Skip to content

Commit 4313e3c

Browse files
feat(banner): add support for new styles in penta (#9891)
* feat(banner): add support for new styles in penta * chore(banner): update tests * chore(banner): update banner documentation copy
1 parent 007dc2c commit 4313e3c

5 files changed

Lines changed: 126 additions & 48 deletions

File tree

packages/react-core/src/components/Banner/Banner.tsx

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import * as React from 'react';
22
import styles from '@patternfly/react-styles/css/components/Banner/banner';
33
import { css } from '@patternfly/react-styles';
44

5+
export type BannerColor = 'red' | 'orangered' | 'orange' | 'gold' | 'green' | 'cyan' | 'blue' | 'purple';
6+
7+
export type BannerStatus = 'success' | 'warning' | 'danger' | 'info' | 'custom';
8+
59
export interface BannerProps extends React.HTMLProps<HTMLDivElement> {
610
/** Content rendered inside the banner. */
711
children?: React.ReactNode;
@@ -13,29 +17,48 @@ export interface BannerProps extends React.HTMLProps<HTMLDivElement> {
1317
* be passed in when the banner conveys status/severity.
1418
*/
1519
screenReaderText?: string;
16-
/** Variant styles for the banner. */
17-
variant?: 'default' | 'blue' | 'red' | 'green' | 'gold';
20+
/** Color options for the banner, will be overwritten by any applied using the status prop. */
21+
color?: BannerColor;
22+
/** Status style options for the banner, will overwrite any color applied using the color prop. */
23+
status?: BannerStatus;
24+
}
25+
interface StatusBanner extends BannerProps {
26+
color?: never;
27+
status?: BannerStatus;
1828
}
1929

20-
export const Banner: React.FunctionComponent<BannerProps> = ({
30+
interface NonStatusBanner extends BannerProps {
31+
color?: BannerColor;
32+
status?: never;
33+
}
34+
35+
export const Banner: React.FunctionComponent<StatusBanner | NonStatusBanner> = ({
2136
children,
2237
className,
23-
variant = 'default',
2438
screenReaderText,
2539
isSticky = false,
40+
color,
41+
status,
2642
...props
27-
}: BannerProps) => (
28-
<div
29-
className={css(
30-
styles.banner,
31-
styles.modifiers[variant as 'green' | 'red' | 'gold' | 'blue'],
32-
isSticky && styles.modifiers.sticky,
33-
className
34-
)}
35-
{...props}
36-
>
37-
{screenReaderText && <span className="pf-v5-screen-reader">{screenReaderText}</span>}
38-
{children}
39-
</div>
40-
);
43+
}: BannerProps) => {
44+
const getStatusOrColorModifier = () => {
45+
if (status) {
46+
return styles.modifiers[status];
47+
}
48+
49+
if (color) {
50+
return styles.modifiers[color];
51+
}
52+
};
53+
54+
return (
55+
<div
56+
className={css(styles.banner, getStatusOrColorModifier(), isSticky && styles.modifiers.sticky, className)}
57+
{...props}
58+
>
59+
{screenReaderText && <span className="pf-v5-screen-reader">{screenReaderText}</span>}
60+
{children}
61+
</div>
62+
);
63+
};
4164
Banner.displayName = 'Banner';

packages/react-core/src/components/Banner/__tests__/Banner.test.tsx

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,76 @@ test('Renders with custom class name when className prop is provided', () => {
2727
expect(screen.getByText('Test')).toHaveClass('custom-class');
2828
});
2929

30-
test('Renders without any modifier class when variant prop is not passed', () => {
30+
test('Renders without any modifier class when color and status props are not passed', () => {
3131
render(<Banner>Test</Banner>);
3232
expect(screen.getByText('Test')).toHaveClass(styles.banner, { exact: true });
3333
});
3434

35-
test('Renders with class name pf-m-green when "green" is passed to variant prop', () => {
36-
render(<Banner variant="green">Test</Banner>);
37-
expect(screen.getByText('Test')).toHaveClass('pf-m-green');
35+
test('Renders with class name pf-m-red when "red" is passed to color prop', () => {
36+
render(<Banner color="red">Test</Banner>);
37+
expect(screen.getByText('Test')).toHaveClass('pf-m-red');
3838
});
3939

40-
test('Renders with class name pf-m-red when "red" is passed to variant prop', () => {
41-
render(<Banner variant="red">Test</Banner>);
42-
expect(screen.getByText('Test')).toHaveClass('pf-m-red');
40+
test('Renders with class name pf-m-orangered when "orangered" is passed to color prop', () => {
41+
render(<Banner color="orangered">Test</Banner>);
42+
expect(screen.getByText('Test')).toHaveClass('pf-m-orangered');
4343
});
4444

45-
test('Renders with class name pf-m-gold when "gold" is passed to variant prop', () => {
46-
render(<Banner variant="gold">Test</Banner>);
45+
test('Renders with class name pf-m-orange when "orange" is passed to color prop', () => {
46+
render(<Banner color="orange">Test</Banner>);
47+
expect(screen.getByText('Test')).toHaveClass('pf-m-orange');
48+
});
49+
50+
test('Renders with class name pf-m-gold when "gold" is passed to color prop', () => {
51+
render(<Banner color="gold">Test</Banner>);
4752
expect(screen.getByText('Test')).toHaveClass('pf-m-gold');
4853
});
4954

50-
test('Renders with class name pf-m-blue when "blue" is passed to variant prop', () => {
51-
render(<Banner variant="blue">Test</Banner>);
55+
test('Renders with class name pf-m-green when "green" is passed to color prop', () => {
56+
render(<Banner color="green">Test</Banner>);
57+
expect(screen.getByText('Test')).toHaveClass('pf-m-green');
58+
});
59+
60+
test('Renders with class name pf-m-cyan when "cyan" is passed to color prop', () => {
61+
render(<Banner color="cyan">Test</Banner>);
62+
expect(screen.getByText('Test')).toHaveClass('pf-m-cyan');
63+
});
64+
65+
test('Renders with class name pf-m-blue when "blue" is passed to color prop', () => {
66+
render(<Banner color="blue">Test</Banner>);
5267
expect(screen.getByText('Test')).toHaveClass('pf-m-blue');
5368
});
5469

70+
test('Renders with class name pf-m-purple when "purple" is passed to color prop', () => {
71+
render(<Banner color="purple">Test</Banner>);
72+
expect(screen.getByText('Test')).toHaveClass('pf-m-purple');
73+
});
74+
75+
test('Renders with class name pf-m-success when "success" is passed to status prop', () => {
76+
render(<Banner status="success">Test</Banner>);
77+
expect(screen.getByText('Test')).toHaveClass('pf-m-success');
78+
});
79+
80+
test('Renders with class name pf-m-warning when "warning" is passed to status prop', () => {
81+
render(<Banner status="warning">Test</Banner>);
82+
expect(screen.getByText('Test')).toHaveClass('pf-m-warning');
83+
});
84+
85+
test('Renders with class name pf-m-danger when "danger" is passed to status prop', () => {
86+
render(<Banner status="danger">Test</Banner>);
87+
expect(screen.getByText('Test')).toHaveClass('pf-m-danger');
88+
});
89+
90+
test('Renders with class name pf-m-info when "info" is passed to status prop', () => {
91+
render(<Banner status="info">Test</Banner>);
92+
expect(screen.getByText('Test')).toHaveClass('pf-m-info');
93+
});
94+
95+
test('Renders with class name pf-m-custom when "custom" is passed to status prop', () => {
96+
render(<Banner status="custom">Test</Banner>);
97+
expect(screen.getByText('Test')).toHaveClass('pf-m-custom');
98+
});
99+
55100
test('Does not render pf-v5-screen-reader class by default', () => {
56101
render(<Banner>Test</Banner>);
57102
expect(screen.getByText('Test')).not.toContainHTML('<span class="pf-v5-screen-reader"></span>');

packages/react-core/src/components/Banner/examples/Banner.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
1515

1616
### Basic
1717

18-
Banners can be styled with one of 5 different colors. A basic banner should only be used when the banner color does not represent status or severity.
18+
Banners can be styled with one of 9 different colors using the `color` prop. A basic banner should only be used when the banner color does not represent status or severity.
1919

2020
```ts file="./BannerBasic.tsx"
2121

2222
```
2323

2424
### Status
2525

26-
When a banner is used to convey status, it is advised to pass in an icon inside the banner to convey the status in a way besides just color. The `screenReaderText` prop should also be passed in to convey the status/severity of the banner to users of certain assistive technologies such as screen readers.
26+
When a banner is used to convey status it should be styled using the `status` prop. Additionally, it is advised to pass an icon inside the banner to convey the status in a way besides just color.
27+
28+
The `screenReaderText` prop should also be passed in to convey the status/severity of the banner to users of certain assistive technologies such as screen readers.
2729

2830
In the following example, a flex layout is used inside the banner content to show one possible way to create spacing between the icons and banner text.
2931

packages/react-core/src/components/Banner/examples/BannerBasic.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@ export const BannerBasic: React.FunctionComponent = () => (
55
<>
66
<Banner>Default banner</Banner>
77
<br />
8-
<Banner variant="blue">Blue banner</Banner>
8+
<Banner color="red">Red banner</Banner>
99
<br />
10-
<Banner variant="red">Red banner</Banner>
10+
<Banner color="orangered">Orangered banner</Banner>
1111
<br />
12-
<Banner variant="green">Green banner</Banner>
12+
<Banner color="orange">Orange banner</Banner>
1313
<br />
14-
<Banner variant="gold">Gold banner</Banner>
14+
<Banner color="gold">Gold banner</Banner>
15+
<br />
16+
<Banner color="green">Green banner</Banner>
17+
<br />
18+
<Banner color="cyan">Cyan banner</Banner>
19+
<br />
20+
<Banner color="blue">Blue banner</Banner>
21+
<br />
22+
<Banner color="purple">Purple banner</Banner>
1523
</>
1624
);

packages/react-core/src/components/Banner/examples/BannerStatus.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,25 @@ import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
88

99
export const BannerStatus: React.FunctionComponent = () => (
1010
<>
11-
<Banner screenReaderText="Default banner">
11+
<Banner screenReaderText="Success banner" status="success">
1212
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
1313
<FlexItem>
14-
<BellIcon />
14+
<CheckCircleIcon />
1515
</FlexItem>
16-
<FlexItem>Default banner</FlexItem>
16+
<FlexItem>Success banner</FlexItem>
1717
</Flex>
1818
</Banner>
1919
<br />
20-
<Banner screenReaderText="Info banner" variant="blue">
20+
<Banner screenReaderText="Warning banner" status="warning">
2121
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
2222
<FlexItem>
23-
<InfoCircleIcon />
23+
<ExclamationTriangleIcon />
2424
</FlexItem>
25-
<FlexItem>Info banner</FlexItem>
25+
<FlexItem>Warning banner</FlexItem>
2626
</Flex>
2727
</Banner>
2828
<br />
29-
<Banner screenReaderText="Danger banner" variant="red">
29+
<Banner screenReaderText="Danger banner" status="danger">
3030
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
3131
<FlexItem>
3232
<ExclamationCircleIcon />
@@ -35,21 +35,21 @@ export const BannerStatus: React.FunctionComponent = () => (
3535
</Flex>
3636
</Banner>
3737
<br />
38-
<Banner screenReaderText="Success banner" variant="green">
38+
<Banner screenReaderText="Info banner" status="info">
3939
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
4040
<FlexItem>
41-
<CheckCircleIcon />
41+
<InfoCircleIcon />
4242
</FlexItem>
43-
<FlexItem>Success banner</FlexItem>
43+
<FlexItem>Info banner</FlexItem>
4444
</Flex>
4545
</Banner>
4646
<br />
47-
<Banner screenReaderText="Warning banner" variant="gold">
47+
<Banner screenReaderText="Custom banner" status="custom">
4848
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
4949
<FlexItem>
50-
<ExclamationTriangleIcon />
50+
<BellIcon />
5151
</FlexItem>
52-
<FlexItem>Warning banner</FlexItem>
52+
<FlexItem>Custom banner</FlexItem>
5353
</Flex>
5454
</Banner>
5555
</>

0 commit comments

Comments
 (0)