From f479b3bda10d4667c53c5081ae855f8ecc15c381 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 25 Dec 2024 12:09:56 +0530 Subject: [PATCH] chore: fixes and adding draft1 of stories --- .../components/toast/src/toast-provider.tsx | 29 +--- .../components/toast/src/toast-region.tsx | 10 +- packages/components/toast/src/toast.tsx | 25 ++- packages/components/toast/src/use-toast.ts | 38 ++--- .../toast/stories/toast.stories.tsx | 158 +++++++++++++++++- packages/core/theme/src/components/toast.ts | 36 +++- .../utilities/shared-icons/src/danger.tsx | 1 + .../shared-icons/src/info-filled.tsx | 31 ++-- .../utilities/shared-icons/src/warning.tsx | 1 + 9 files changed, 254 insertions(+), 75 deletions(-) diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx index 1274fb234c..859c093a1a 100644 --- a/packages/components/toast/src/toast-provider.tsx +++ b/packages/components/toast/src/toast-provider.tsx @@ -1,10 +1,9 @@ import {ToastOptions, ToastQueue, useToastQueue} from "@react-stately/toast"; -import {ToastVariantProps} from "@nextui-org/theme"; import {ToastRegion} from "./toast-region"; -import {ToastType} from "./use-toast"; +import {ToastProps} from "./use-toast"; -let globalToastQueue: ToastQueue | null = null; +let globalToastQueue: ToastQueue | null = null; interface ToastProviderProps { maxVisibleToasts?: number; @@ -30,31 +29,15 @@ export const ToastProvider = ({maxVisibleToasts = 5}: ToastProviderProps) => { return ; }; -export const addToast = ({ - title, - description, - priority, - timeout, - ...config -}: { - title: string; - description: string; -} & ToastOptions & - ToastVariantProps) => { +export const addToast = ({...props}: ToastProps & ToastOptions) => { if (!globalToastQueue) { return; } - const content: ToastType = { - title, - description, - config: config, - }; - const options: Partial = { - timeout, - priority, + timeout: props?.timeout, + priority: props?.priority, }; - globalToastQueue.add(content, options); + globalToastQueue.add(props, options); }; diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index dc1bd40682..8f585c2cf4 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -3,13 +3,13 @@ import {useToastRegion, AriaToastRegionProps} from "@react-aria/toast"; import {QueuedToast, ToastState} from "@react-stately/toast"; import Toast from "./toast"; -import {ToastType} from "./use-toast"; +import {ToastProps} from "./use-toast"; interface ToastRegionProps extends AriaToastRegionProps { toastQueue: ToastState; } -export function ToastRegion({toastQueue, ...props}: ToastRegionProps) { +export function ToastRegion({toastQueue, ...props}: ToastRegionProps) { const ref = useRef(null); const {regionProps} = useToastRegion(props, toastQueue, ref); @@ -20,10 +20,8 @@ export function ToastRegion({toastQueue, ...props}: ToastRe ref={ref} className="fixed bottom-6 right-6 w-screen flex flex-col items-end justify-center" > - {toastQueue.visibleToasts.map((toast: QueuedToast) => { - return ( - - ); + {toastQueue.visibleToasts.map((toast: QueuedToast) => { + return ; })} diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index 54ace7c3ef..a64477d34a 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -1,20 +1,36 @@ import {forwardRef} from "@nextui-org/system"; import {Button, ButtonProps} from "@nextui-org/button"; -import {CloseIcon} from "@nextui-org/shared-icons"; +import { + CloseIcon, + DangerIcon, + InfoFilledIcon, + SuccessIcon, + WarningIcon, +} from "@nextui-org/shared-icons"; import {motion, AnimatePresence} from "framer-motion"; import {Progress} from "@nextui-org/progress"; +import {cloneElement, isValidElement} from "react"; import {UseToastProps, useToast} from "./use-toast"; export interface ToastProps extends UseToastProps {} +const iconMap = { + primary: InfoFilledIcon, + secondary: InfoFilledIcon, + success: SuccessIcon, + warning: WarningIcon, + danger: DangerIcon, +} as const; + const Toast = forwardRef<"div", ToastProps>((props, ref) => { const { Component, - Icon, + icon, domRef, endContent, closeProgressBarValue, + color, getToastProps, getContentProps, getTitleProps, @@ -33,6 +49,9 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { exit: {opacity: 0, y: 50}, }; + const customIcon = icon && isValidElement(icon) ? cloneElement(icon, getIconProps()) : null; + const IconComponent = iconMap[color] || iconMap.primary; + return ( ((props, ref) => { >
- + {customIcon || }
{props.toast.content.title}
{props.toast.content.description}
diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 6658846763..d0d182f5da 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -8,33 +8,26 @@ import {ReactNode, useCallback, useEffect, useMemo, useState} from "react"; import {useToast as useToastAria, AriaToastProps} from "@react-aria/toast"; import {mergeProps} from "@react-aria/utils"; import {QueuedToast, ToastState} from "@react-stately/toast"; -import {InfoFilledIcon} from "@nextui-org/shared-icons"; - -export type ToastType = { - title: string; - description: string; - config: ToastVariantProps; -}; - -interface Props extends HTMLNextUIProps<"div"> { - /** - * Ref to the DOM node. - */ + +export interface ToastProps extends ToastVariantProps { ref?: ReactRef; - toast: QueuedToast; - state: ToastState; + title?: string; + description?: string; classNames?: SlotsToClasses; - /** - * Content to be displayed in the end side of the alert - */ endContent?: ReactNode; + icon?: ReactNode; +} + +interface Props extends HTMLNextUIProps<"div">, ToastProps { + toast: QueuedToast; + state: ToastState; } -export type UseToastProps = Props & +export type UseToastProps = Props & ToastVariantProps & Omit, "div">; -export function useToast(originalProps: UseToastProps) { +export function useToast(originalProps: UseToastProps) { const [props, variantProps] = mapPropsVariants(originalProps, toastTheme.variantKeys); const [closeProgressBarValue, setCloseProgressBarValue] = useState(0); @@ -56,7 +49,7 @@ export function useToast(originalProps: UseToastProps) { const {ref, as, className, classNames, toast, endContent, ...otherProps} = props; const Component = as || "div"; - let Icon = InfoFilledIcon; + const icon: ReactNode = props.icon; const domRef = useDOMRef(ref); const baseStyles = clsx(className, classNames?.base); @@ -108,7 +101,7 @@ export function useToast(originalProps: UseToastProps) { const getIconProps: PropGetter = useCallback( (props = {}) => ({ - className: slots.content({class: classNames?.icon}), + className: slots.icon({class: classNames?.icon}), ...props, }), [], @@ -166,11 +159,12 @@ export function useToast(originalProps: UseToastProps) { return { Component, - Icon, + icon, styles, domRef, classNames, closeProgressBarValue, + color: variantProps["color"], getToastProps, getTitleProps, getContentProps, diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 9650527b40..fdad171e01 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -1,6 +1,6 @@ import React from "react"; import {Meta} from "@storybook/react"; -import {toast} from "@nextui-org/theme"; +import {cn, toast} from "@nextui-org/theme"; import {Button} from "@nextui-org/button"; import {Toast, ToastProps, ToastProvider, addToast} from "../src"; @@ -43,7 +43,7 @@ const Template = (args: ToastProps) => ( + + ); +}; + +const WithEndContentTemplate = (args) => { + return ( + <> + + + ), + color: "warning", + variant: "faded", + ...args, + }); + }} + > + Toast + + + ); +}; + +const CustomToastComponent = (args) => { + const color = args.color; + const colorMap = { + primary: "before:bg-primary border-primary-200 dark:border-primary-100", + secondary: "before:bg-secondary border-secondary-200 dark:border-secondary-100", + success: "before:bg-success border-success-200 dark:border-success-100", + warning: "before:bg-warning border-warning-200 dark:border-warning-100", + danger: "before:bg-danger border-danger-200 dark:border-danger-100", + }; + + return ( + <> + + +
+ ), + color: color, + }); + }} + > + Toast + + + ); +}; + +const CustomToastTemplate = () => { + const colors = ["primary", "secondary", "warning", "danger", "success"]; + + return ( + <> + +
+ {colors.map((color, idx) => ( + + ))} +
+ + ); +}; + export const Default = { render: Template, args: { @@ -61,10 +175,46 @@ export const Default = { }, }; -export const WithTimeout = { +export const WithIcon = { render: Template, args: { ...defaultProps, - timeout: 3000, + title: "Custom Icon", + icon: ( + + + + + + + ), + }, +}; + +export const WithTimeout = { + render: TimeoutTemplate, + args: { + ...defaultProps, + }, +}; + +export const WithEndContent = { + render: WithEndContentTemplate, + args: { + ...defaultProps, }, }; + +export const CustomTemplate = { + render: CustomToastTemplate, +}; diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 4a619ce408..11f5160a67 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -15,8 +15,7 @@ const toast = tv({ "justify-center", ], base: [ - "flex", - "flex-col", + "flex gap-x-4 items-center", "relative", "bg-white", "z-50", @@ -32,7 +31,7 @@ const toast = tv({ "text-white", "shadow-inner", ], - icon: ["w-6 h-6"], + icon: ["w-6 h-6 fill-current"], content: ["flex flex-grow flex-row gap-x-1 items-center"], title: ["font-medium", "ms-4"], description: ["font-light", "ms-4"], @@ -53,7 +52,15 @@ const toast = tv({ }, variants: { size: { - xs: "", + sm: { + icon: "w-4 h-4", + }, + md: { + icon: "w-6 h-6", + }, + lg: { + icon: "w-8 h-8", + }, }, variant: { flat: "bg-default", @@ -79,11 +86,28 @@ const toast = tv({ progressTrack: "bg-danger-200", }, }, - position: {}, + radius: { + none: { + base: "rounded-none", + }, + sm: { + base: "rounded-small", + }, + md: { + base: "rounded-medium", + }, + lg: { + base: "rounded-large", + }, + full: { + base: "rounded-full", + }, + }, }, defaultVariants: { - size: "xs", + size: "sm", variant: "flat", + radius: "none", }, compoundVariants: [ // flat and color diff --git a/packages/utilities/shared-icons/src/danger.tsx b/packages/utilities/shared-icons/src/danger.tsx index ffa5c56f6d..d5cd7f3259 100644 --- a/packages/utilities/shared-icons/src/danger.tsx +++ b/packages/utilities/shared-icons/src/danger.tsx @@ -7,6 +7,7 @@ export const DangerIcon = ( ) => { return ( ( - - - -); +import {IconSvgProps} from "./types"; + +export const InfoFilledIcon = ( + props: IconSvgProps & { + className?: string; + }, +) => { + return ( + + + + ); +}; diff --git a/packages/utilities/shared-icons/src/warning.tsx b/packages/utilities/shared-icons/src/warning.tsx index fd4d4d3133..69bd9c02de 100644 --- a/packages/utilities/shared-icons/src/warning.tsx +++ b/packages/utilities/shared-icons/src/warning.tsx @@ -7,6 +7,7 @@ export const WarningIcon = ( ) => { return (