Skip to content

Commit

Permalink
Made icon support an example instead of new props
Browse files Browse the repository at this point in the history
  • Loading branch information
thatblindgeye committed Oct 11, 2022
1 parent a2f5bbb commit cc9b1fa
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 114 deletions.
63 changes: 19 additions & 44 deletions packages/react-core/src/components/Banner/Banner.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,43 @@
import * as React from 'react';
import styles from '@patternfly/react-styles/css/components/Banner/banner';
import { css } from '@patternfly/react-styles';
import { variantIcons } from '../Alert/AlertIcon';
import { Flex, FlexItem } from '../../layouts';

export interface BannerProps extends React.HTMLProps<HTMLDivElement> {
/** Content rendered inside the banner. */
children?: React.ReactNode;
/** Additional classes added to the banner. */
className?: string;
/** A custom icon for the banner. This property will override the icon that is set based on
* the variant property.
*/
customIcon?: React.ReactNode;
/** Flag for indicating whether the banner has a status icon. When set to "true", the icon
* will be set based on the variant property.
*/
hasStatusIcon?: boolean;
/** If set to true, the banner sticks to the top of its container */
isSticky?: boolean;
/** Text announced by screen readers to indicate the type of banner when the hasStatusIcon property
* is passed in. Defaults to "${variant} banner" if this property is not passed in.
/** Text announced by screen readers to indicate the type of banner. Defaults to "${variant} banner"
* if this property is not passed in.
*
* Pass in null to omit this text from the banner when the banner does not convey status/severity.
*/
screenReaderText?: string;
screenReaderText?: string | null;
/** Variant styles for the banner. */
variant?: 'default' | 'info' | 'danger' | 'success' | 'warning';
}

export const Banner: React.FunctionComponent<BannerProps> = ({
children,
className,
customIcon,
hasStatusIcon = false,
variant = 'default',
screenReaderText,
isSticky = false,
...props
}: BannerProps) => {
const StatusIcon = variantIcons[variant];

return (
<div
className={css(
styles.banner,
styles.modifiers[variant as 'success' | 'danger' | 'warning' | 'info'],
isSticky && styles.modifiers.sticky,
className
)}
{...props}
>
{hasStatusIcon ? (
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
<FlexItem>
<span className="pf-u-screen-reader">{screenReaderText || `${variant} banner`}</span>
{customIcon || <StatusIcon />}
</FlexItem>
<FlexItem>
<div className="pf-l-flex__item">{children}</div>
</FlexItem>
</Flex>
) : (
children
)}
</div>
);
};
}: BannerProps) => (
<div
className={css(
styles.banner,
styles.modifiers[variant as 'success' | 'danger' | 'warning' | 'info'],
isSticky && styles.modifiers.sticky,
className
)}
{...props}
>
{screenReaderText !== null && <span className="pf-u-screen-reader">{screenReaderText || `${variant} banner`}</span>}
{children}
</div>
);
Banner.displayName = 'Banner';
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ import { Banner } from '../Banner';
import React from 'react';
import { render, screen } from '@testing-library/react';

jest.mock('@patternfly/react-icons/dist/esm/icons/check-circle-icon', () => () => 'Check circle icon mock');
jest.mock('@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon', () => () => 'Exclamation circle icon mock');
jest.mock('@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon', () => () =>
'Exclamation triangle icon mock'
);
jest.mock('@patternfly/react-icons/dist/esm/icons/info-circle-icon', () => () => 'Info circle icon mock');
jest.mock('@patternfly/react-icons/dist/esm/icons/bell-icon', () => () => 'Bell icon mock');

['default', 'info', 'success', 'warning', 'danger'].forEach((variant: string) => {
test(`${variant} banner`, () => {
const { asFragment } = render(
Expand All @@ -34,58 +26,20 @@ test(`sticky banner`, () => {
expect(asFragment()).toMatchSnapshot();
});

test('Renders with the bell icon when variant is not passed and hasStatusIcon is passed', () => {
render(<Banner hasStatusIcon>Default banner</Banner>);

expect(screen.getByText('Bell icon mock')).toBeVisible();
});

test('Renders with the bell icon when variant = "default" and hasStatusIcon is passed', () => {
render(
<Banner variant="default" hasStatusIcon>
Default banner
</Banner>
);

expect(screen.getByText('Bell icon mock')).toBeVisible();
});

test('Renders with the info circle icon when variant = "info" and hasStatusIcon is passed', () => {
render(
<Banner variant="info" hasStatusIcon>
Info banner
</Banner>
);

expect(screen.getByText('Info circle icon mock')).toBeVisible();
});

test('Renders with the exclamation circle icon when variant = "danger" and hasStatusIcon is passed', () => {
render(
<Banner variant="danger" hasStatusIcon>
Danger banner
</Banner>
);
test('Renders with screen reader text by default', () => {
render(<Banner>Banner text</Banner>);

expect(screen.getByText('Exclamation circle icon mock')).toBeVisible();
expect(screen.getByText('default banner')).toBeInTheDocument();
});

test('Renders with the check circle icon when variant = "success" and hasStatusIcon is passed', () => {
render(
<Banner variant="success" hasStatusIcon>
Success banner
</Banner>
);
test('Does not render with screen reader text when screenReaderText = null', () => {
render(<Banner screenReaderText={null}>Banner text</Banner>);

expect(screen.getByText('Check circle icon mock')).toBeVisible();
expect(screen.queryByText('default banner')).not.toBeInTheDocument();
});

test('Renders with the exclamation triangle icon when variant = "warning" and hasStatusIcon is passed', () => {
render(
<Banner variant="warning" hasStatusIcon>
Warning banner
</Banner>
);
test('Renders with custom screen reader text when screenReaderText is passed', () => {
render(<Banner screenReaderText="Custom screen reader text">Banner text</Banner>);

expect(screen.getByText('Exclamation triangle icon mock')).toBeVisible();
expect(screen.getByText('Custom screen reader text')).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ exports[`danger banner 1`] = `
aria-label="danger"
class="pf-c-banner pf-m-danger"
>
<span
class="pf-u-screen-reader"
>
danger banner
</span>
danger Banner
</div>
</DocumentFragment>
Expand All @@ -17,6 +22,11 @@ exports[`default banner 1`] = `
aria-label="default"
class="pf-c-banner"
>
<span
class="pf-u-screen-reader"
>
default banner
</span>
default Banner
</div>
</DocumentFragment>
Expand All @@ -28,6 +38,11 @@ exports[`info banner 1`] = `
aria-label="info"
class="pf-c-banner pf-m-info"
>
<span
class="pf-u-screen-reader"
>
info banner
</span>
info Banner
</div>
</DocumentFragment>
Expand All @@ -39,6 +54,11 @@ exports[`sticky banner 1`] = `
aria-label="sticky"
class="pf-c-banner pf-m-sticky"
>
<span
class="pf-u-screen-reader"
>
default banner
</span>
Sticky Banner
</div>
</DocumentFragment>
Expand All @@ -50,6 +70,11 @@ exports[`success banner 1`] = `
aria-label="success"
class="pf-c-banner pf-m-success"
>
<span
class="pf-u-screen-reader"
>
success banner
</span>
success Banner
</div>
</DocumentFragment>
Expand All @@ -61,6 +86,11 @@ exports[`warning banner 1`] = `
aria-label="warning"
class="pf-c-banner pf-m-warning"
>
<span
class="pf-u-screen-reader"
>
warning banner
</span>
warning Banner
</div>
</DocumentFragment>
Expand Down
10 changes: 9 additions & 1 deletion packages/react-core/src/components/Banner/examples/Banner.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@ cssPrefix: pf-c-banner
propComponents: ['Banner']
---

import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon';
import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon';
import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';

## Examples

### Basic

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.

The following example also passes in the `screenReaderText` property with a value of `null` to prevent visually hidden text meant for screen readers from rendering. When using a basic banner, a value of `null` or text that does not convey status/severity should be passed into `screenReaderText`.

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

### Status

When a banner is used to convey status, it is advised to pass in either the `hasStatusIcon` or `customIcon` property to render an icon inside the banner. This icon should convey the banner variant beyond just the banner color.
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.

```ts file="./BannerStatus.tsx"
```
18 changes: 13 additions & 5 deletions packages/react-core/src/components/Banner/examples/BannerBasic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@ import { Banner } from '@patternfly/react-core';

export const BannerBasic: React.FunctionComponent = () => (
<>
<Banner>Default banner</Banner>
<Banner screenReaderText={null}>Default banner</Banner>
<br />
<Banner variant="info">Blue banner</Banner>
<Banner screenReaderText={null} variant="info">
Blue banner
</Banner>
<br />
<Banner variant="danger">Red banner</Banner>
<Banner screenReaderText={null} variant="danger">
Red banner
</Banner>
<br />
<Banner variant="success">Green banner</Banner>
<Banner screenReaderText={null} variant="success">
Green banner
</Banner>
<br />
<Banner variant="warning">Gold banner</Banner>
<Banner screenReaderText={null} variant="warning">
Gold banner
</Banner>
</>
);
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import React from 'react';
import { Banner } from '@patternfly/react-core';
import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon';
import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon';
import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';

export const BannerStatus: React.FunctionComponent = () => (
<>
<Banner hasStatusIcon>Default banner</Banner>
<Banner>
<BellIcon /> Default banner
</Banner>
<br />
<Banner hasStatusIcon variant="info">
Info banner
<Banner variant="info">
<InfoCircleIcon /> Info banner
</Banner>
<br />
<Banner hasStatusIcon variant="danger">
Danger banner
<Banner variant="danger">
<ExclamationCircleIcon /> Danger banner
</Banner>
<br />
<Banner hasStatusIcon variant="success">
Success banner
<Banner variant="success">
<CheckCircleIcon /> Success banner
</Banner>
<br />
<Banner hasStatusIcon variant="warning">
Warning banner
<Banner variant="warning">
<ExclamationTriangleIcon /> Warning banner
</Banner>
</>
);

0 comments on commit cc9b1fa

Please sign in to comment.