mirror of
https://github.com/acid-info/lsd.git
synced 2025-01-27 09:15:38 +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 { ModalFooterStyles } from '../ModalFooter/ModalFooter.styles'
|
||||
import { ModalBodyStyles } from '../ModalBody/ModalBody.styles'
|
||||
import { ToastStyles } from '../Toast/Toast.styles'
|
||||
|
||||
const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
|
||||
[
|
||||
@ -80,6 +81,7 @@ const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
|
||||
DatePickerStyles,
|
||||
DateFieldStyles,
|
||||
CalendarStyles,
|
||||
ToastStyles,
|
||||
]
|
||||
|
||||
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/DatePicker'
|
||||
export * from './components/Calendar'
|
||||
export * from './components/Toast'
|
||||
|
Loading…
x
Reference in New Issue
Block a user