mirror of
https://github.com/acid-info/lsd.git
synced 2025-01-28 17:55:08 +00:00
feat: toast componet v0.1 - missing position and animation props
This commit is contained in:
parent
ade4af1856
commit
dc9ce1f4a8
@ -39,6 +39,7 @@ import { NumberInputStyles } from '../NumberInput/NumberInput.styles'
|
|||||||
import { ModalStyles } from '../Modal/Modal.styles'
|
import { ModalStyles } from '../Modal/Modal.styles'
|
||||||
import { ModalFooterStyles } from '../ModalFooter/ModalFooter.styles'
|
import { ModalFooterStyles } from '../ModalFooter/ModalFooter.styles'
|
||||||
import { ModalBodyStyles } from '../ModalBody/ModalBody.styles'
|
import { ModalBodyStyles } from '../ModalBody/ModalBody.styles'
|
||||||
|
import { ToastStyles } from '../Toast/Toast.styles'
|
||||||
|
|
||||||
const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
|
const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
|
||||||
[
|
[
|
||||||
@ -80,6 +81,7 @@ const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
|
|||||||
DatePickerStyles,
|
DatePickerStyles,
|
||||||
DateFieldStyles,
|
DateFieldStyles,
|
||||||
CalendarStyles,
|
CalendarStyles,
|
||||||
|
ToastStyles,
|
||||||
]
|
]
|
||||||
|
|
||||||
export const CSSBaseline: React.FC<{ theme?: Theme }> = ({
|
export const CSSBaseline: React.FC<{ theme?: Theme }> = ({
|
||||||
|
24
packages/lsd-react/src/components/Toast/Toast.classes.ts
Normal file
24
packages/lsd-react/src/components/Toast/Toast.classes.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export const toastClasses = {
|
||||||
|
root: `lsd-toast`,
|
||||||
|
|
||||||
|
inlineContainer: 'lsd-toast__inline-container',
|
||||||
|
blockContainer: 'lsd-toast__block-container',
|
||||||
|
|
||||||
|
large: 'lsd-toast--large',
|
||||||
|
medium: 'lsd-toast--medium',
|
||||||
|
small: 'lsd-toast--small',
|
||||||
|
|
||||||
|
textContainer: 'lsd-toast__text-container',
|
||||||
|
title: 'lsd-toast__title',
|
||||||
|
information: 'lsd-toast__information',
|
||||||
|
|
||||||
|
inlineButtonContainer: 'lsd-toast__inline-button-container',
|
||||||
|
hiddenButtonContainer: 'lsd-toast__hidden-button-container',
|
||||||
|
blockButton: 'lsd-toast__block-button',
|
||||||
|
|
||||||
|
closeButton: 'lsd-toast__close-button',
|
||||||
|
actionButton: 'lsd-toast__action-button',
|
||||||
|
|
||||||
|
errorIcon: 'lsd-toast__error-icon',
|
||||||
|
errorIconContainer: 'lsd-toast__error-icon-container',
|
||||||
|
}
|
43
packages/lsd-react/src/components/Toast/Toast.stories.tsx
Normal file
43
packages/lsd-react/src/components/Toast/Toast.stories.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import { Meta, Story } from '@storybook/react'
|
||||||
|
import { Toast, ToastProps } from './Toast'
|
||||||
|
import { Button } from '../Button'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Toast',
|
||||||
|
component: Toast,
|
||||||
|
argTypes: {
|
||||||
|
size: {
|
||||||
|
type: {
|
||||||
|
name: 'enum',
|
||||||
|
value: ['small', 'medium', 'large'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Meta
|
||||||
|
|
||||||
|
export const Root: Story<ToastProps> = ({ buttonText, ...args }) => {
|
||||||
|
const [isVisible, setIsVisible] = useState(args.isOpen)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ width: 400, position: 'relative' }}>
|
||||||
|
<Button onClick={() => setIsVisible(!isVisible)}>Show Toast</Button>
|
||||||
|
<Toast
|
||||||
|
{...args}
|
||||||
|
isOpen={isVisible}
|
||||||
|
onClose={() => setIsVisible(false)}
|
||||||
|
buttonText={buttonText}
|
||||||
|
onButtonClick={() => alert('Button clicked!')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Root.args = {
|
||||||
|
title: 'Toast Title',
|
||||||
|
information: '',
|
||||||
|
size: 'large',
|
||||||
|
buttonText: 'Click me',
|
||||||
|
isOpen: false,
|
||||||
|
inline: true,
|
||||||
|
}
|
106
packages/lsd-react/src/components/Toast/Toast.styles.ts
Normal file
106
packages/lsd-react/src/components/Toast/Toast.styles.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { css } from '@emotion/react'
|
||||||
|
import { toastClasses } from './Toast.classes'
|
||||||
|
|
||||||
|
export const ToastStyles = css`
|
||||||
|
.${toastClasses.root} {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 20px;
|
||||||
|
background: rgb(var(--lsd-surface-primary));
|
||||||
|
border: 1px solid rgb(var(--lsd-border-primary));
|
||||||
|
padding: 8px;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.inlineButtonContainer} {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.hiddenButtonContainer} {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.blockButton} {
|
||||||
|
margin-top: 18px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.inlineContainer} {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.blockContainer} {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.textContainer} {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
color: rgb(var(--lsd-text-secondary));
|
||||||
|
margin-left: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.title} {
|
||||||
|
position: relative;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.information} {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.actionButton} {
|
||||||
|
height: 28px;
|
||||||
|
min-width: 60px;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 6px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.closeButton} {
|
||||||
|
margin-bottom: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 28px;
|
||||||
|
width: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.errorIconContainer} {
|
||||||
|
width: 26px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.errorIcon} {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: -26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.large} {
|
||||||
|
.${toastClasses.textContainer} {
|
||||||
|
min-width: 204px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.medium} {
|
||||||
|
.${toastClasses.textContainer} {
|
||||||
|
min-width: 184px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.${toastClasses.small} {
|
||||||
|
.${toastClasses.textContainer} {
|
||||||
|
min-width: 144px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
116
packages/lsd-react/src/components/Toast/Toast.tsx
Normal file
116
packages/lsd-react/src/components/Toast/Toast.tsx
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import clsx from 'clsx'
|
||||||
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
CommonProps,
|
||||||
|
omitCommonProps,
|
||||||
|
useCommonProps,
|
||||||
|
} from '../../utils/useCommonProps'
|
||||||
|
import { toastClasses } from './Toast.classes'
|
||||||
|
import { CloseIcon, ErrorIcon } from '../Icons'
|
||||||
|
import { IconButton } from '../IconButton'
|
||||||
|
import { Typography } from '../Typography'
|
||||||
|
import { Button } from '../Button'
|
||||||
|
|
||||||
|
export type ToastProps = CommonProps &
|
||||||
|
Omit<React.HTMLAttributes<HTMLDivElement>, 'label'> & {
|
||||||
|
isOpen: boolean
|
||||||
|
title: string
|
||||||
|
information?: string
|
||||||
|
inline?: boolean
|
||||||
|
buttonText?: string
|
||||||
|
onButtonClick?: () => void
|
||||||
|
onClose?: () => void
|
||||||
|
size?: 'large' | 'medium' | 'small'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Toast: React.FC<ToastProps> & {
|
||||||
|
classes: typeof toastClasses
|
||||||
|
} = ({
|
||||||
|
isOpen,
|
||||||
|
title,
|
||||||
|
information,
|
||||||
|
inline = true,
|
||||||
|
buttonText,
|
||||||
|
onButtonClick,
|
||||||
|
onClose,
|
||||||
|
size = 'large',
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const commonProps = useCommonProps(props)
|
||||||
|
const isInlineButtonHidden = !inline || !!information || !buttonText
|
||||||
|
|
||||||
|
// If the toast is not open, do not render anything.
|
||||||
|
if (!isOpen) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...omitCommonProps(props)}
|
||||||
|
className={clsx(
|
||||||
|
commonProps.className,
|
||||||
|
toastClasses.root,
|
||||||
|
toastClasses[size],
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
inline ? toastClasses.inlineContainer : toastClasses.blockContainer
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={clsx(toastClasses.textContainer)}>
|
||||||
|
{!!title && (
|
||||||
|
<Typography className={toastClasses.title} component="div">
|
||||||
|
<ErrorIcon
|
||||||
|
color="primary"
|
||||||
|
className={toastClasses.errorIcon}
|
||||||
|
style={{ width: '16px' }}
|
||||||
|
/>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!!information && (
|
||||||
|
<Typography className={toastClasses.information} component="div">
|
||||||
|
{information}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!inline && !!buttonText && (
|
||||||
|
<Button
|
||||||
|
onClick={onButtonClick}
|
||||||
|
className={clsx(
|
||||||
|
toastClasses.actionButton,
|
||||||
|
toastClasses.blockButton,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{buttonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
toastClasses.inlineButtonContainer,
|
||||||
|
isInlineButtonHidden && toastClasses.hiddenButtonContainer,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Button onClick={onButtonClick} className={toastClasses.actionButton}>
|
||||||
|
{`${isInlineButtonHidden ? '' : buttonText}`}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
onClick={onClose}
|
||||||
|
className={toastClasses.closeButton}
|
||||||
|
size="medium"
|
||||||
|
>
|
||||||
|
<CloseIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toast.classes = toastClasses
|
1
packages/lsd-react/src/components/Toast/index.ts
Normal file
1
packages/lsd-react/src/components/Toast/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './Toast'
|
@ -37,3 +37,4 @@ export * from './components/ModalFooter'
|
|||||||
export * from './components/DateField'
|
export * from './components/DateField'
|
||||||
export * from './components/DatePicker'
|
export * from './components/DatePicker'
|
||||||
export * from './components/Calendar'
|
export * from './components/Calendar'
|
||||||
|
export * from './components/Toast'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user