From c38a18104ff1e46ceaf1e0426c7be41075314f51 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 1 Jan 2025 19:16:56 +0530 Subject: [PATCH] feat: adding the promises support --- packages/components/toast/package.json | 3 +- .../components/toast/src/toast-region.tsx | 4 + packages/components/toast/src/toast.tsx | 31 ++++---- packages/components/toast/src/use-toast.ts | 15 ++++ .../toast/stories/toast.stories.tsx | 76 ++++++++++++++++--- packages/core/theme/src/components/toast.ts | 7 +- packages/utilities/shared-icons/src/index.ts | 1 + .../utilities/shared-icons/src/loading.tsx | 31 ++++++++ pnpm-lock.yaml | 3 + 9 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 packages/utilities/shared-icons/src/loading.tsx diff --git a/packages/components/toast/package.json b/packages/components/toast/package.json index 378a824376..5f88d80e35 100644 --- a/packages/components/toast/package.json +++ b/packages/components/toast/package.json @@ -47,7 +47,8 @@ "@react-aria/toast": "3.0.0-beta.15", "@react-aria/utils": "3.24.1", "@react-aria/interactions": "3.22.5", - "@react-stately/toast": "3.0.0-beta.5" + "@react-stately/toast": "3.0.0-beta.5", + "@react-stately/utils": "3.10.5" }, "devDependencies": { "@nextui-org/system": "workspace:*", diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index e38382527a..d229793402 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -78,6 +78,10 @@ export function ToastRegion({ onTouchStart={handleTouchStart} > {toastQueue.visibleToasts.map((toast: QueuedToast, index) => { + if (disableAnimation && total - index > maxVisibleToasts) { + return null; + } + if (total - index <= 4 || (isHovered && total - index <= maxVisibleToasts + 1)) { return ( ((props, ref) => { liftHeight, initialHeight, frontHeight, + isLoading, } = useToast({ ...props, ref, @@ -70,6 +72,7 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { const customIcon = icon && isValidElement(icon) ? cloneElement(icon, getIconProps()) : null; const IconComponent = iconMap[color] || iconMap.primary; + const loadingIcon = isLoading ? : null; const handleDragEnd = (offsetX: number, offsetY: number) => { const isRight = position.includes("right"); @@ -87,10 +90,24 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { } }; + const positionStyles: Record = { + "right-bottom": "bottom-0 right-0 mx-auto w-max", + "left-bottom": "bottom-0 left-0 mx-auto w-max", + "center-bottom": "bottom-0 left-0 right-0 w-max mx-auto", + "right-top": "top-0 right-0 mx-auto w-max", + "left-top": "top-0 left-0 mx-auto w-max", + "center-top": "top-0 left-0 right-0 w-max mx-auto", + }; + const positionStyle = position ? positionStyles[position] : positionStyles["right-bottom"]; + const multiplier = position.includes("top") ? 1 : -1; + const [drag, setDrag] = useState(false); + const toastContent = (
- {hideIcon ? null : customIcon || } + {hideIcon && !isLoading + ? null + : loadingIcon || customIcon || }
{props.toast.content.title}
{props.toast.content.description}
@@ -111,18 +128,6 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { ); - const positionStyles: Record = { - "right-bottom": "bottom-0 right-0 mx-auto w-max", - "left-bottom": "bottom-0 left-0 mx-auto w-max", - "center-bottom": "bottom-0 left-0 right-0 w-max mx-auto", - "right-top": "top-0 right-0 mx-auto w-max", - "left-top": "top-0 left-0 mx-auto w-max", - "center-top": "top-0 left-0 right-0 w-max mx-auto", - }; - const positionStyle = position ? positionStyles[position] : positionStyles["right-bottom"]; - const multiplier = position.includes("top") ? 1 : -1; - const [drag, setDrag] = useState(false); - return ( <> {disableAnimation ? ( diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 95f6bb5aa1..5d6268ec15 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -30,6 +30,10 @@ export interface ToastProps extends ToastVariantProps { * description of the toast */ description?: string; + /** + * Promise based on which the notification will be sent. + */ + promise?: Promise; /** * Classname or List of classes to change the classNames of the element. * if `className` is passed, it will be added to the base slot. @@ -164,10 +168,20 @@ export function useToast(originalProps: UseToastProps) total = 1, index = 0, heights, + promise: promiseProp, setHeights, ...otherProps } = props; + const [isLoading, setIsLoading] = useState(!!promiseProp); + + useEffect(() => { + if (!promiseProp) return; + promiseProp.finally(() => { + setIsLoading(false); + }); + }, [promiseProp]); + const Component = as || "div"; const icon: ReactNode = props.icon; @@ -326,6 +340,7 @@ export function useToast(originalProps: UseToastProps) liftHeight, frontHeight, initialHeight, + isLoading, }; } diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index d1bbd88991..29d0b849cc 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -35,11 +35,6 @@ export default { type: "boolean", }, }, - disableAnimation: { - control: { - type: "boolean", - }, - }, position: { control: {type: "select"}, options: [ @@ -77,7 +72,7 @@ const defaultProps = { const Template = (args: ToastProps) => { return ( <> - +
+
+ + ); +}; + +const PromiseToastTemplate = (args: ToastProps) => { + return ( + <> + +
+ +
+ + ); +}; + const CustomToastComponent = (args) => { const color = args.color; const colorMap = { @@ -214,12 +252,12 @@ const CustomToastComponent = (args) => { ); }; -const CustomToastTemplate = () => { +const CustomToastTemplate = (args) => { const colors = ["primary", "secondary", "warning", "danger", "success"]; return ( <> - +
{colors.map((color, idx) => ( @@ -270,6 +308,20 @@ export const iconHidden = { }, }; +export const DisableAnimation = { + render: DisableAnimationTemplate, + args: { + ...defaultProps, + }, +}; + +export const PromiseToast = { + render: PromiseToastTemplate, + args: { + ...defaultProps, + }, +}; + export const WithTimeout = { render: TimeoutTemplate, args: { @@ -292,8 +344,8 @@ export const WithEndContent = { }; export const CustomStyles = { + render: CustomToastTemplate, args: { - disableAnimation: true, + ...defaultProps, }, - render: CustomToastTemplate, }; diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 10d539d6fc..9e074bd5e0 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -16,11 +16,10 @@ const toast = tv({ "my-1", "w-[210px] sm:w-[270px] md:w-[300px]", "min-h-4", - "text-white", - "shadow-inner", + "drop-shadow", ], - title: ["font-medium", "text-sm", "me-4"], - description: ["text-sm", "me-4"], + title: ["font-medium", "text-sm", "me-4", "text-foreground"], + description: ["text-sm", "me-4", "text-default-600"], icon: ["w-6 h-6 fill-current"], content: ["flex flex-grow flex-row gap-x-4 items-center relative"], progressTrack: ["absolute h-[2px] left-0 -bottom-2 w-full bg-default-200"], diff --git a/packages/utilities/shared-icons/src/index.ts b/packages/utilities/shared-icons/src/index.ts index 664f7da714..3a07b8aa00 100644 --- a/packages/utilities/shared-icons/src/index.ts +++ b/packages/utilities/shared-icons/src/index.ts @@ -38,6 +38,7 @@ export * from "./info-circle"; export * from "./warning"; export * from "./danger"; export * from "./success"; +export * from "./loading"; // sets export * from "./bulk"; diff --git a/packages/utilities/shared-icons/src/loading.tsx b/packages/utilities/shared-icons/src/loading.tsx new file mode 100644 index 0000000000..4f44f83c86 --- /dev/null +++ b/packages/utilities/shared-icons/src/loading.tsx @@ -0,0 +1,31 @@ +import {IconSvgProps} from "./types"; + +export const LoadingIcon = ( + props: IconSvgProps & { + className?: string; + }, +) => { + return ( + + + + + + ); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa7760ed93..44058ce42e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3020,6 +3020,9 @@ importers: '@react-stately/toast': specifier: 3.0.0-beta.5 version: 3.0.0-beta.5(react@18.2.0) + '@react-stately/utils': + specifier: 3.10.5 + version: 3.10.5(react@18.2.0) devDependencies: '@nextui-org/button': specifier: workspace:*