@choi-ui/react-toast
Version:
This package provides easy access to toast messages in React applications.
1 lines • 13.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/Toast/Toast.tsx","../src/store/toastStore.ts","../src/components/Toast/Toast.styles.ts","../src/components/Toast/Icon/Close.tsx","../src/components/Toast/ToastContent.tsx","../src/store/action.ts"],"sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Position, ToastType } from '../../types/toast';\nimport { useToastState } from '../../store/toastStore';\n\nimport { Wrapper } from './Toast.styles';\n\nimport ToastContent from './ToastContent';\n\nconst Toast = () => {\n const toasts = useToastState();\n\n const groupByToast = toasts.reduce(\n (acc, toast) => {\n const position = toast.position ?? 'bottom';\n (acc[position] ??= []).push(toast);\n return acc;\n },\n {} as Record<Position, ToastType[]>\n );\n\n return ReactDOM.createPortal(\n <>\n {(Object.keys(groupByToast) as Array<keyof typeof groupByToast>).map(\n (key) => (\n <Wrapper key={key} position={key}>\n {groupByToast[key].map(\n ({\n id,\n message = '',\n type = 'default',\n isClosable = true,\n duration = 3000,\n variants = 'filled',\n position = 'bottom',\n ...rest\n }: ToastType) =>\n React.cloneElement((<ToastContent />) as React.ReactElement, {\n id,\n message,\n type,\n isClosable,\n duration,\n variants,\n position,\n key: id,\n ...rest,\n })\n )}\n </Wrapper>\n )\n )}\n </>,\n document.body\n );\n};\n\nexport default Toast;\n","import { useState, useEffect } from 'react';\nimport { ToastType } from '../types/toast';\nimport { ActionType } from './type';\n\nlet globalToasts: ToastType[] = [];\nlet setGlobalToasts: (toasts: ToastType[]) => void = () => {};\n\nconst reducer = (state: ToastType[], action: ActionType): ToastType[] => {\n switch (action.type) {\n case 'ADD_TOAST':\n return [...state, { ...action.payload }];\n case 'REMOVE_TOAST':\n return state.filter((toast) => toast.id !== action.payload);\n default:\n return state;\n }\n};\n\nexport const dispatch = (action: ActionType) => {\n globalToasts = reducer(globalToasts, action);\n setGlobalToasts(globalToasts);\n};\n\nexport const useToastState = () => {\n const [toasts, setToasts] = useState<ToastType[]>(globalToasts);\n\n useEffect(() => {\n setGlobalToasts = setToasts;\n\n return () => {\n setGlobalToasts = () => {};\n };\n }, []);\n\n return toasts;\n};\n","import { css, keyframes } from '@emotion/react';\nimport styled from '@emotion/styled';\n\nimport { ToastType, Position } from '../../types/toast';\n\nimport ToastCloseIcon from './Icon/Close';\n\nconst topAnimation = keyframes({\n '0%': {\n transform: 'translateY(-120%)',\n },\n '100%': {\n transform: 'translateY(0)',\n },\n});\n\nconst LeftAnimation = keyframes({\n '0%': {\n transform: 'translateX(-120%)',\n },\n '100%': {\n transform: 'translateX(0)',\n },\n});\n\nconst RightAnimation = keyframes({\n '0%': {\n transform: 'translateX(120%)',\n },\n '100%': {\n transform: 'translateX(0)',\n },\n});\n\nconst bottomAnimation = keyframes({\n '0%': {\n transform: 'translateY(120%)',\n },\n '100%': {\n transform: 'translateY(0)',\n },\n});\n\nconst positionAnimation = {\n top: topAnimation,\n 'top-left': LeftAnimation,\n 'top-right': RightAnimation,\n bottom: bottomAnimation,\n 'bottom-left': LeftAnimation,\n 'bottom-right': RightAnimation,\n};\n\nconst toastStyle = {\n type: {\n success: css`\n --main-color: #ffffff;\n --main-background: #55a0ee;\n `,\n warn: css`\n --main-color: #ffffff;\n --main-background: #f1ad0f;\n `,\n error: css`\n --main-color: #ffffff;\n --main-background: #c9162b;\n `,\n default: css`\n --main-color: #ffffff;\n --main-background: #343a40;\n `,\n },\n variants: {\n filled: css`\n color: var(--main-color);\n background: var(--main-background);\n `,\n outlined: css`\n color: var(--main-background);\n background: #fff;\n border: 1px solid var(--main-background);\n `,\n },\n};\n\nexport const StyledToastItem = styled.div<\n Pick<ToastType, 'type' | 'variants' | 'position'>\n>`\n display: flex;\n gap: 16px;\n align-items: center;\n justify-content: space-between;\n\n box-sizing: content-box;\n min-width: 320px;\n max-width: 640px;\n min-height: 24px;\n margin-bottom: 8px;\n padding: 16px;\n\n border-radius: 8px;\n\n ${({ type }) => type && toastStyle.type[type]}\n ${({ variants }) => variants && toastStyle.variants[variants]}\n ${({ position }) =>\n position &&\n css`\n animation: ${positionAnimation[position]} 0.3s forwards;\n `}\n`;\n\nexport const StyledCloseButton = styled.button`\n height: 24px;\n padding: 0;\n background: none;\n border: none;\n`;\n\nexport const StyledModalCloseIcon = styled(ToastCloseIcon)<{\n variant?: string;\n}>`\n ${({ variant }) =>\n variant === 'outlined'\n ? css`\n > path {\n fill: var(--main-background);\n }\n `\n : css`\n > path {\n fill: var(--main-color);\n }\n `}\n`;\n\nconst positionStyle = {\n top: css`\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n `,\n 'top-left': css`\n top: 20px;\n left: 20px;\n `,\n 'top-right': css`\n top: 20px;\n right: 20px;\n `,\n bottom: css`\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n `,\n 'bottom-left': css`\n bottom: 20px;\n left: 20px;\n `,\n 'bottom-right': css`\n right: 20px;\n bottom: 20px;\n `,\n};\n\nexport const Wrapper = styled.div<{ position: Position }>`\n position: fixed;\n z-index: 10000;\n overflow: hidden;\n box-sizing: border-box;\n\n ${({ position }) => positionStyle[position]};\n`;\n","import { SVGProps } from 'react';\n\ntype ToastCloseIconProps = SVGProps<SVGSVGElement>;\n\nconst CloseIcon = (props: ToastCloseIconProps) => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n {...props}\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M7.421 7.42167C7.69437 7.1483 8.13758 7.1483 8.41095 7.42167L16.5776 15.5883C16.851 15.8617 16.851 16.3049 16.5776 16.5783C16.3042 16.8517 15.861 16.8517 15.5877 16.5783L7.421 8.41162C7.14763 8.13825 7.14763 7.69504 7.421 7.42167Z\"\n fill=\"white\"\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M16.5776 7.42167C16.851 7.69504 16.851 8.13825 16.5776 8.41162L8.41095 16.5783C8.13758 16.8517 7.69437 16.8517 7.421 16.5783C7.14763 16.3049 7.14763 15.8617 7.421 15.5883L15.5877 7.42167C15.861 7.1483 16.3042 7.1483 16.5776 7.42167Z\"\n fill=\"white\"\n />\n </svg>\n );\n};\n\nexport default CloseIcon;\n","import React, { useEffect } from 'react';\n\nimport { ToastType } from '../../types/toast';\n\nimport { removeToast } from '../../store/action';\nimport {\n StyledToastItem,\n StyledModalCloseIcon,\n StyledCloseButton,\n} from './Toast.styles';\n\nconst ToastContent = ({\n id,\n message,\n duration,\n isClosable,\n type,\n custom,\n variants,\n position,\n}: ToastType) => {\n useEffect(() => {\n const timer = setTimeout(() => {\n removeToast(String(id));\n }, duration);\n\n return () => clearTimeout(timer);\n }, [id, duration]);\n\n return (\n <StyledToastItem type={type} variants={variants} position={position}>\n {custom?.() ?? (\n <span>\n {message?.split('\\n').map((line, index) => (\n <React.Fragment key={index}>\n {line}\n <br />\n </React.Fragment>\n ))}\n </span>\n )}\n {isClosable && (\n <StyledCloseButton onClick={() => removeToast(String(id))}>\n <StyledModalCloseIcon variant={variants} />\n </StyledCloseButton>\n )}\n </StyledToastItem>\n );\n};\n\nexport default ToastContent;\n","import { v4 as uuid } from 'uuid';\nimport { dispatch } from './toastStore';\nimport { ToastType } from '../types/toast';\n\nexport const addToast = (toast: ToastType) => {\n const id = uuid();\n dispatch({\n type: 'ADD_TOAST',\n payload: { ...toast, id },\n });\n};\n\n// 토스트 제거하는 함수\nexport const removeToast = (id: string) => {\n dispatch({ type: 'REMOVE_TOAST', payload: id });\n};\n"],"mappings":"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","names":["React","ReactDOM","useState","useEffect","globalToasts","setGlobalToasts","reducer","state","action","toast","dispatch","useToastState","toasts","setToasts","css","keyframes","styled","jsx","jsxs","CloseIcon","props","Close_default","topAnimation","keyframes","LeftAnimation","RightAnimation","bottomAnimation","positionAnimation","toastStyle","css","StyledToastItem","styled","type","variants","position","StyledCloseButton","StyledModalCloseIcon","Close_default","variant","positionStyle","Wrapper","React","useEffect","uuid","addToast","toast","id","uuid","dispatch","removeToast","jsx","jsxs","ToastContent","id","message","duration","isClosable","type","custom","variants","position","useEffect","timer","removeToast","StyledToastItem","line","index","React","StyledCloseButton","StyledModalCloseIcon","ToastContent_default","Fragment","jsx","Toast","groupByToast","useToastState","acc","toast","position","ReactDOM","key","Wrapper","id","message","type","isClosable","duration","variants","rest","React","ToastContent_default","Toast_default"]}