-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* First commit * Simple version of snackbar * Add support for async/await in tests https://github.com/facebook/jest/issues/3126\#issuecomment-483320742 * Tests for snackbar * Add better button labels, add knobs for storybook * Add version with Moss green 34 as action button color * Remove button color because of lack of contrast on hover * Wider query for 'larger screen' -> 1200px. Swap center and left, had this mixed up * Add lighter button color example
- Loading branch information
Showing
8 changed files
with
344 additions
and
2 deletions.
There are no files selected for viewing
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,120 @@ | ||
import React, { Fragment, useState } from 'react' | ||
import { withKnobs, select, text } from '@storybook/addon-knobs' | ||
import { Snackbar, Button, Typography } from '@equinor/eds-core-react' | ||
|
||
const { SnackbarAction } = Snackbar | ||
import styled from 'styled-components' | ||
import { tokens } from '@equinor/eds-tokens' | ||
|
||
const { | ||
colors: { | ||
infographic: { | ||
primary__moss_green_34: { rgba: buttonColor }, | ||
}, | ||
}, | ||
} = tokens | ||
|
||
const Wrapper = styled.div` | ||
display: grid; | ||
grid-template-rows: min-width; | ||
padding: 32px 0; | ||
padding-bottom: 8rem; | ||
grid-gap: 2rem; | ||
` | ||
// At the moment you'll have to override the default ghost button with this slightly lighter color for better contrast on dark background | ||
const StyledButton = styled(Button)` | ||
:not(:hover) { | ||
color: ${buttonColor}; | ||
} | ||
` | ||
|
||
export default { | ||
title: 'Components|Snackbar', | ||
component: Snackbar, | ||
} | ||
|
||
export const Example = () => { | ||
const [open, setOpen] = useState(false) | ||
const [withActionOpen, setWithActionOpen] = useState(false) | ||
|
||
return ( | ||
<Wrapper> | ||
<div> | ||
<Button type="button" onClick={() => setOpen(true)}> | ||
Show a simple snackbar for 5 seconds | ||
</Button> | ||
<Snackbar | ||
open={open} | ||
onClose={() => setOpen(false)} | ||
autoHideDuration={5000} | ||
leftAlignFrom="1500px" | ||
> | ||
Message goes here | ||
</Snackbar> | ||
</div> | ||
<div> | ||
<Button type="button" onClick={() => setWithActionOpen(true)}> | ||
Show a snackbar with action for the default 7 seconds | ||
</Button> | ||
<Snackbar | ||
open={withActionOpen} | ||
onClose={() => setWithActionOpen(false)} | ||
> | ||
Your changes was saved | ||
<SnackbarAction> | ||
<StyledButton variant="ghost">Undo</StyledButton> | ||
</SnackbarAction> | ||
</Snackbar> | ||
</div> | ||
</Wrapper> | ||
) | ||
} | ||
|
||
const autoHideDurationOptions = { | ||
Five: 5000, | ||
Six: 6000, | ||
Seven: 7000, | ||
Eight: 8000, | ||
Nine: 9000, | ||
Ten: 10000, | ||
} | ||
|
||
const actionOptions = { | ||
none: null, | ||
undoButton: 'button', | ||
} | ||
|
||
export const knobs = () => { | ||
const [open, setOpen] = useState(false) | ||
const message = text('Message', 'Message goes here') | ||
const duration = select('Duration in seconds', autoHideDurationOptions) | ||
const action = select('Action', actionOptions) | ||
|
||
return ( | ||
<Wrapper> | ||
<div> | ||
<Button onClick={() => setOpen(true)}>Trigger snackbar</Button> | ||
</div> | ||
{open && ( | ||
<Snackbar | ||
open={open} | ||
onClose={() => setOpen(false)} | ||
autoHideDuration={duration} | ||
> | ||
{message} | ||
{action} | ||
{action && ( | ||
<SnackbarAction> | ||
<Button variant="ghost">Undo</Button> | ||
</SnackbarAction> | ||
)} | ||
</Snackbar> | ||
)} | ||
</Wrapper> | ||
) | ||
} | ||
|
||
knobs.story = { | ||
name: 'With knobs', | ||
decorators: [withKnobs], | ||
} |
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
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,83 @@ | ||
import React, { useState, useEffect } from 'react' | ||
import PropTypes from 'prop-types' | ||
import styled from 'styled-components' | ||
import { snackbar as tokens } from './Snackbar.tokens' | ||
import { typographyTemplate } from '../_common/templates' | ||
|
||
const StyledSnackbar = styled.div.attrs(() => ({ | ||
role: 'alert', | ||
}))` | ||
position: fixed; | ||
left: ${tokens.spacings.left}; | ||
bottom: ${tokens.spacings.bottom}; | ||
background-color: ${tokens.background}; | ||
padding: ${tokens.spacings.padding}; | ||
border-radius: ${tokens.borderRadius}; | ||
${typographyTemplate(tokens.text.typography)} | ||
color: ${tokens.text.color}; | ||
box-shadow: ${tokens.boxShadow}; | ||
min-height: ${tokens.minHeight}; | ||
box-sizing: border-box; | ||
left: 50%; | ||
transform: translateX(-50%); | ||
@media (min-width: ${({ leftAlignFrom }) => leftAlignFrom}) { | ||
left: auto; | ||
transform: none; | ||
} | ||
` | ||
|
||
export const Snackbar = ({ | ||
open, | ||
autoHideDuration, | ||
onClose, | ||
leftAlignFrom, | ||
children, | ||
className, | ||
}) => { | ||
const [visible, setVisible] = useState(open) | ||
useEffect(() => { | ||
setVisible(open) | ||
const timer = setTimeout(() => { | ||
setVisible(false) | ||
if (onClose) { | ||
onClose() | ||
} | ||
}, autoHideDuration) | ||
return () => clearTimeout(timer) | ||
}, [open]) | ||
return ( | ||
<> | ||
{visible && ( | ||
<StyledSnackbar leftAlignFrom={leftAlignFrom} className={className}> | ||
{children} | ||
</StyledSnackbar> | ||
)} | ||
</> | ||
) | ||
} | ||
|
||
Snackbar.displayName = 'eds-snackbar' | ||
|
||
Snackbar.propTypes = { | ||
/** Controls the visibility of the snackbar */ | ||
open: PropTypes.bool, | ||
/** How long will the message be visible in milliseconds */ | ||
autoHideDuration: PropTypes.number, | ||
/** @ignore */ | ||
children: PropTypes.node.isRequired, | ||
/** @ignore */ | ||
className: PropTypes.string, | ||
/** Callback fired when the snackbar is closed by auto hide duration timeout */ | ||
onClose: PropTypes.func, | ||
/** Media query from which the snackbar will be horizontal centered */ | ||
centerAlignFrom: PropTypes.string, | ||
} | ||
|
||
Snackbar.defaultProps = { | ||
autoHideDuration: 7000, | ||
onClose: undefined, | ||
open: false, | ||
leftAlignFrom: '1200px', | ||
className: undefined, | ||
} |
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,67 @@ | ||
/* eslint-disable no-undef */ | ||
|
||
import React from 'react' | ||
import { | ||
render, | ||
cleanup, | ||
waitForElementToBeRemoved, | ||
} from '@testing-library/react' | ||
|
||
import '@testing-library/jest-dom' | ||
|
||
import 'jest-styled-components' | ||
import styled from 'styled-components' | ||
|
||
import { Snackbar } from './index' | ||
|
||
const { SnackbarAction } = Snackbar | ||
|
||
afterEach(cleanup) | ||
|
||
const StyledSnackbar = styled(Snackbar)` | ||
clip-path: unset; | ||
` | ||
const message = "Hi, I'm the snackbar" | ||
|
||
describe('Snackbar', () => { | ||
it('Can extend the css for the component', () => { | ||
const { container } = render( | ||
<StyledSnackbar open>{message}</StyledSnackbar>, | ||
) | ||
expect(container.firstChild).toHaveStyleRule('clip-path', 'unset') | ||
}) | ||
it('Sets the message', () => { | ||
const { getByText } = render(<Snackbar open>{message}</Snackbar>) | ||
const snackbar = getByText(message) | ||
expect(snackbar).toBeDefined() | ||
}) | ||
it('Is only visible when the open prop is true', () => { | ||
const { rerender, container } = render( | ||
<StyledSnackbar open={false}>{message}</StyledSnackbar>, | ||
) | ||
expect(container.firstChild).toBe(null) | ||
rerender(<StyledSnackbar open>{message}</StyledSnackbar>) | ||
expect(container.firstChild).not.toBe(null) | ||
}) | ||
it('Disappears automatically after a provided timeout', async () => { | ||
const { queryByText } = render( | ||
<Snackbar open autoHideDuration={1000}> | ||
{message} | ||
</Snackbar>, | ||
) | ||
expect(queryByText(message)).toBeDefined() | ||
await waitForElementToBeRemoved(() => queryByText(message)) | ||
}) | ||
it('Can have one button attached', () => { | ||
const buttonText = "I'm the button" | ||
const { queryByText } = render( | ||
<Snackbar open> | ||
{message} | ||
<SnackbarAction> | ||
<button type="button">{buttonText}</button> | ||
</SnackbarAction> | ||
</Snackbar>, | ||
) | ||
expect(queryByText(buttonText)).toBeDefined() | ||
}) | ||
}) |
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,39 @@ | ||
import { tokens } from '@equinor/eds-tokens' | ||
|
||
const { | ||
typography: { | ||
ui: { snackbar: typography }, | ||
}, | ||
colors: { | ||
ui: { | ||
background__overlay: { rgba: background }, | ||
}, | ||
text: { | ||
static_icons__primary_white: { hex: color }, | ||
}, | ||
}, | ||
spacings: { | ||
comfortable: { medium: spacingMedium }, | ||
}, | ||
elevation: { overlay: boxShadow }, | ||
clickbounds: { default__base: clickbounds }, | ||
} = tokens | ||
|
||
export const snackbar = { | ||
background, | ||
boxShadow, | ||
minHeight: clickbounds, | ||
spacings: { | ||
left: spacingMedium, | ||
bottom: spacingMedium, | ||
padding: spacingMedium, | ||
actionSpace: '32px', | ||
}, | ||
text: { | ||
color, | ||
typography: { | ||
...typography, | ||
}, | ||
}, | ||
borderRadius: '4px', | ||
} |
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,20 @@ | ||
import React, { Children } from 'react' | ||
import PropTypes from 'prop-types' | ||
import styled from 'styled-components' | ||
import { snackbar as tokens } from './Snackbar.tokens' | ||
|
||
const StyledSnackbarAction = styled.div` | ||
display: inline-flex; | ||
margin-left: ${tokens.spacings.actionSpace}; | ||
margin-top: -10px; | ||
margin-bottom: -10px; | ||
` | ||
|
||
export const SnackbarAction = ({ children }) => { | ||
return <StyledSnackbarAction>{Children.only(children)}</StyledSnackbarAction> | ||
} | ||
|
||
SnackbarAction.propTypes = { | ||
/** @ignore */ | ||
children: PropTypes.node.isRequired, | ||
} |
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,8 @@ | ||
import { SnackbarAction } from './SnackbarAction' | ||
import { Snackbar } from './Snackbar' | ||
|
||
Snackbar.SnackbarAction = SnackbarAction | ||
|
||
export { Snackbar } | ||
|
||
/* export { useSnackbars } from './snackbar-hook' */ |
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