Skip to content

Commit 1404bfd

Browse files
committed
✨ feat: added scrollable option to header and footer components
1 parent 745a367 commit 1404bfd

11 files changed

+291
-28
lines changed

src/components/Footer/Footer.tsx

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { cx } from '@emotion/css';
22
import React from 'react';
33
import { SequentialVariant, ThemeProps } from '../../types';
4+
import { useAccessibility } from '../../context/Accessibility/useAccessibility';
45
import { useThemeId } from '../../context/Theme';
56
import styles from './styles/Footer.module.css';
67

@@ -11,6 +12,10 @@ export type FooterProps = React.HTMLAttributes<HTMLDivElement> &
1112
className?: string;
1213
full?: boolean;
1314
style?: React.CSSProperties;
15+
/** When used with the scrollable flag the footer will overflow horizontally instead of wrapping */
16+
nowrap?: boolean;
17+
scrollable?: boolean;
18+
scrollbar?: 'xsmall' | 'small' | 'medium';
1419
transparent?: boolean;
1520
variant?: SequentialVariant;
1621
volume?: 'quiet';
@@ -27,6 +32,9 @@ export function Footer({
2732
className,
2833
contrast = false,
2934
full = false,
35+
nowrap = false,
36+
scrollable = false,
37+
scrollbar = 'small',
3038
themeId: initThemeId,
3139
transparent = false,
3240
unthemed = false,
@@ -35,22 +43,28 @@ export function Footer({
3543
...props
3644
}: FooterProps): JSX.Element {
3745
const themeId = useThemeId(initThemeId);
46+
const accessible = useAccessibility();
3847
const variant = contrast ? 'contrast' : initVariant;
3948

4049
const classes = cx(
4150
styles.footer,
4251
bordered && styles['footer--bordered'],
4352
bordered === 'pseudo' && styles['footer--bordered-pseudo'],
4453
full && styles['footer--full'],
54+
nowrap && styles['footer--nowrap'],
55+
scrollable && styles['footer--scrollable'],
56+
scrollbar && styles[`footer--${scrollbar}-scrollbar`],
4557
!unthemed && themeId && styles[`footer--${themeId}`],
4658
!unthemed && variant && styles[`footer--${variant}`],
4759
transparent && styles['footer--transparent'],
4860
volume && styles[`footer--${volume}`],
61+
accessible && styles['is-accessible'],
4962
className,
5063
);
5164

5265
return (
53-
<div className={classes} {...props}>
66+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
67+
<div className={classes} tabIndex={scrollable ? 0 : undefined} {...props}>
5468
{children}
5569
</div>
5670
);

src/components/Footer/StyledFooter.tsx

+23-6
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,34 @@ import styled from '@emotion/styled';
22
import React from 'react';
33
import { Footer, FooterProps } from './Footer';
44

5-
export type StyledFooterProps = Omit<FooterProps, 'contrast' | 'themeId'> & {
5+
export type StyledFooterProps = Omit<FooterProps, 'contrast'> & {
66
backgroundColor?: string;
77
borderColor?: string;
8+
focusedOutlineColor?: string;
9+
scrollbarColor?: string;
810
textColor?: string;
911
height?: number | string;
12+
/** Allow the footer to fall back to the normal theme */
13+
themed?: boolean;
1014
};
1115

1216
const BaseStyledFooter = styled(Footer, {
13-
shouldForwardProp: (prop: string) => !['borderColor', 'backgroundColor', 'textColor', 'height'].includes(prop),
17+
shouldForwardProp: (prop: string) =>
18+
!['borderColor', 'backgroundColor', 'focusedOutlineColor', 'scrollbarThumbColor', 'textColor', 'height'].includes(
19+
prop,
20+
),
1421
})<StyledFooterProps>`
15-
${({ backgroundColor }) => backgroundColor && `--footer-background-color: ${backgroundColor};`}
16-
${({ borderColor }) => borderColor && `--footer-border-color: ${borderColor};`}
17-
${({ textColor }) => textColor && `--footer-text-color: ${textColor};`}
22+
${({ backgroundColor, unthemed }) =>
23+
backgroundColor && `--footer-background-color: ${backgroundColor}${unthemed ? '' : ' !important'};`}
24+
${({ borderColor, unthemed }) =>
25+
borderColor && `--footer-border-color: ${borderColor}${unthemed ? '' : ' !important'};`}
26+
27+
${({ focusedOutlineColor, unthemed }) =>
28+
focusedOutlineColor && `--footer-focused-outline-color: ${focusedOutlineColor}${unthemed ? '' : ' !important'};`}
29+
${({ scrollbarColor, unthemed }) =>
30+
scrollbarColor && `--footer-scrollbar-thumb-color: ${scrollbarColor}${unthemed ? '' : ' !important'};`}
31+
32+
${({ textColor, unthemed }) => textColor && `--footer-text-color: ${textColor}${unthemed ? '' : ' !important'};`}
1833
${({ height }) => height !== undefined && `height: ${Number.isNaN(Number(height)) ? height : `${height}px`};`}
1934
`;
2035

@@ -24,6 +39,8 @@ const BaseStyledFooter = styled(Footer, {
2439
* and background colors, and an optional custom
2540
* height.
2641
*/
27-
export const StyledFooter = (props: StyledFooterProps) => <BaseStyledFooter {...props} unthemed />;
42+
export const StyledFooter = ({ themed, ...props }: StyledFooterProps) => (
43+
<BaseStyledFooter {...props} unthemed={!themed} />
44+
);
2845

2946
StyledFooter.displayName = 'StyledFooter';

src/components/Footer/stories/Footer.stories.tsx

+37
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,26 @@ export default {
2222
type: 'text',
2323
},
2424
},
25+
nowrap: {
26+
table: {
27+
category: 'Appearance',
28+
},
29+
},
2530
full: {
2631
table: {
2732
category: 'Appearance',
2833
},
2934
},
35+
scrollable: {
36+
table: {
37+
category: 'Appearance',
38+
},
39+
},
40+
scrollbar: {
41+
table: {
42+
category: 'Appearance',
43+
},
44+
},
3045
transparent: {
3146
table: {
3247
category: 'Appearance',
@@ -162,3 +177,25 @@ TertiaryVariant.args = {
162177
bordered: true,
163178
variant: 'tertiary',
164179
};
180+
181+
export const Scrollable = Template.bind({});
182+
Scrollable.args = {
183+
...defaultArgs,
184+
children: (
185+
<React.Fragment>
186+
<div>Superlongword</div>
187+
<div>Superlongword</div>
188+
<div>Superlongword</div>
189+
<div>Superlongword</div>
190+
<div>Superlongword</div>
191+
<div>Superlongword</div>
192+
<div>Superlongword</div>
193+
<div>Superlongword</div>
194+
<div>Superlongword</div>
195+
<div>Superlongword</div>
196+
</React.Fragment>
197+
),
198+
nowrap: true,
199+
scrollable: true,
200+
scrollbar: 'small',
201+
};

src/components/Footer/stories/StyledFooter.stories.tsx

+27-1
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,32 @@ export default {
3030
category: 'Styled',
3131
},
3232
},
33+
focusedOutlineColor: {
34+
table: {
35+
category: 'Styled',
36+
},
37+
},
38+
scrollbarColor: {
39+
table: {
40+
category: 'Styled',
41+
},
42+
},
3343
textColor: {
3444
table: {
3545
category: 'Styled',
3646
},
3747
},
38-
footerColor: {
48+
themed: {
3949
table: {
4050
category: 'Styled',
4151
},
4252
},
53+
54+
themeId: {
55+
table: {
56+
category: 'Uncommon',
57+
},
58+
},
4359
...argTypes,
4460
},
4561
parameters: {
@@ -77,6 +93,7 @@ const defaultArgs = {
7793
borderColor: '#393a61',
7894
textColor: '#fff',
7995
height: 50,
96+
themed: false,
8097
variant: undefined,
8198
};
8299

@@ -85,6 +102,15 @@ Default.args = {
85102
...defaultArgs,
86103
};
87104

105+
export const Themed = Template.bind({});
106+
Themed.storyName = 'Inherit theme';
107+
Themed.args = {
108+
bordered: true,
109+
height: 50,
110+
variant: 'primary',
111+
themed: true,
112+
};
113+
88114
/*
89115
Default.parameters = {
90116
jest: ['StyledFooter.test.js', 'Footer.test.js'],

src/components/Footer/styles/Footer.module.css

+47-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import '../../../styles/common/mixins/addScrollbar.css';
2+
13
.footer {
24
align-items: center;
35
background-color: var(--footer-background-color);
@@ -10,6 +12,10 @@
1012
width: 100%;
1113
}
1214

15+
.footer--nowrap {
16+
flex-wrap: nowrap;
17+
}
18+
1319
/**
1420
* 1. Use a pseudo element rather than a border so that
1521
* it doesn't add height to the box element.
@@ -35,6 +41,10 @@
3541
.footer--primary {
3642
@mixin themed .footer {
3743
--footer-border-color: $theme-primary-palette-border-color;
44+
--footer-focused-outline-color: $theme-primary-palette-text-color;
45+
--footer-scrollbar-thumb-color: $theme-primary-scrollbar-thumb-color;
46+
--footer-background-color: $theme-primary-palette-background-color;
47+
--footer-text-color: $theme-primary-palette-text-color;
3848

3949
&.footer--quiet {
4050
--footer-border-color: $theme-primary-palette-quiet-border-color;
@@ -43,15 +53,16 @@
4353
&.footer--transparent {
4454
background-color: transparent;
4555
}
46-
47-
background-color: $theme-primary-palette-background-color;
48-
color: $theme-primary-palette-text-color;
4956
}
5057
}
5158

5259
.footer--secondary {
5360
@mixin themed .footer {
5461
--footer-border-color: $theme-secondary-palette-border-color;
62+
--footer-focused-outline-color: $theme-secondary-palette-text-color;
63+
--footer-scrollbar-thumb-color: $theme-primary-scrollbar-thumb-color;
64+
--footer-background-color: $theme-secondary-palette-background-color;
65+
--footer-text-color: $theme-secondary-palette-text-color;
5566

5667
&.footer--quiet {
5768
--footer-border-color: $theme-secondary-palette-quiet-border-color;
@@ -60,15 +71,16 @@
6071
&.footer--transparent {
6172
background-color: transparent;
6273
}
63-
64-
background-color: $theme-secondary-palette-background-color;
65-
color: $theme-secondary-palette-text-color;
6674
}
6775
}
6876

6977
.footer--tertiary {
7078
@mixin themed .footer {
7179
--footer-border-color: $theme-tertiary-palette-border-color;
80+
--footer-focused-outline-color: $theme-tertiary-palette-text-color;
81+
--footer-scrollbar-thumb-color: $theme-primary-scrollbar-thumb-color;
82+
--footer-background-color: $theme-tertiary-palette-background-color;
83+
--footer-textcolor: $theme-tertiary-palette-text-color;
7284

7385
&.footer--quiet {
7486
--footer-border-color: $theme-tertiary-palette-quiet-border-color;
@@ -77,15 +89,16 @@
7789
&.footer--transparent {
7890
background-color: transparent;
7991
}
80-
81-
background-color: $theme-tertiary-palette-background-color;
82-
color: $theme-tertiary-palette-text-color;
8392
}
8493
}
8594

8695
.footer--contrast {
8796
@mixin themed .footer {
8897
--footer-border-color: $theme-contrast-palette-border-color;
98+
--footer-focused-outline-color: $theme-contrast-palette-text-color;
99+
--footer-scrollbar-thumb-color: $theme-contrast-scrollbar-thumb-color;
100+
--footer-background-color: var(--phork-contrast-color, $theme-contrast-palette-background-color);
101+
--footer-text-color: $theme-contrast-palette-text-color;
89102

90103
&.footer--quiet {
91104
--footer-border-color: $theme-contrast-palette-quiet-border-color;
@@ -94,13 +107,35 @@
94107
&.footer--transparent {
95108
background-color: transparent;
96109
}
97-
98-
background-color: var(--phork-contrast-color, $theme-contrast-palette-background-color);
99-
color: $theme-contrast-palette-text-color;
100110
}
101111
}
102112

103113
.footer--full {
104114
height: 100%;
105115
width: 100%;
106116
}
117+
118+
.footer--scrollable {
119+
&.footer--medium-scrollbar {
120+
@mixin addScrollbar var(--footer-scrollbar-thumb-color);
121+
}
122+
123+
&.footer--small-scrollbar {
124+
@mixin addSmallScrollbar var(--footer-scrollbar-thumb-color);
125+
}
126+
127+
&.footer--xsmall-scrollbar {
128+
@mixin addXSmallScrollbar var(--footer-scrollbar-thumb-color);
129+
}
130+
131+
&:focus {
132+
outline: none;
133+
}
134+
135+
&.is-accessible:focus {
136+
outline: 1px solid var(--footer-focused-outline-color);
137+
outline-offset: -1px;
138+
}
139+
140+
overflow: auto;
141+
}

src/components/Form/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './Checkbox';
22
export * from './Fieldset';
3+
export * from './Formbox';
34
export * from './Label';
45
export * from './LabelWrapper';
56
export * from './Notification';

0 commit comments

Comments
 (0)