Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

💄 Snackbar: implement [popover] #3577

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { useState } from 'react'
import { useArgs } from '@storybook/preview-api'
import { Dialog, DialogProps, Button, Radio, Typography, Tooltip } from '../..'
import {
Dialog,
DialogProps,
Button,
Radio,
Typography,
Tooltip,
Snackbar,
} from '../..'
import styled from 'styled-components'
import { StoryFn, Meta } from '@storybook/react'
import { Stack } from './../../../.storybook/components'
Expand Down Expand Up @@ -99,6 +107,7 @@ export const Introduction: StoryFn<DialogProps> = (args) => {

export const Dismissable: StoryFn<DialogProps> = () => {
const [isOpen, setIsOpen] = useState(false)
const [snackbar, setSnackbar] = useState(false)
const handleOpen = () => {
setIsOpen(true)
}
Expand All @@ -110,6 +119,13 @@ export const Dismissable: StoryFn<DialogProps> = () => {
<Button aria-haspopup="dialog" onClick={handleOpen}>
Trigger Dialog
</Button>
<Snackbar
open={snackbar}
onClose={() => setSnackbar(false)}
autoHideDuration={2000}
>
Snackbar in front of scrim!
</Snackbar>
<Dialog open={isOpen} isDismissable onClose={handleClose}>
<Dialog.Header>
<Dialog.Title>Dismissable dialog</Dialog.Title>
Expand All @@ -118,6 +134,9 @@ export const Dismissable: StoryFn<DialogProps> = () => {
<Typography variant="body_short">
Closes dialog on click outside and escape key.
</Typography>
<Button variant="outlined" onClick={() => setSnackbar(true)}>
Show a snackbar
</Button>
</Dialog.CustomContent>
<Dialog.Actions>
<Wrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,15 @@ describe('Snackbar', () => {
{message}
</Snackbar>,
)
expect(screen.getByTestId('test-snackbar-3')).toHaveStyleRule(
// eslint-disable-next-line testing-library/no-node-access
expect(screen.getByTestId('test-snackbar-3').parentElement).toHaveStyleRule(
'top',
tokens.spacings.top,
)
expect(screen.getByTestId('test-snackbar-3')).toHaveStyleRule('left', '50%')
// eslint-disable-next-line testing-library/no-node-access
expect(screen.getByTestId('test-snackbar-3').parentElement).toHaveStyleRule(
'left',
'50%',
)
})
})
51 changes: 33 additions & 18 deletions packages/eds-core-react/src/components/Snackbar/Snackbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useState, useEffect, HTMLAttributes, forwardRef, useRef } from 'react'
import * as ReactDom from 'react-dom'
import { useEffect, HTMLAttributes, forwardRef, useRef, useState } from 'react'
import styled, { css, ThemeProvider } from 'styled-components'
import { snackbar as SnackbarToken } from './Snackbar.tokens'
import {
Expand All @@ -12,6 +11,7 @@ import { Paper } from '../Paper'
import { useEds } from '../EdsProvider'

type StyledProps = {
popover: string
$placement?:
| 'left'
| 'right'
Expand All @@ -23,17 +23,16 @@ type StyledProps = {
| 'bottom-right'
}

const StyledSnackbar = styled(Paper)<StyledProps>(({ theme, $placement }) => {
const PopoverDiv = styled('div').withConfig({
shouldForwardProp: () => true, //workaround to avoid warning until popover gets added to react types
})<StyledProps>(({ theme, $placement }) => {
return css`
inset: unset;
border: 0;
overflow: visible;
position: fixed;
background-color: ${theme.background};
${spacingsTemplate(theme.spacings)}
${bordersTemplate(theme.border)}
${typographyTemplate(theme.typography)}
min-height: ${theme.minHeight};
box-sizing: border-box;
z-index: 1400;

padding: 0;
background-color: transparent;
${{
top: $placement.includes('top')
? theme.spacings.top
Expand All @@ -54,7 +53,20 @@ const StyledSnackbar = styled(Paper)<StyledProps>(({ theme, $placement }) => {
? 'translateX(-50%)'
: undefined,
}}
&::backdrop {
background-color: transparent;
}
`
})

const StyledSnackbar = styled(Paper)(({ theme }) => {
return css`
background-color: ${theme.background};
${spacingsTemplate(theme.spacings)}
${bordersTemplate(theme.border)}
${typographyTemplate(theme.typography)}
min-height: ${theme.minHeight};
box-sizing: border-box;
a,
button {
color: ${theme.entities.button.typography.color};
Expand Down Expand Up @@ -107,25 +119,28 @@ export const Snackbar = forwardRef<HTMLDivElement, SnackbarProps>(
}, autoHideDuration)
}
return () => clearTimeout(timer.current)
}, [open, autoHideDuration, setVisible, onClose])
}, [open, setVisible, autoHideDuration, onClose])

const props = {
ref,
$placement: placement,
...rest,
}
const { density } = useEds()
const token = useToken({ density }, SnackbarToken)

return (
<ThemeProvider theme={token}>
{visible &&
ReactDom.createPortal(
{visible && (
<PopoverDiv
popover="manual"
$placement={placement}
ref={(el) => el?.showPopover()}
>
<StyledSnackbar role="alert" elevation="overlay" {...props}>
{children}
</StyledSnackbar>,
document.body,
)}
</StyledSnackbar>
</PopoverDiv>
)}
</ThemeProvider>
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ exports[`Snackbar Matches snapshot 1`] = `
}

.c1 {
position: fixed;
background-color: var(--eds_ui_background__overlay, rgba(0, 0, 0, 0.8));
padding-left: 16px;
padding-top: 16px;
Expand All @@ -23,10 +22,6 @@ exports[`Snackbar Matches snapshot 1`] = `
text-align: left;
min-height: 48px;
box-sizing: border-box;
z-index: 1400;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
}

.c1 a,
Expand Down