-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add PersistantNotification component, stories and tests (#3921)
Co-authored-by: Will McVay <[email protected]>
- Loading branch information
Showing
6 changed files
with
337 additions
and
1 deletion.
There are no files selected for viewing
100 changes: 100 additions & 0 deletions
100
packages/elements/src/components-v3/PersistantNotification/__styles__/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { css } from 'linaria' | ||
import { styled } from 'linaria/react' | ||
import { ElIcon } from '../../Icon/__styles__' | ||
import { elIsActive } from '../../../styles-v3/base/states' | ||
import { | ||
elIntentPrimary, | ||
elIntentSecondary, | ||
elIntentCritical, | ||
elIntentSuccess, | ||
elIntentDanger, | ||
} from '../../../styles-v3/base/intent' | ||
|
||
export const elPnIcon = css` | ||
padding: 0 0.5rem; | ||
display: flex; | ||
align-items: center; | ||
border-radius var(--default-border-radius) 0 0 var(--default-border-radius); | ||
cursor: pointer; | ||
${ElIcon} { | ||
color: var(--color-white); | ||
} | ||
` | ||
|
||
export const elPnContent = css` | ||
padding: 0.75rem 1.25rem; | ||
opacity: 0; | ||
transition: 0.5s; | ||
` | ||
|
||
export const ElPersistantNotification = styled.div` | ||
display: flex; | ||
position: fixed; | ||
top: 1rem; | ||
right: 2rem; // should be the width of the elPnIcon element (icon is 1rem and padding is 0.5rem each side) | ||
max-width: 50%; | ||
transform: translateX(100%); | ||
transition: 0.5s; | ||
z-index: 10; | ||
&${elIsActive} { | ||
right: 0; | ||
transform: translateX(0); | ||
.${elPnContent} { | ||
opacity: 1; | ||
} | ||
} | ||
&${elIntentPrimary} { | ||
.${elPnContent} { | ||
background: var(--intent-primary-light); | ||
color: var(--intent-primary-light-text); | ||
} | ||
.${elPnIcon} { | ||
background: var(--intent-primary); | ||
color: var(--intent-primary-text); | ||
} | ||
} | ||
&${elIntentSecondary} { | ||
.${elPnContent} { | ||
background: var(--intent-secondary-light); | ||
color: var(--intent-secondary-light-text); | ||
} | ||
.${elPnIcon} { | ||
background: var(--intent-secondary); | ||
color: var(--intent-secondary-text); | ||
} | ||
} | ||
&${elIntentCritical} { | ||
.${elPnContent} { | ||
background: var(--intent-critical-light); | ||
color: var(--intent-critical-light-text); | ||
} | ||
.${elPnIcon} { | ||
background: var(--intent-critical); | ||
color: var(--intent-critical-text); | ||
} | ||
} | ||
&${elIntentSuccess} { | ||
.${elPnContent} { | ||
background: var(--intent-success-light); | ||
color: var(--intent-success-light-text); | ||
} | ||
.${elPnIcon} { | ||
background: var(--intent-success); | ||
color: var(--intent-success-text); | ||
} | ||
} | ||
&${elIntentDanger} { | ||
.${elPnContent} { | ||
background: var(--intent-danger-light); | ||
color: var(--intent-danger-light-text); | ||
} | ||
.${elPnIcon} { | ||
background: var(--intent-danger); | ||
color: var(--intent-danger-text); | ||
} | ||
} | ||
` |
61 changes: 61 additions & 0 deletions
61
.../elements/src/components-v3/PersistantNotification/__tests__/__snapshots__/index.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`PersistantNotification component should match a snapshot 1`] = ` | ||
<ElPersistantNotification | ||
className="el-intent-secondary" | ||
> | ||
<div | ||
className="el-pn-icon" | ||
onClick={[Function]} | ||
> | ||
<Icon | ||
icon="info" | ||
/> | ||
</div> | ||
<div | ||
className="el-pn-content" | ||
> | ||
I am notification | ||
</div> | ||
</ElPersistantNotification> | ||
`; | ||
|
||
exports[`PersistantNotification component should match a snapshot when expanded 1`] = ` | ||
<ElPersistantNotification | ||
className="el-intent-secondary el-is-active" | ||
> | ||
<div | ||
className="el-pn-icon" | ||
onClick={[Function]} | ||
> | ||
<Icon | ||
icon="info" | ||
/> | ||
</div> | ||
<div | ||
className="el-pn-content" | ||
> | ||
I am notification | ||
</div> | ||
</ElPersistantNotification> | ||
`; | ||
|
||
exports[`PersistantNotification component should match a snapshot when given an intent 1`] = ` | ||
<ElPersistantNotification | ||
className="el-intent-critical" | ||
> | ||
<div | ||
className="el-pn-icon" | ||
onClick={[Function]} | ||
> | ||
<Icon | ||
icon="info" | ||
/> | ||
</div> | ||
<div | ||
className="el-pn-content" | ||
> | ||
I am notification | ||
</div> | ||
</ElPersistantNotification> | ||
`; |
32 changes: 32 additions & 0 deletions
32
packages/elements/src/components-v3/PersistantNotification/__tests__/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import * as React from 'react' | ||
import { shallow } from 'enzyme' | ||
import { PersistantNotification } from '../' | ||
import { elPnIcon } from '../__styles__' | ||
|
||
describe('PersistantNotification component', () => { | ||
it('should match a snapshot', () => { | ||
const wrapper = shallow(<PersistantNotification>I am notification</PersistantNotification>) | ||
expect(wrapper).toMatchSnapshot() | ||
}) | ||
|
||
it('should match a snapshot when given an intent', () => { | ||
const wrapper = shallow(<PersistantNotification intent="critical">I am notification</PersistantNotification>) | ||
expect(wrapper).toMatchSnapshot() | ||
}) | ||
|
||
it('should match a snapshot when expanded', () => { | ||
const wrapper = shallow(<PersistantNotification isExpanded={true}>I am notification</PersistantNotification>) | ||
expect(wrapper).toMatchSnapshot() | ||
}) | ||
|
||
it('should fire the onStepClick event correctly', () => { | ||
const spy = jest.fn() | ||
const wrapper = shallow( | ||
<PersistantNotification intent="critical" onExpansionToggle={spy}> | ||
I am notification | ||
</PersistantNotification>, | ||
) | ||
wrapper.find(`.${elPnIcon}`).first().simulate('click') | ||
expect(spy).toHaveBeenCalledTimes(1) | ||
}) | ||
}) |
36 changes: 36 additions & 0 deletions
36
packages/elements/src/components-v3/PersistantNotification/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { cx } from 'linaria' | ||
import * as React from 'react' | ||
import { ElPersistantNotification, elPnIcon, elPnContent } from './__styles__' | ||
import { Icon, IconNames } from '../Icon' | ||
import { elIsActive } from '../../styles-v3/base/states' | ||
import { Intent, getIntentClassName } from '../../helpers/v3/intent' | ||
|
||
export interface IPersistantNotification extends React.HTMLAttributes<HTMLDivElement> { | ||
icon?: IconNames | ||
intent?: Intent | ||
className?: string | ||
isExpanded?: boolean | ||
onExpansionToggle?: (newState: boolean) => void | ||
} | ||
|
||
export const PersistantNotification: React.FC<IPersistantNotification> = ({ | ||
icon = 'info', | ||
intent = 'secondary', | ||
className, | ||
isExpanded = false, | ||
onExpansionToggle, | ||
children, | ||
...rest | ||
}) => { | ||
const intentClassName = getIntentClassName(intent) | ||
const combinedClassName = cx(className, intentClassName, isExpanded && elIsActive) | ||
|
||
return ( | ||
<ElPersistantNotification className={combinedClassName} {...rest}> | ||
<div className={elPnIcon} onClick={() => onExpansionToggle && onExpansionToggle(!isExpanded)}> | ||
<Icon icon={icon} /> | ||
</div> | ||
<div className={elPnContent}>{children}</div> | ||
</ElPersistantNotification> | ||
) | ||
} |
107 changes: 107 additions & 0 deletions
107
...nts/src/components-v3/PersistantNotification/persistantNotification.stories.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs/blocks' | ||
import { useState } from 'react' | ||
import { PersistantNotification } from './index' | ||
|
||
<Meta title="V3/PersistantNotification" component={PersistantNotification} /> | ||
|
||
# PersistantNotification | ||
|
||
Underlying tag: `<div>` | ||
|
||
## Full React example using `useState` and the default CSS position: fixed | ||
|
||
<Canvas> | ||
<Story name="Full React example (fixed position)"> | ||
{() => { | ||
const [isExpanded, setIsExpanded] = useState(false) | ||
return ( | ||
<> | ||
The element uses CSS position fixed by default, which means the component "floats" on top of all other | ||
content. This example can be seen in the top right corner of the screen. Only one PersistantNotification per | ||
page is supported. | ||
<PersistantNotification isExpanded={isExpanded} onExpansionToggle={setIsExpanded}> | ||
Here is a persistant notification. Here is more content. Here is more content. Here is more content. Here is | ||
more content. Here is more content. | ||
</PersistantNotification> | ||
</> | ||
) | ||
}} | ||
</Story> | ||
</Canvas> | ||
|
||
<ArgsTable of={PersistantNotification} /> | ||
|
||
## Inline examples | ||
|
||
These stories have been given a custom CSS positon (`position: relative`) so that they appear inline. This makes it easier to preview these examples, but in normal usage they will pin to the top right of the screen as in the above example. | ||
|
||
### Default usage | ||
|
||
<Canvas> | ||
<Story name="Default Usage"> | ||
<PersistantNotification isExpanded={true} style={{ position: 'relative' }}> | ||
Here is a persistant notification | ||
</PersistantNotification> | ||
</Story> | ||
</Canvas> | ||
|
||
### With longer content | ||
|
||
The notification is set to a max-width of 50% of the parent element (in normal usage this is the entire window). If the content is longer the box just grows downwards. | ||
|
||
<Canvas> | ||
<Story name="Long text"> | ||
<PersistantNotification isExpanded={true} style={{ position: 'relative' }}> | ||
Here is a persistant notification. Here is more content. Here is more content. Here is more content. Here is more | ||
content. Here is more content. | ||
</PersistantNotification> | ||
</Story> | ||
</Canvas> | ||
|
||
### With a different icon | ||
|
||
<Canvas> | ||
<Story name="With a different icon"> | ||
<PersistantNotification isExpanded={true} icon="warning" style={{ position: 'relative' }}> | ||
Here's some infomation about the thing you should be warned about, so bad things don't happen. | ||
</PersistantNotification> | ||
</Story> | ||
</Canvas> | ||
|
||
### With different intents | ||
|
||
<Canvas> | ||
<Story name="Intent: primary"> | ||
<PersistantNotification isExpanded={true} intent="primary" style={{ position: 'relative' }}> | ||
Here's a notification with a primary intent. | ||
</PersistantNotification> | ||
</Story> | ||
<Story name="Intent: secondary (default)"> | ||
<PersistantNotification isExpanded={true} intent="secondary" style={{ position: 'relative' }}> | ||
Here's a notification with a secondary intent. | ||
</PersistantNotification> | ||
</Story> | ||
<Story name="Intent: critical"> | ||
<PersistantNotification isExpanded={true} intent="critical" style={{ position: 'relative' }}> | ||
Here's a notification with a critical intent. | ||
</PersistantNotification> | ||
</Story> | ||
<Story name="Intent: success"> | ||
<PersistantNotification isExpanded={true} intent="success" style={{ position: 'relative' }}> | ||
Here's a notification with a success intent. | ||
</PersistantNotification> | ||
</Story> | ||
<Story name="Intent: danger"> | ||
<PersistantNotification isExpanded={true} intent="danger" style={{ position: 'relative' }}> | ||
Here's a notification with a danger intent. | ||
</PersistantNotification> | ||
</Story> | ||
</Canvas> | ||
|
||
### Collapsed/Expanded state | ||
|
||
Set the prop `isExpanded` to expand/collapse the component. In the collapsed state the whole component is moved to the right. In normal usage when the component is fixed to the right of the screen this means the content is out of view. | ||
|
||
## Other attributes | ||
|
||
All other standard HTML attributes for `<div>` are supported and are passed through to the React component. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters