Skip to content

Commit f7595ac

Browse files
author
Kubit
committed
Improve footer component content structure
1 parent 9ba1a52 commit f7595ac

File tree

8 files changed

+267
-116
lines changed

8 files changed

+267
-116
lines changed

src/components/footer/components/footerContent.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ interface IFooterContent {
88
contentDirection?: ContentDirectionType;
99
forceVertical?: boolean;
1010
children: React.ReactNode[];
11-
margin?: boolean;
12-
marginLeft?: boolean;
13-
marginRight?: boolean;
1411
}
1512

1613
export const FooterContent = (props: IFooterContent): JSX.Element | null => {
@@ -21,11 +18,11 @@ export const FooterContent = (props: IFooterContent): JSX.Element | null => {
2118
return null;
2219
}
2320

21+
const order = (props.children[0] as JSX.Element)?.props['data-order'] || 0;
22+
2423
return (
2524
<FooterContentStyled
26-
$margin={props.margin}
27-
$marginLeft={props.marginLeft}
28-
$marginRight={props.marginRight}
25+
$order={order}
2926
aria-hidden={!props.children.length}
3027
contentDirection={props.contentDirection}
3128
flexDirectionDesktopTablet={flexDirectionDesktopTablet}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as React from 'react';
2+
3+
import { FooterSectionStyled } from '../footer.styled';
4+
import { FooterPositionType, FooterPropsStylesType } from '../types';
5+
6+
interface IFooterSection {
7+
styles: FooterPropsStylesType;
8+
forceVertical?: boolean;
9+
position: string;
10+
tabInverse?: boolean;
11+
children: React.ReactNode[];
12+
}
13+
14+
export const FooterSection = (props: IFooterSection): JSX.Element | null => {
15+
if (!props.children.length) {
16+
return null;
17+
}
18+
19+
const getElementJustify = (position: string) => {
20+
const styles = {
21+
[FooterPositionType.LEFT]: props.tabInverse ? 'flex-end' : 'flex-start',
22+
[FooterPositionType.CENTER]: 'center',
23+
[FooterPositionType.RIGHT]: props.tabInverse ? 'flex-start' : 'flex-end',
24+
};
25+
return styles[position] || 'center';
26+
};
27+
28+
return (
29+
<FooterSectionStyled
30+
$forceVertical={props.forceVertical}
31+
$justifyContent={getElementJustify(props.position)}
32+
$tabInverse={props.tabInverse}
33+
aria-hidden={!props.children.length}
34+
styles={props.styles}
35+
>
36+
{props.tabInverse ? props.children.reverse() : props.children}
37+
</FooterSectionStyled>
38+
);
39+
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from './footerContent';
1+
export * from './footerSection';
Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,84 @@
1-
import styled from 'styled-components';
1+
import styled, { css } from 'styled-components';
22

33
import { getStyles } from '@/utils';
44

55
import { LineSeparatorLinePropsStylesType, LineSeparatorPositionType } from '../lineSeparator';
6-
import { ContentDirectionType, FooterPropsStylesType } from './types';
6+
import { FooterPropsStylesType } from './types';
77

88
type FooterStylesType = {
99
styles: FooterPropsStylesType;
10-
contentDirection?: ContentDirectionType;
11-
flexDirectionDesktopTablet?: string;
12-
alignItems?: string;
13-
$margin?: boolean;
14-
$marginLeft?: boolean;
15-
$marginRight?: boolean;
10+
$forceVertical?: boolean;
11+
$tabInverse?: boolean;
12+
};
13+
14+
type FooterSectionStyledType = FooterStylesType & {
15+
$justifyContent: string;
1616
};
1717

1818
type RootContainerStyledType = FooterStylesType & {
1919
lineSeparatorLineStyles: LineSeparatorLinePropsStylesType;
2020
};
2121

2222
export const FooterStyled = styled.div<RootContainerStyledType>`
23-
display: flex;
24-
width: 100%;
25-
align-items: ${props => props.alignItems || 'center'};
26-
justify-content: space-between;
27-
box-sizing: border-box;
28-
2923
${({ lineSeparatorLineStyles }) =>
3024
lineSeparatorLineStyles?.buildLineStyles?.(LineSeparatorPositionType.TOP)}
3125
${props => getStyles(props.styles?.rootContainer)}
32-
${props =>
33-
props.contentDirection && getStyles(props.styles?.rootContainer?.[props.contentDirection])}
34-
`;
3526
36-
export const FooterContentStyled = styled.div<FooterStylesType>`
3727
display: flex;
38-
flex-direction: ${props => props.flexDirectionDesktopTablet};
39-
justify-content: ${props =>
40-
props.contentDirection === ContentDirectionType.HORIZONTAL ? 'flex-start' : 'center'};
28+
${() =>
29+
({
30+
theme: {
31+
MEDIA_QUERIES: { onlyMobile, tabletAndDesktop },
32+
},
33+
$forceVertical,
34+
$tabInverse,
35+
}) => css`
36+
${tabletAndDesktop} {
37+
flex-direction: ${$forceVertical
38+
? $tabInverse
39+
? 'column-reverse'
40+
: 'column'
41+
: $tabInverse
42+
? 'row-reverse'
43+
: 'row'};
44+
}
45+
${onlyMobile} {
46+
flex-direction: ${$tabInverse ? 'column-reverse' : 'column'};
47+
justify-content: center;
48+
}
49+
`};
50+
`;
51+
52+
export const FooterSectionStyled = styled.div<FooterSectionStyledType>`
4153
${props => getStyles(props.styles?.contentContainer)}
42-
margin: ${props => props.$margin && 'auto'};
43-
margin-left: ${props => props.$marginLeft && 'auto'};
44-
margin-right: ${props => props.$marginRight && 'auto'};
54+
55+
display: flex;
56+
width: 100%;
57+
${() =>
58+
({
59+
theme: {
60+
MEDIA_QUERIES: { onlyMobile, tabletAndDesktop },
61+
},
62+
63+
$justifyContent,
64+
$forceVertical,
65+
$tabInverse,
66+
}) => css`
67+
${tabletAndDesktop} {
68+
justify-content: ${$forceVertical ? 'center' : $justifyContent};
69+
flex-direction: ${$forceVertical
70+
? $tabInverse
71+
? 'column-reverse'
72+
: 'column'
73+
: $tabInverse
74+
? 'row-reverse'
75+
: 'row'};
76+
77+
align-items: ${$forceVertical && 'center'};
78+
}
79+
${onlyMobile} {
80+
flex-direction: ${$tabInverse ? 'column-reverse' : 'column'};
81+
align-items: center;
82+
}
83+
`};
4584
`;

src/components/footer/footerStandAlone.tsx

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,111 @@
11
import * as React from 'react';
22

3-
import { DeviceBreakpointsType } from '@/types/breakpoints';
43
import { pickAriaProps } from '@/utils/aria/aria';
54

65
// inner components
7-
import { FooterContent } from './components';
6+
import { FooterSection } from './components';
87
import { FooterStyled } from './footer.styled';
9-
import { FooterMobileColumnFlow, FooterPositionType, IFooterStandAlone, MobileSort } from './types';
8+
import {
9+
ContentDirectionType,
10+
FooterMobileColumnFlow,
11+
FooterPositionType,
12+
IFooterStandAlone,
13+
} from './types';
1014

1115
// simple container tag
1216
const FOOTER = 'footer';
13-
// default footer sort
14-
const DEFAULT_SORT: MobileSort = {
15-
column: FooterMobileColumnFlow.REVERSE,
16-
firstContent: FooterPositionType.RIGHT,
17-
secondContent: FooterPositionType.CENTER,
18-
thirdContent: FooterPositionType.LEFT,
19-
};
2017

2118
const FooterStandAloneComponent = (
22-
{ footerMobileSortConfig = DEFAULT_SORT, ...props }: IFooterStandAlone,
19+
{ ...props }: IFooterStandAlone,
2320
ref: React.ForwardedRef<HTMLElement> | undefined | null
2421
): JSX.Element | null => {
22+
if (!props.children) {
23+
return null;
24+
}
25+
2526
const ariaProps = pickAriaProps(props);
2627

27-
const getPositionContent = (position: FooterPositionType) => {
28-
const childrens = React.Children.toArray(props.children).filter((child: React.ReactNode) => {
29-
return (child as JSX.Element)?.props?.['data-position'] === position;
28+
const asFooter = props.simpleContainer ? undefined : FOOTER;
29+
30+
const renderChildren = (children: JSX.Element | JSX.Element[]) => {
31+
const childrenArray = React.Children.toArray(children);
32+
33+
const positions = {
34+
[FooterPositionType.LEFT]: [],
35+
[FooterPositionType.CENTER]: [],
36+
[FooterPositionType.RIGHT]: [],
37+
};
38+
39+
let defaultPositionCounter = 0;
40+
41+
childrenArray.forEach((child: React.ReactNode) => {
42+
let position = (child as JSX.Element)?.props?.['data-position'];
43+
44+
// START CONTENT: Remove when footerMobileSortConfig is removed
45+
if (props.footerMobileSortConfig) {
46+
if (props.footerMobileSortConfig.firstContent === position) {
47+
position = FooterPositionType.LEFT;
48+
} else if (props.footerMobileSortConfig.secondContent === position) {
49+
position = FooterPositionType.CENTER;
50+
} else if (props.footerMobileSortConfig.thirdContent === position) {
51+
position = FooterPositionType.RIGHT;
52+
}
53+
}
54+
// END CONTENT
55+
56+
if (!position) {
57+
if (defaultPositionCounter === 0) {
58+
position = FooterPositionType.LEFT;
59+
} else if (defaultPositionCounter === 1) {
60+
position = FooterPositionType.RIGHT;
61+
}
62+
defaultPositionCounter++;
63+
}
64+
65+
if (positions[position]) {
66+
positions[position].push(child);
67+
}
3068
});
3169

32-
if (props.device !== DeviceBreakpointsType.MOBILE) {
33-
return childrens;
34-
}
70+
const sections = Object.entries(positions).map(([position, children]) => (
71+
<FooterSection
72+
key={position}
73+
forceVertical={forceVertical}
74+
position={position}
75+
styles={props.styles}
76+
tabInverse={tabInverse}
77+
>
78+
{children}
79+
</FooterSection>
80+
));
3581

36-
return footerMobileSortConfig.column === FooterMobileColumnFlow.DEFAULT
37-
? childrens
38-
: childrens.reverse();
82+
return <>{tabInverse ? sections.reverse() : sections}</>;
3983
};
4084

41-
const firstContent = (() =>
42-
footerMobileSortConfig?.firstContent && props.device === DeviceBreakpointsType.MOBILE
43-
? getPositionContent(footerMobileSortConfig.firstContent)
44-
: getPositionContent(FooterPositionType.LEFT))();
45-
const secondContent = (() =>
46-
footerMobileSortConfig?.secondContent && props.device === DeviceBreakpointsType.MOBILE
47-
? getPositionContent(footerMobileSortConfig.secondContent)
48-
: getPositionContent(FooterPositionType.CENTER))();
49-
const thridContent = (() =>
50-
footerMobileSortConfig?.thirdContent && props.device === DeviceBreakpointsType.MOBILE
51-
? getPositionContent(footerMobileSortConfig.thirdContent)
52-
: getPositionContent(FooterPositionType.RIGHT))();
53-
54-
const showFooter =
55-
props.children ||
56-
firstContent.length > 0 ||
57-
thridContent.length > 0 ||
58-
secondContent.length > 0;
59-
if (!showFooter) {
60-
return null;
61-
}
85+
// START CONTENT: Remove when contentDirection is removed
86+
const forceVertical =
87+
props.forceVertical || props.contentDirection === ContentDirectionType.VERTICAL;
88+
// END CONTENT
6289

63-
const asFooter = props.simpleContainer ? undefined : FOOTER;
90+
// START CONTENT: Remove when footerMobileSortConfig is removed
91+
const tabInverse =
92+
props.tabInverse || props.footerMobileSortConfig?.column === FooterMobileColumnFlow.REVERSE;
93+
// END CONTENT
6494

6595
return (
6696
<FooterStyled
6797
{...ariaProps}
98+
{...props}
6899
ref={ref}
69-
alignItems={props.alignItems}
100+
$forceVertical={forceVertical}
101+
$tabInverse={tabInverse}
70102
as={asFooter}
71-
contentDirection={props.contentDirection}
72103
data-testid={props.dataTestId}
73-
{...props}
74104
lineSeparatorLineStyles={props.lineSeparatorLineStyles}
75105
role={props.role}
76106
styles={props.styles}
77107
>
78-
{Array.isArray(props.children) ? (
79-
<>
80-
<FooterContent
81-
contentDirection={props.contentDirection}
82-
forceVertical={props.forceVertical}
83-
marginRight={true}
84-
styles={props.styles}
85-
>
86-
{firstContent}
87-
</FooterContent>
88-
<FooterContent
89-
contentDirection={props.contentDirection}
90-
forceVertical={props.forceVertical}
91-
margin={true}
92-
styles={props.styles}
93-
>
94-
{secondContent}
95-
</FooterContent>
96-
<FooterContent
97-
contentDirection={props.contentDirection}
98-
forceVertical={props.forceVertical}
99-
marginLeft={true}
100-
styles={props.styles}
101-
>
102-
{thridContent}
103-
</FooterContent>
104-
</>
105-
) : (
106-
props.children
107-
)}
108+
{renderChildren(props.children)}
108109
</FooterStyled>
109110
);
110111
};

src/components/footer/stories/argtypes.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const argtypes = (variants: IThemeObjectVariants, themeSelected: string):
1515
control: { type: 'select' },
1616
type: { name: 'string', required: true },
1717
description: 'Footer variant',
18-
options: Object.keys(variants[themeSelected].FooterVariant || {}),
18+
options: Object.keys(variants[themeSelected].FooterVariants || {}),
1919
table: {
2020
type: {
2121
summary: 'string',
@@ -82,6 +82,17 @@ export const argtypes = (variants: IThemeObjectVariants, themeSelected: string):
8282
category: CATEGORY_CONTROL.MODIFIERS,
8383
},
8484
},
85+
tabInverse: {
86+
description: 'Change the order to tab of the footer content',
87+
control: { type: 'boolean' },
88+
type: { name: 'boolean' },
89+
table: {
90+
type: {
91+
summary: 'boolean',
92+
},
93+
category: CATEGORY_CONTROL.MODIFIERS,
94+
},
95+
},
8596
forceVertical: {
8697
description: 'Force button going vertical or take styles from theme',
8798
control: { type: 'boolean' },

0 commit comments

Comments
 (0)