Skip to content

Commit

Permalink
feat(AppNotification)!: introduce 2.0 component (#1945)
Browse files Browse the repository at this point in the history
- add component with specified design and code API
- add in tests and stories
- support button alignment in ButtonGroup via new internal value
  • Loading branch information
booc0mtaco authored May 16, 2024
1 parent 2f25f6b commit 489e8d9
Show file tree
Hide file tree
Showing 12 changed files with 540 additions and 2 deletions.
1 change: 1 addition & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const parameters = {
],
},
badgesConfig: {
...createInitialReleaseConfig('2.0'),
...createInitialReleaseConfig('1.3'),
...createInitialReleaseConfig('1.2'),
...createInitialReleaseConfig('1.1'),
Expand Down
55 changes: 55 additions & 0 deletions src/components/AppNotification/AppNotification.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*------------------------------------*\
# APP NOTIFICATION
\*------------------------------------*/

/**
* AppNotification
*/
.app-notification {
padding: 1.5rem;

&.app-notification--color-dark {
color: var(--eds-theme-color-text-utility-inverse);
background-color: var(--eds-theme-color-background-utility-default-high-emphasis);
}

&.app-notification--color-light {
color: var(--eds-theme-color-text-utility-default-primary-active);
background-color: var(--eds-theme-color-background-utility-container);
}

@media (min-width: $eds-bp-sm) {
padding-left: calc(var(--eds-size-6) * 1px);
padding-right: calc(var(--eds-size-6) * 1px);
}

@media (min-width: $eds-bp-xl) {
.app-notification__content {
margin: 0 auto;
}
}
}

.app-notification__title {
margin-bottom: 0.5rem;
}

/* .app-notification__sub-title {
} */

.app-notification__actions {
margin-top: 1.5rem;
}

.app-notification__content {
/* TODO-AH: how to define this magic number */
max-width: 1320px;
display: flex;
gap: 0.5rem;
}

.app-notification__close-btn {
flex-shrink: 0;
margin-top: -0.5rem;
margin-right: -0.5rem;
}
81 changes: 81 additions & 0 deletions src/components/AppNotification/AppNotification.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { BADGE } from '@geometricpanda/storybook-addon-badges';
import type { StoryObj, Meta } from '@storybook/react';

import React from 'react';

import { AppNotification } from './AppNotification';
import { ButtonV2 as Button } from '../Button';
import { ButtonGroupV2 as ButtonGroup } from '../ButtonGroup';

export default {
title: 'Components/V2/AppNotification',
component: AppNotification,
parameters: {
badges: [BADGE.BETA, 'intro-2.0', 'current-2.0'],
},
args: {
title: 'This is an AppNotification title',
subTitle:
'Lorem ipsum dolor sit amet consectetur. At et vitae quis amet felis mollis in vitae. Eget in neque et molestie. Luctus sed id commodo volutpat. In a eu in id molestie consectetur pellentesque.',
},
argTypes: {
children: {
control: {
type: null,
},
},
},
} as Meta<Args>;

type Args = React.ComponentProps<typeof AppNotification>;

export const Default: StoryObj<Args> = {
args: {},
};

export const WithControls: StoryObj<Args> = {
args: {
children: (
<ButtonGroup buttonLayout="horizontal" className="!flex-row">
<Button rank="secondary" variant="inverse">
Call To Action
</Button>
<Button rank="tertiary" variant="inverse">
Other action
</Button>
</ButtonGroup>
),
},
};

export const LightColor: StoryObj<Args> = {
args: {
color: 'light',
children: (
<ButtonGroup buttonLayout="horizontal-align-left">
<Button rank="secondary">Call To Action</Button>
<Button rank="tertiary">Other action</Button>
</ButtonGroup>
),
},
};

export const WithDismissAndControls: StoryObj<Args> = {
args: {
...WithControls.args,
onDismiss: () => {
console.log('dismissing!');
},
},
};

export const LightWithDismissAndControls: StoryObj<Args> = {
args: {
...LightColor.args,
onDismiss: () => {
console.log('dismissing!');
},
},
};

// TODO-AH: add in responsive tests for each breakpoint to cover layout and spacing
8 changes: 8 additions & 0 deletions src/components/AppNotification/AppNotification.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { generateSnapshots } from '@chanzuckerberg/story-utils';
import type { StoryFile } from '@storybook/testing-react';

import * as stories from './AppNotification.stories';

describe('<AppNotification />', () => {
generateSnapshots(stories as StoryFile);
});
94 changes: 94 additions & 0 deletions src/components/AppNotification/AppNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import clsx from 'clsx';
import React from 'react';
import { ButtonV2 as Button } from '../Button';
import Text from '../Text';
import styles from './AppNotification.module.css';

export interface Props {
// Design API
/**
* The title/heading of the notification
*/
title: string;
/**
* Secondary text used to describe the notification in more detail
*/
subTitle: React.ReactNode;
/**
* Treatment for component (whether it is dark on light text, or light on dark text)
*/
color: 'dark' | 'light';

// Component API
/**
* Contents of the component below the title and sub-title (used mainly for `ButtonGroup`)
*/
children?: React.ReactNode;
/**
* CSS class names that can be appended to the component.
*/
className?: string;
/**
* Callback when banner is dismissed. When passed in, renders banner with a close icon in the top right.
*/
onDismiss?: () => void;
}

/**
* `import {AppNotification} from "@chanzuckerberg/eds";`
*
* An alert placed at the top of an application which persists across pages.
*/
export const AppNotification = ({
className,
children,
color = 'dark',
onDismiss,
subTitle,
title,
...other
}: Props) => {
const componentClassName = clsx(
styles['app-notification'],
color && styles[`app-notification--color-${color}`],
className,
);

return (
<div className={componentClassName} role="status" {...other}>
<div className={styles['app-notification__content']}>
<section>
<Text
as="div"
className={styles['app-notification__title']}
preset="headline-sm-bold"
>
{title}
</Text>
<Text
as="p"
className={styles['app-notification__sub-title']}
preset="body-md"
>
{subTitle}
</Text>
<div className={styles['app-notification__actions']}>{children}</div>
</section>
{onDismiss && (
<Button
aria-label="close"
className={styles['app-notification__close-btn']}
context="default"
icon="close"
iconLayout="icon-only"
onClick={onDismiss}
rank="tertiary"
variant={color === 'dark' ? 'inverse' : 'neutral'}
>
Close
</Button>
)}
</div>
</div>
);
};
Loading

0 comments on commit 489e8d9

Please sign in to comment.