From 976c903a70c99d5657243c2897d26a106161cd73 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Sat, 21 Dec 2024 16:11:35 +0530 Subject: [PATCH 01/49] feat: initial commit --- packages/components/toast/README.md | 24 ++ packages/components/toast/package.json | 60 +++++ packages/components/toast/src/index.ts | 13 + .../components/toast/src/toast-provider.tsx | 60 +++++ .../components/toast/src/toast-region.tsx | 31 +++ packages/components/toast/src/toast.tsx | 54 ++++ packages/components/toast/src/use-toast.ts | 185 +++++++++++++ .../toast/stories/toast.stories.tsx | 64 +++++ packages/components/toast/tsconfig.json | 10 + packages/components/toast/tsup.config.ts | 8 + packages/core/theme/src/components/index.ts | 1 + packages/core/theme/src/components/toast.ts | 246 ++++++++++++++++++ packages/utilities/shared-icons/src/close.tsx | 1 + packages/utilities/shared-icons/src/index.ts | 1 + .../shared-icons/src/info-filled.tsx | 11 + pnpm-lock.yaml | 114 ++++++++ 16 files changed, 883 insertions(+) create mode 100644 packages/components/toast/README.md create mode 100644 packages/components/toast/package.json create mode 100644 packages/components/toast/src/index.ts create mode 100644 packages/components/toast/src/toast-provider.tsx create mode 100644 packages/components/toast/src/toast-region.tsx create mode 100644 packages/components/toast/src/toast.tsx create mode 100644 packages/components/toast/src/use-toast.ts create mode 100644 packages/components/toast/stories/toast.stories.tsx create mode 100644 packages/components/toast/tsconfig.json create mode 100644 packages/components/toast/tsup.config.ts create mode 100644 packages/core/theme/src/components/toast.ts create mode 100644 packages/utilities/shared-icons/src/info-filled.tsx diff --git a/packages/components/toast/README.md b/packages/components/toast/README.md new file mode 100644 index 0000000000..4e348bc039 --- /dev/null +++ b/packages/components/toast/README.md @@ -0,0 +1,24 @@ +# @nextui-org/toast + +Toast Component helps to provide feedback on user-actions. + +> This is an internal utility, not intended for public usage. + +## Installation + +```sh +yarn add @nextui-org/toast +# or +npm i @nextui-org/toast +``` + +## Contribution + +Yes please! See the +[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md) +for details. + +## License + +This project is licensed under the terms of the +[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE). diff --git a/packages/components/toast/package.json b/packages/components/toast/package.json new file mode 100644 index 0000000000..2b86beb11c --- /dev/null +++ b/packages/components/toast/package.json @@ -0,0 +1,60 @@ +{ + "name": "@nextui-org/toast", + "version": "2.0.0", + "description": "adding toast", + "keywords": [ + "toast" + ], + "author": "Junior Garcia ", + "homepage": "https://nextui.org", + "license": "MIT", + "main": "src/index.ts", + "sideEffects": false, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nextui-org/nextui.git", + "directory": "packages/components/toast" + }, + "bugs": { + "url": "https://github.com/nextui-org/nextui/issues" + }, + "scripts": { + "build": "tsup src --dts", + "build:fast": "tsup src", + "dev": "pnpm build:fast --watch", + "clean": "rimraf dist .turbo", + "typecheck": "tsc --noEmit", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.0.0", + "react": ">=18", + "react-dom": ">=18" + }, + "dependencies": { + "@nextui-org/react-utils": "workspace:*", + "@nextui-org/shared-utils": "workspace:*", + "@nextui-org/shared-icons": "workspace:*", + "@react-aria/button": "3.9.5", + "@react-aria/toast": "3.0.0-beta.15", + "@react-aria/utils": "3.24.1", + "@react-stately/toast": "3.0.0-beta.5" + }, + "devDependencies": { + "@nextui-org/system": "workspace:*", + "@nextui-org/theme": "workspace:*", + "@nextui-org/button": "workspace:*", + "clean-package": "2.2.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "clean-package": "../../../clean-package.config.json" +} diff --git a/packages/components/toast/src/index.ts b/packages/components/toast/src/index.ts new file mode 100644 index 0000000000..a602590488 --- /dev/null +++ b/packages/components/toast/src/index.ts @@ -0,0 +1,13 @@ +import Toast from "./toast"; +import {ToastProvider} from "./toast-provider"; + +// export types +export type {ToastProps} from "./toast"; + +// export hooks +export {useToast} from "./use-toast"; +export {addToast} from "./toast-provider"; + +// export component +export {Toast}; +export {ToastProvider}; diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx new file mode 100644 index 0000000000..e50151f3cb --- /dev/null +++ b/packages/components/toast/src/toast-provider.tsx @@ -0,0 +1,60 @@ +import {ToastOptions, ToastQueue, useToastQueue} from "@react-stately/toast"; +import {ToastVariantProps} from "@nextui-org/theme"; + +import {ToastRegion} from "./toast-region"; +import {ToastType} from "./use-toast"; + +let globalToastQueue: ToastQueue | null = null; + +interface ToastProviderProps { + maxVisibleToasts?: number; +} + +export const getToastQueue = (maxVisibleToasts: number) => { + if (!globalToastQueue) { + globalToastQueue = new ToastQueue({ + maxVisibleToasts, + }); + } + + return globalToastQueue; +}; + +export const ToastProvider = ({maxVisibleToasts = 5}: ToastProviderProps) => { + const toastQueue = useToastQueue(getToastQueue(maxVisibleToasts)); + + if (toastQueue.visibleToasts.length == 0) { + return null; + } + + return <>{}; +}; + +export const addToast = ({ + title, + description, + priority, + timeout, + ...config +}: { + title: string; + description: string; +} & ToastOptions & + ToastVariantProps) => { + if (!globalToastQueue) { + return; + } + + const content: ToastType = { + title, + description, + config: config, + }; + + const options: Partial = { + timeout, + priority, + }; + + globalToastQueue.add(content, options); +}; diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx new file mode 100644 index 0000000000..69b4635b5c --- /dev/null +++ b/packages/components/toast/src/toast-region.tsx @@ -0,0 +1,31 @@ +import {useRef} from "react"; +import {useToastRegion, AriaToastRegionProps} from "@react-aria/toast"; +import {QueuedToast, ToastState} from "@react-stately/toast"; + +import Toast from "./toast"; +import {ToastType} from "./use-toast"; + +interface ToastRegionProps extends AriaToastRegionProps { + toastQueue: ToastState; +} + +export function ToastRegion({toastQueue, ...props}: ToastRegionProps) { + const ref = useRef(null); + const {regionProps} = useToastRegion(props, toastQueue, ref); + + return ( + <> +
+ {toastQueue.visibleToasts.map((toast: QueuedToast) => { + return ( + + ); + })} +
+ + ); +} diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx new file mode 100644 index 0000000000..ca21196436 --- /dev/null +++ b/packages/components/toast/src/toast.tsx @@ -0,0 +1,54 @@ +import {forwardRef} from "@nextui-org/system"; +import {Button, ButtonProps} from "@nextui-org/button"; +import {CloseIcon} from "@nextui-org/shared-icons"; + +import {Progress} from "../../../core/react/src"; + +import {UseToastProps, useToast} from "./use-toast"; + +export interface ToastProps extends UseToastProps {} + +const Toast = forwardRef<"div", ToastProps>((props, ref) => { + const { + Component, + Icon, + domRef, + endContent, + closeProgressBarValue, + getToastProps, + getContentProps, + getTitleProps, + getDescriptionProps, + getProgressBarProps, + getCloseButtonProps, + getIconProps, + } = useToast({ + ...props, + ref, + }); + + return ( + +
+ +
+
{props.toast.content.title}
+
{props.toast.content.description}
+
+
+ + {endContent} + +
+ ); +}); + +Toast.displayName = "NextUI.Toast"; + +export default Toast; diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts new file mode 100644 index 0000000000..bddd0af822 --- /dev/null +++ b/packages/components/toast/src/use-toast.ts @@ -0,0 +1,185 @@ +import type {SlotsToClasses, ToastSlots, ToastVariantProps} from "@nextui-org/theme"; + +import {HTMLNextUIProps, PropGetter, mapPropsVariants} from "@nextui-org/system"; +import {toast as toastTheme} from "@nextui-org/theme"; +import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; +import {clsx, objectToDeps} from "@nextui-org/shared-utils"; +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. + */ + ref?: ReactRef; + toast: QueuedToast; + state: ToastState; + classNames?: SlotsToClasses; + /** + * Content to be displayed in the end side of the alert + */ + endContent?: ReactNode; +} + +export type UseToastProps = Props & + ToastVariantProps & + Omit, "div">; + +export function useToast(originalProps: UseToastProps) { + const [props, variantProps] = mapPropsVariants(originalProps, toastTheme.variantKeys); + + const [closeProgressBarValue, setCloseProgressBarValue] = useState(0); + const [isToastClicked, setIsToastClicked] = useState(false); + + useEffect(() => { + const interval = setInterval(async () => { + if (isToastClicked) { + return; + } + setCloseProgressBarValue(closeProgressBarValue + 10); + }, Number(props.toast.timeout) / 20); + + return () => { + clearInterval(interval); + }; + }); + + const {ref, as, className, classNames, toast, endContent, ...otherProps} = props; + + const Component = as || "div"; + let Icon = InfoFilledIcon; + + const domRef = useDOMRef(ref); + const baseStyles = clsx(className, classNames?.base); + const {toastProps, contentProps, titleProps, descriptionProps, closeButtonProps} = useToastAria( + props, + props.state, + domRef, + ); + + const styles = useMemo( + () => + toastTheme({ + ...variantProps, + className, + }), + [objectToDeps(variantProps), className], + ); + + const slots = useMemo( + () => + toastTheme({ + ...variantProps, + }), + [objectToDeps(variantProps)], + ); + + const getToastProps: PropGetter = useCallback( + (props = {}) => ({ + ref: domRef, + className: slots.base({class: clsx(baseStyles, classNames?.base)}), + onMouseDown: () => { + if (!toast.timer) { + return; + } + setIsToastClicked(true); + toast.timer.pause(); + }, + onMouseUp: () => { + if (!toast.timer) { + return; + } + setIsToastClicked(false); + toast.timer.resume(); + }, + ...mergeProps(props, otherProps, toastProps), + }), + [slots, classNames, toastProps], + ); + + const getIconProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.content({class: classNames?.icon}), + ...props, + }), + [], + ); + + const getContentProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.content({class: classNames?.content}), + ...mergeProps(props, otherProps, contentProps), + }), + [contentProps], + ); + + const getTitleProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.title({class: classNames?.title}), + ...mergeProps(props, otherProps, titleProps), + }), + [titleProps], + ); + + const getDescriptionProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.description({class: classNames?.description}), + ...mergeProps(props, otherProps, descriptionProps), + }), + [descriptionProps], + ); + + const getCloseButtonProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.closeButton({class: classNames?.closeButton}), + ...mergeProps(props, otherProps, closeButtonProps), + }), + [closeButtonProps], + ); + + const isProgressBarHidden = toast.timeout ? "block" : "hidden"; + const progressBarProps = { + classNames: { + track: "bg-default-200", + indicator: "bg-default-700/40", + }, + radius: "none", + isDisabled: true, + }; + + const getProgressBarProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.progressBar({class: clsx(isProgressBarHidden, classNames?.progressBar)}), + ...mergeProps(props, otherProps, progressBarProps), + }), + [], + ); + + return { + Component, + Icon, + styles, + domRef, + classNames, + closeProgressBarValue, + getToastProps, + getTitleProps, + getContentProps, + getDescriptionProps, + getProgressBarProps, + getCloseButtonProps, + getIconProps, + endContent, + }; +} + +export type UseToastReturn = ReturnType; diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx new file mode 100644 index 0000000000..95305d7d05 --- /dev/null +++ b/packages/components/toast/stories/toast.stories.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import {Meta} from "@storybook/react"; +import {toast} from "@nextui-org/theme"; +import {Button} from "@nextui-org/button"; + +import {Toast, ToastProps, ToastProvider, addToast} from "../src"; + +export default { + title: "Components/Toast", + component: Toast, + argTypes: { + variant: { + control: {type: "select"}, + options: ["faded", "flat", "bordered", "solid"], + }, + color: { + control: {type: "select"}, + options: ["default", "primary", "secondary", "success", "warning", "danger"], + }, + radius: { + control: {type: "select"}, + options: ["none", "sm", "md", "lg", "full"], + }, + size: { + control: {type: "select"}, + options: ["sm", "md", "lg"], + }, + isDisabled: { + control: { + type: "boolean", + }, + }, + }, +} as Meta; + +const defaultProps = { + ...toast.defaultVariants, +}; + +const Template = (args: ToastProps) => ( + <> + + + +); + +export const Default = { + render: Template, + args: { + ...defaultProps, + variant: "bordered", + color: "danger", + }, +}; diff --git a/packages/components/toast/tsconfig.json b/packages/components/toast/tsconfig.json new file mode 100644 index 0000000000..5d012f6e61 --- /dev/null +++ b/packages/components/toast/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "tailwind-variants": ["../../../node_modules/tailwind-variants"] + }, + }, + "include": ["src", "index.ts"] +} diff --git a/packages/components/toast/tsup.config.ts b/packages/components/toast/tsup.config.ts new file mode 100644 index 0000000000..3e2bcff6cc --- /dev/null +++ b/packages/components/toast/tsup.config.ts @@ -0,0 +1,8 @@ +import {defineConfig} from "tsup"; + +export default defineConfig({ + clean: true, + target: "es2019", + format: ["cjs", "esm"], + banner: {js: '"use client";'}, +}); diff --git a/packages/core/theme/src/components/index.ts b/packages/core/theme/src/components/index.ts index dee45f4401..68832da61e 100644 --- a/packages/core/theme/src/components/index.ts +++ b/packages/core/theme/src/components/index.ts @@ -41,3 +41,4 @@ export * from "./date-picker"; export * from "./alert"; export * from "./drawer"; export * from "./form"; +export * from "./toast"; diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts new file mode 100644 index 0000000000..e79096739b --- /dev/null +++ b/packages/core/theme/src/components/toast.ts @@ -0,0 +1,246 @@ +import type {VariantProps} from "tailwind-variants"; + +import {tv} from "../utils/tv"; + +const toast = tv({ + slots: { + wrapper: [ + "flex", + "w-screen", + "min-h-10", + "fixed", + "inset-0", + "z-50", + "overflow-x-auto", + "justify-center", + ], + base: [ + "flex", + "flex-col", + "relative", + "bg-white", + "z-50", + "w-full", + "box-border", + "outline-none", + "p-2 px-4 mx-1", + "my-1", + "sm:mx-4", + "sm:my-4", + "max-w-[542px]", + "rounded-md", + "text-white", + "shadow-inner", + ], + icon: ["w-6 h-6"], + content: ["flex flex-grow flex-row gap-x-1 items-center"], + title: ["font-medium", "ms-4"], + description: ["font-light", "ms-4"], + progressBar: [ + "absolute", + "h-[2px]", + "right-0", + "bottom-0", + "w-full", + "overflow-hidden", + "bg-black-500", + "rounded-none", + ], + closeButton: [ + "w-4 h-4 min-w-4 p-0.5 absolute -right-1 -top-1 flex items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", + ], + }, + variants: { + size: { + xs: "", + }, + variant: { + flat: "bg-default", + faded: "bg-default border border-1 border-default-400", + solid: "bg-default shadow-inner", + bordered: "bg-white dark:bg-black border border-1 border-default-400", + }, + color: { + default: "", + primary: "", + secondary: "", + success: "", + warning: "", + danger: "", + }, + }, + defaultVariants: { + size: "xs", + variant: "flat", + }, + compoundVariants: [ + // flat and color + { + variant: "flat", + color: "primary", + class: { + base: "bg-primary-100/40 text-primary-400", + }, + }, + { + variant: "flat", + color: "secondary", + class: { + base: "bg-secondary-100/40 text-secondary-400", + }, + }, + { + variant: "faded", + color: "success", + class: { + base: "bg-success-100/40 text-success-400", + }, + }, + { + variant: "faded", + color: "warning", + class: { + base: "bg-warning-100/40 text-warning-400", + }, + }, + { + variant: "faded", + color: "danger", + class: { + base: "bg-danger-100/40 text-danger-400", + }, + }, + // faded and color + { + variant: "faded", + color: "primary", + class: { + base: "bg-primary-100/40 text-primary-400 border-primary-400", + closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + }, + }, + { + variant: "faded", + color: "secondary", + class: { + base: "bg-secondary-100/40 text-secondary-400 border-secondary-400", + closeButton: + "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + }, + }, + { + variant: "faded", + color: "success", + class: { + base: "bg-success-100/40 text-success-400 border-success-400", + closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + }, + }, + { + variant: "faded", + color: "warning", + class: { + base: "bg-warning-100/40 text-warning-400 border-warning-400", + closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + }, + }, + { + variant: "faded", + color: "danger", + class: { + base: "bg-danger-100/40 text-danger-400 border-danger-400", + closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + }, + }, + // bordered and color + { + variant: "bordered", + color: "primary", + class: { + base: "border-primary-400 text-primary-400", + closeButton: + "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + }, + }, + { + variant: "bordered", + color: "secondary", + class: { + base: "border-secondary-400 text-secondary-400", + closeButton: + "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + }, + }, + { + variant: "bordered", + color: "success", + class: { + base: "border-success-400 text-success-400", + closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + }, + }, + { + variant: "bordered", + color: "warning", + class: { + base: "border-warning-400 text-warning-400", + closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + }, + }, + { + variant: "bordered", + color: "danger", + class: { + base: "border-danger-400 text-danger-400", + closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + }, + }, + // solid and color + { + variant: "solid", + color: "primary", + class: { + base: "bg-primary-100 text-default-600", + closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + }, + }, + { + variant: "solid", + color: "secondary", + class: { + base: "bg-secondary-100 text-default-600", + closeButton: + "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + }, + }, + { + variant: "solid", + color: "success", + class: { + base: "bg-success-100 text-default-600", + closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + }, + }, + { + variant: "solid", + color: "warning", + class: { + base: "bg-warning-100 text-default-600", + closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + }, + }, + { + variant: "solid", + color: "danger", + class: { + base: "bg-danger-100 text-default-600", + closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + }, + }, + ], +}); + +export type ToastVariantProps = VariantProps; +export type ToastSlots = keyof ReturnType; + +export {toast}; diff --git a/packages/utilities/shared-icons/src/close.tsx b/packages/utilities/shared-icons/src/close.tsx index 13ef5c2b00..51681d6e2b 100644 --- a/packages/utilities/shared-icons/src/close.tsx +++ b/packages/utilities/shared-icons/src/close.tsx @@ -17,6 +17,7 @@ export const CloseIcon = ( return (
-
{props.toast.content.title}
-
{props.toast.content.description}
-
- - - {endContent} - - + + + +
+ +
+
{props.toast.content.title}
+
{props.toast.content.description}
+
+
+ + {endContent} + +
+
+
); }); From 3c602443f7f620fc2040ec4e33783d124a3d6ad8 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Tue, 24 Dec 2024 18:21:57 +0530 Subject: [PATCH 03/49] chore: nits --- packages/components/toast/package.json | 1 + .../components/toast/src/toast-provider.tsx | 2 +- .../components/toast/src/toast-region.tsx | 2 +- packages/components/toast/src/toast.tsx | 3 +- packages/components/toast/src/use-toast.ts | 4 +- .../toast/stories/toast.stories.tsx | 10 ++++- packages/core/theme/src/components/toast.ts | 39 +++++++++++++------ pnpm-lock.yaml | 3 ++ 8 files changed, 45 insertions(+), 19 deletions(-) diff --git a/packages/components/toast/package.json b/packages/components/toast/package.json index 2b86beb11c..f4d1ccd6ff 100644 --- a/packages/components/toast/package.json +++ b/packages/components/toast/package.json @@ -43,6 +43,7 @@ "@nextui-org/react-utils": "workspace:*", "@nextui-org/shared-utils": "workspace:*", "@nextui-org/shared-icons": "workspace:*", + "@nextui-org/progress": "workspace:*", "@react-aria/button": "3.9.5", "@react-aria/toast": "3.0.0-beta.15", "@react-aria/utils": "3.24.1", diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx index e50151f3cb..1274fb234c 100644 --- a/packages/components/toast/src/toast-provider.tsx +++ b/packages/components/toast/src/toast-provider.tsx @@ -27,7 +27,7 @@ export const ToastProvider = ({maxVisibleToasts = 5}: ToastProviderProps) => { return null; } - return <>{}; + return ; }; export const addToast = ({ diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index 69b4635b5c..dc1bd40682 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -18,7 +18,7 @@ export function ToastRegion({toastQueue, ...props}: ToastRe
{toastQueue.visibleToasts.map((toast: QueuedToast) => { return ( diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index cdb7acfea8..54ace7c3ef 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -2,8 +2,7 @@ import {forwardRef} from "@nextui-org/system"; import {Button, ButtonProps} from "@nextui-org/button"; import {CloseIcon} from "@nextui-org/shared-icons"; import {motion, AnimatePresence} from "framer-motion"; - -import {Progress} from "../../../core/react/src"; +import {Progress} from "@nextui-org/progress"; import {UseToastProps, useToast} from "./use-toast"; diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index bddd0af822..6658846763 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -149,8 +149,8 @@ export function useToast(originalProps: UseToastProps) { const isProgressBarHidden = toast.timeout ? "block" : "hidden"; const progressBarProps = { classNames: { - track: "bg-default-200", - indicator: "bg-default-700/40", + track: slots.progressTrack({class: clsx(classNames?.progressTrack)}), + indicator: "bg-default-600", }, radius: "none", isDisabled: true, diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 95305d7d05..9650527b40 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -58,7 +58,13 @@ export const Default = { render: Template, args: { ...defaultProps, - variant: "bordered", - color: "danger", + }, +}; + +export const WithTimeout = { + render: Template, + args: { + ...defaultProps, + timeout: 3000, }, }; diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index e79096739b..4a619ce408 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -43,9 +43,10 @@ const toast = tv({ "bottom-0", "w-full", "overflow-hidden", - "bg-black-500", + "bg-green-500", "rounded-none", ], + progressTrack: ["bg-default-200"], closeButton: [ "w-4 h-4 min-w-4 p-0.5 absolute -right-1 -top-1 flex items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", ], @@ -62,12 +63,23 @@ const toast = tv({ }, color: { default: "", - primary: "", - secondary: "", - success: "", - warning: "", - danger: "", + primary: { + progressTrack: "bg-primary-200", + }, + secondary: { + progressTrack: "bg-secondary-200", + }, + success: { + progressTrack: "bg-success-200", + }, + warning: { + progressTrack: "bg-warning-200", + }, + danger: { + progressTrack: "bg-danger-200", + }, }, + position: {}, }, defaultVariants: { size: "xs", @@ -80,6 +92,7 @@ const toast = tv({ color: "primary", class: { base: "bg-primary-100/40 text-primary-400", + closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", }, }, { @@ -87,27 +100,32 @@ const toast = tv({ color: "secondary", class: { base: "bg-secondary-100/40 text-secondary-400", + closeButton: + "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", }, }, { - variant: "faded", + variant: "flat", color: "success", class: { base: "bg-success-100/40 text-success-400", + closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", }, }, { - variant: "faded", + variant: "flat", color: "warning", class: { base: "bg-warning-100/40 text-warning-400", + closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", }, }, { - variant: "faded", + variant: "flat", color: "danger", class: { base: "bg-danger-100/40 text-danger-400", + closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", }, }, // faded and color @@ -158,8 +176,7 @@ const toast = tv({ color: "primary", class: { base: "border-primary-400 text-primary-400", - closeButton: - "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", }, }, { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d67f7d374..25ae47b742 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2999,6 +2999,9 @@ importers: packages/components/toast: dependencies: + '@nextui-org/progress': + specifier: workspace:* + version: link:../progress '@nextui-org/react-utils': specifier: workspace:* version: link:../../utilities/react-utils From ff91ad101715099955ce075c77f9a0ddc8850de6 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 25 Dec 2024 12:09:56 +0530 Subject: [PATCH 04/49] 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 ( Date: Thu, 26 Dec 2024 14:39:04 +0530 Subject: [PATCH 05/49] chore: adding the docs draft --- .changeset/shaggy-beers-breathe.md | 7 + apps/docs/app/examples/toast/color/page.tsx | 31 +++ .../app/examples/toast/custom-icon/page.tsx | 39 +++ .../app/examples/toast/custom-style/page.tsx | 57 ++++ .../app/examples/toast/hidden-icon/page.tsx | 22 ++ .../docs/app/examples/toast/position/page.tsx | 24 ++ apps/docs/app/examples/toast/radius/page.tsx | 31 +++ apps/docs/app/examples/toast/usage/page.tsx | 21 ++ apps/docs/app/examples/toast/variant/page.tsx | 30 ++ .../app/examples/toast/with-action/page.tsx | 28 ++ apps/docs/config/routes.json | 2 +- .../content/components/toast/color.raw.jsx | 30 ++ apps/docs/content/components/toast/color.ts | 9 + .../components/toast/custom-icon.raw.jsx | 38 +++ .../content/components/toast/custom-icon.ts | 9 + .../components/toast/custom-styles.raw.jsx | 55 ++++ .../content/components/toast/custom-styles.ts | 9 + .../components/toast/hidden-icon.raw.jsx | 23 ++ .../content/components/toast/hidden-icon.ts | 9 + apps/docs/content/components/toast/index.ts | 17 ++ .../content/components/toast/position.raw.jsx | 35 +++ .../docs/content/components/toast/position.ts | 9 + .../content/components/toast/radius.raw.jsx | 29 ++ apps/docs/content/components/toast/radius.ts | 9 + .../content/components/toast/usage.raw.jsx | 19 ++ apps/docs/content/components/toast/usage.ts | 9 + .../content/components/toast/variants.raw.jsx | 29 ++ .../docs/content/components/toast/variants.ts | 9 + .../components/toast/with-action.raw.jsx | 26 ++ .../content/components/toast/with-action.ts | 9 + apps/docs/content/docs/components/toast.mdx | 263 ++++++++++++++++++ .../components/toast/src/toast-provider.tsx | 14 +- .../components/toast/src/toast-region.tsx | 64 ++++- packages/components/toast/src/toast.tsx | 20 +- packages/components/toast/src/use-toast.ts | 34 ++- .../toast/stories/toast.stories.tsx | 48 ++-- packages/core/react/package.json | 1 + packages/core/react/src/index.ts | 1 + packages/core/theme/src/components/toast.ts | 18 +- pnpm-lock.yaml | 3 + 40 files changed, 1084 insertions(+), 56 deletions(-) create mode 100644 .changeset/shaggy-beers-breathe.md create mode 100644 apps/docs/app/examples/toast/color/page.tsx create mode 100644 apps/docs/app/examples/toast/custom-icon/page.tsx create mode 100644 apps/docs/app/examples/toast/custom-style/page.tsx create mode 100644 apps/docs/app/examples/toast/hidden-icon/page.tsx create mode 100644 apps/docs/app/examples/toast/position/page.tsx create mode 100644 apps/docs/app/examples/toast/radius/page.tsx create mode 100644 apps/docs/app/examples/toast/usage/page.tsx create mode 100644 apps/docs/app/examples/toast/variant/page.tsx create mode 100644 apps/docs/app/examples/toast/with-action/page.tsx create mode 100644 apps/docs/content/components/toast/color.raw.jsx create mode 100644 apps/docs/content/components/toast/color.ts create mode 100644 apps/docs/content/components/toast/custom-icon.raw.jsx create mode 100644 apps/docs/content/components/toast/custom-icon.ts create mode 100644 apps/docs/content/components/toast/custom-styles.raw.jsx create mode 100644 apps/docs/content/components/toast/custom-styles.ts create mode 100644 apps/docs/content/components/toast/hidden-icon.raw.jsx create mode 100644 apps/docs/content/components/toast/hidden-icon.ts create mode 100644 apps/docs/content/components/toast/index.ts create mode 100644 apps/docs/content/components/toast/position.raw.jsx create mode 100644 apps/docs/content/components/toast/position.ts create mode 100644 apps/docs/content/components/toast/radius.raw.jsx create mode 100644 apps/docs/content/components/toast/radius.ts create mode 100644 apps/docs/content/components/toast/usage.raw.jsx create mode 100644 apps/docs/content/components/toast/usage.ts create mode 100644 apps/docs/content/components/toast/variants.raw.jsx create mode 100644 apps/docs/content/components/toast/variants.ts create mode 100644 apps/docs/content/components/toast/with-action.raw.jsx create mode 100644 apps/docs/content/components/toast/with-action.ts create mode 100644 apps/docs/content/docs/components/toast.mdx diff --git a/.changeset/shaggy-beers-breathe.md b/.changeset/shaggy-beers-breathe.md new file mode 100644 index 0000000000..3e6f439b12 --- /dev/null +++ b/.changeset/shaggy-beers-breathe.md @@ -0,0 +1,7 @@ +--- +"@nextui-org/shared-icons": patch +"@nextui-org/toast": patch +"@nextui-org/theme": patch +--- + +Introducing the toast component(#2560) diff --git a/apps/docs/app/examples/toast/color/page.tsx b/apps/docs/app/examples/toast/color/page.tsx new file mode 100644 index 0000000000..7696a8b348 --- /dev/null +++ b/apps/docs/app/examples/toast/color/page.tsx @@ -0,0 +1,31 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {["default", "primary", "secondary", "success", "warning", "danger"].map((color) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/app/examples/toast/custom-icon/page.tsx b/apps/docs/app/examples/toast/custom-icon/page.tsx new file mode 100644 index 0000000000..9f7b02b5cd --- /dev/null +++ b/apps/docs/app/examples/toast/custom-icon/page.tsx @@ -0,0 +1,39 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/app/examples/toast/custom-style/page.tsx b/apps/docs/app/examples/toast/custom-style/page.tsx new file mode 100644 index 0000000000..93839249e9 --- /dev/null +++ b/apps/docs/app/examples/toast/custom-style/page.tsx @@ -0,0 +1,57 @@ +"use client"; + +import {addToast, Button, cn, ToastProvider} from "@nextui-org/react"; + +const CustomToastComponent = () => { + return ( + <> + + + + ), + }); + }} + > + Show Toast + + + ); +}; + +export default function App() { + return ( + <> + +
+ +
+ + ); +} diff --git a/apps/docs/app/examples/toast/hidden-icon/page.tsx b/apps/docs/app/examples/toast/hidden-icon/page.tsx new file mode 100644 index 0000000000..4e262ea482 --- /dev/null +++ b/apps/docs/app/examples/toast/hidden-icon/page.tsx @@ -0,0 +1,22 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/app/examples/toast/position/page.tsx b/apps/docs/app/examples/toast/position/page.tsx new file mode 100644 index 0000000000..50cd1853a0 --- /dev/null +++ b/apps/docs/app/examples/toast/position/page.tsx @@ -0,0 +1,24 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ +
+ + ); +} diff --git a/apps/docs/app/examples/toast/radius/page.tsx b/apps/docs/app/examples/toast/radius/page.tsx new file mode 100644 index 0000000000..e726e30e10 --- /dev/null +++ b/apps/docs/app/examples/toast/radius/page.tsx @@ -0,0 +1,31 @@ +"use client"; + +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {["none", "sm", "md", "lg", "full"].map((radius) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/app/examples/toast/usage/page.tsx b/apps/docs/app/examples/toast/usage/page.tsx new file mode 100644 index 0000000000..28cf52f177 --- /dev/null +++ b/apps/docs/app/examples/toast/usage/page.tsx @@ -0,0 +1,21 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/app/examples/toast/variant/page.tsx b/apps/docs/app/examples/toast/variant/page.tsx new file mode 100644 index 0000000000..553adc8907 --- /dev/null +++ b/apps/docs/app/examples/toast/variant/page.tsx @@ -0,0 +1,30 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {["solid", "bordered", "flat", "faded"].map((variant) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/app/examples/toast/with-action/page.tsx b/apps/docs/app/examples/toast/with-action/page.tsx new file mode 100644 index 0000000000..77d2d1828f --- /dev/null +++ b/apps/docs/app/examples/toast/with-action/page.tsx @@ -0,0 +1,28 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + ), + color: "warning", + variant: "faded", + }); + }} + > + Show Toast + + + ); +} diff --git a/apps/docs/config/routes.json b/apps/docs/config/routes.json index f1ec7ce7b2..f2fcfe4321 100644 --- a/apps/docs/config/routes.json +++ b/apps/docs/config/routes.json @@ -436,7 +436,7 @@ "title": "Toast", "keywords": "toast, notification, message", "path": "/docs/components/toast.mdx", - "comingSoon": true + "newPost": true }, { "key": "textarea", diff --git a/apps/docs/content/components/toast/color.raw.jsx b/apps/docs/content/components/toast/color.raw.jsx new file mode 100644 index 0000000000..e9772bc692 --- /dev/null +++ b/apps/docs/content/components/toast/color.raw.jsx @@ -0,0 +1,30 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {["default", "primary", "secondary", "success", "warning", "danger"].map((color) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/content/components/toast/color.ts b/apps/docs/content/components/toast/color.ts new file mode 100644 index 0000000000..6c2d8d6af9 --- /dev/null +++ b/apps/docs/content/components/toast/color.ts @@ -0,0 +1,9 @@ +import App from "./color.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/custom-icon.raw.jsx b/apps/docs/content/components/toast/custom-icon.raw.jsx new file mode 100644 index 0000000000..e16d6c4134 --- /dev/null +++ b/apps/docs/content/components/toast/custom-icon.raw.jsx @@ -0,0 +1,38 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/custom-icon.ts b/apps/docs/content/components/toast/custom-icon.ts new file mode 100644 index 0000000000..45bfa34b89 --- /dev/null +++ b/apps/docs/content/components/toast/custom-icon.ts @@ -0,0 +1,9 @@ +import App from "./custom-icon.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/custom-styles.raw.jsx b/apps/docs/content/components/toast/custom-styles.raw.jsx new file mode 100644 index 0000000000..1cd38dc337 --- /dev/null +++ b/apps/docs/content/components/toast/custom-styles.raw.jsx @@ -0,0 +1,55 @@ +import {addToast, Button, cn, ToastProvider} from "@nextui-org/react"; + +const CustomToastComponent = () => { + return ( + <> + + + + ), + }); + }} + > + Show Toast + + + ); +}; + +export default function App() { + return ( + <> + +
+ +
+ + ); +} diff --git a/apps/docs/content/components/toast/custom-styles.ts b/apps/docs/content/components/toast/custom-styles.ts new file mode 100644 index 0000000000..da3ea9093a --- /dev/null +++ b/apps/docs/content/components/toast/custom-styles.ts @@ -0,0 +1,9 @@ +import App from "./custom-styles.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/hidden-icon.raw.jsx b/apps/docs/content/components/toast/hidden-icon.raw.jsx new file mode 100644 index 0000000000..93cc1ca305 --- /dev/null +++ b/apps/docs/content/components/toast/hidden-icon.raw.jsx @@ -0,0 +1,23 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ +
+ + ); +} diff --git a/apps/docs/content/components/toast/hidden-icon.ts b/apps/docs/content/components/toast/hidden-icon.ts new file mode 100644 index 0000000000..6255ecb9f7 --- /dev/null +++ b/apps/docs/content/components/toast/hidden-icon.ts @@ -0,0 +1,9 @@ +import App from "./hidden-icon.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/index.ts b/apps/docs/content/components/toast/index.ts new file mode 100644 index 0000000000..4dd575e88a --- /dev/null +++ b/apps/docs/content/components/toast/index.ts @@ -0,0 +1,17 @@ +import color from "./color"; +import usage from "./usage"; +import variants from "./variants"; +import customIcon from "./custom-icon"; +import hiddenIcon from "./hidden-icon"; +import withAction from "./with-action"; +import customStyles from "./custom-styles"; + +export const toastContent = { + color, + usage, + variants, + customIcon, + hiddenIcon, + withAction, + customStyles, +}; diff --git a/apps/docs/content/components/toast/position.raw.jsx b/apps/docs/content/components/toast/position.raw.jsx new file mode 100644 index 0000000000..d5ea6353cc --- /dev/null +++ b/apps/docs/content/components/toast/position.raw.jsx @@ -0,0 +1,35 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {[ + "left-top", + "right-top", + "center-top", + "left-bottom", + "right-bottom", + "center-bottom", + ].map((position) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/content/components/toast/position.ts b/apps/docs/content/components/toast/position.ts new file mode 100644 index 0000000000..e386fb1848 --- /dev/null +++ b/apps/docs/content/components/toast/position.ts @@ -0,0 +1,9 @@ +import App from "./position.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/radius.raw.jsx b/apps/docs/content/components/toast/radius.raw.jsx new file mode 100644 index 0000000000..020aadaa99 --- /dev/null +++ b/apps/docs/content/components/toast/radius.raw.jsx @@ -0,0 +1,29 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {["none", "sm", "md", "lg", "full"].map((radius) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/content/components/toast/radius.ts b/apps/docs/content/components/toast/radius.ts new file mode 100644 index 0000000000..7b78db1ce0 --- /dev/null +++ b/apps/docs/content/components/toast/radius.ts @@ -0,0 +1,9 @@ +import App from "./radius.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/usage.raw.jsx b/apps/docs/content/components/toast/usage.raw.jsx new file mode 100644 index 0000000000..099998ba55 --- /dev/null +++ b/apps/docs/content/components/toast/usage.raw.jsx @@ -0,0 +1,19 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/usage.ts b/apps/docs/content/components/toast/usage.ts new file mode 100644 index 0000000000..1118304c37 --- /dev/null +++ b/apps/docs/content/components/toast/usage.ts @@ -0,0 +1,9 @@ +import App from "./usage.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/variants.raw.jsx b/apps/docs/content/components/toast/variants.raw.jsx new file mode 100644 index 0000000000..1ed0a2aa96 --- /dev/null +++ b/apps/docs/content/components/toast/variants.raw.jsx @@ -0,0 +1,29 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ {["solid", "bordered", "flat", "faded"].map((variant) => ( + + ))} +
+ + ); +} diff --git a/apps/docs/content/components/toast/variants.ts b/apps/docs/content/components/toast/variants.ts new file mode 100644 index 0000000000..ddea95fb2e --- /dev/null +++ b/apps/docs/content/components/toast/variants.ts @@ -0,0 +1,9 @@ +import App from "./variants.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/with-action.raw.jsx b/apps/docs/content/components/toast/with-action.raw.jsx new file mode 100644 index 0000000000..493f6d1f01 --- /dev/null +++ b/apps/docs/content/components/toast/with-action.raw.jsx @@ -0,0 +1,26 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + ), + color: "warning", + variant: "faded", + }); + }} + > + Show Toast + + + ); +} diff --git a/apps/docs/content/components/toast/with-action.ts b/apps/docs/content/components/toast/with-action.ts new file mode 100644 index 0000000000..1bb611e21b --- /dev/null +++ b/apps/docs/content/components/toast/with-action.ts @@ -0,0 +1,9 @@ +import App from "./with-action.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx new file mode 100644 index 0000000000..01dcc08e7c --- /dev/null +++ b/apps/docs/content/docs/components/toast.mdx @@ -0,0 +1,263 @@ +--- +title: "Toast" +description: "Toast are temporary notifications that provide concise feedback about an action or event." +--- + +import {toastContent} from "@/content/components/toast"; + +# Toast + +Toasts are temporary notifications that provide concise feedback about an action or event. + + + +--- + + + +## Installation + + + +## Import + + + +> **Note**: Before using the addToast function, ensure you have added `ToastProvider` to your application (or the relevant part of it). This is necessary to initialize the context for managing toasts. + +### Usage + + + +### Colors + +Toast comes with 6 color variants to convey different meanings. + + + +### Variants + + + +### Radius + + + +### Custom Icon + +By default, Toast displays an appropriate icon based on the `color` prop. You can override this by providing a custom icon using the `icon` prop. + + + +### Without Icon + +You can hide the icon by setting the `hideIcon` prop to `true`. + + + +### With Action + +Toast supports an `endContent` prop for additional actions. + + + +### Toast Position + + + +### Custom Styles + +You can customize the alert by passing custom Tailwind CSS classes to the component slots. + + + + + +## Data Attributes + +Toast has the following attributes on the `base` element: + +- **data-has-title**: When the toast has a title +- **data-has-description**: When the toast has a description + + + +### Slots + +Toast has the following slots: + +- `base`: The main toast container element +- `title`: The title element +- `description`: The description element +- `icon`: The icon element +- `content`: The wrapper for the title, description and icon content +- `progressBar`: The progressBar element that display timer to close the toast. +- `progressTrack`: The track of the progressBar. +- `closeButton`: The close button element + +## Accessibility + +- Toast has role of `alert` +- All Toasts are present in ToastRegion. +- Close button has aria-label="Close" by default +- When no toast are present, ToastRegion is removed from the DOM + + + +## API + +### Toast Props + + + +### ToastProvider Props + + + + +### Toast Events + + void", + description: "Handler called when the close button is clicked", + default: "-" + } + ]} +/> \ No newline at end of file diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx index 859c093a1a..1e850150c3 100644 --- a/packages/components/toast/src/toast-provider.tsx +++ b/packages/components/toast/src/toast-provider.tsx @@ -7,6 +7,13 @@ let globalToastQueue: ToastQueue | null = null; interface ToastProviderProps { maxVisibleToasts?: number; + position?: + | "right-bottom" + | "left-bottom" + | "center-bottom" + | "right-top" + | "left-top" + | "center-top"; } export const getToastQueue = (maxVisibleToasts: number) => { @@ -19,14 +26,17 @@ export const getToastQueue = (maxVisibleToasts: number) => { return globalToastQueue; }; -export const ToastProvider = ({maxVisibleToasts = 5}: ToastProviderProps) => { +export const ToastProvider = ({ + maxVisibleToasts = 5, + position = "right-bottom", +}: ToastProviderProps) => { const toastQueue = useToastQueue(getToastQueue(maxVisibleToasts)); if (toastQueue.visibleToasts.length == 0) { return null; } - return ; + return ; }; export const addToast = ({...props}: ToastProps & ToastOptions) => { diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index 8f585c2cf4..35f9c24db2 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -1,29 +1,67 @@ import {useRef} from "react"; import {useToastRegion, AriaToastRegionProps} from "@react-aria/toast"; import {QueuedToast, ToastState} from "@react-stately/toast"; +import {createPortal} from "react-dom"; +import {clsx} from "@nextui-org/shared-utils"; import Toast from "./toast"; import {ToastProps} from "./use-toast"; interface ToastRegionProps extends AriaToastRegionProps { toastQueue: ToastState; + position?: + | "right-bottom" + | "left-bottom" + | "center-bottom" + | "right-top" + | "left-top" + | "center-top"; } -export function ToastRegion({toastQueue, ...props}: ToastRegionProps) { +export function ToastRegion({ + toastQueue, + position, + ...props +}: ToastRegionProps) { const ref = useRef(null); const {regionProps} = useToastRegion(props, toastQueue, ref); + let positionStyle; - return ( - <> -
- {toastQueue.visibleToasts.map((toast: QueuedToast) => { - return ; - })} -
- + switch (position) { + case "right-bottom": + positionStyle = "bottom-0 right-0 pr-2"; + break; + case "left-bottom": + positionStyle = "bottom-0 left-0 pl-2"; + break; + case "center-bottom": + positionStyle = "bottom-0 left-1/2 -translate-x-1/2"; + break; + case "right-top": + positionStyle = "top-0 right-0 pr-2"; + break; + case "left-top": + positionStyle = "top-0 left-0 pl-2"; + break; + case "center-top": + positionStyle = "top-0 left-1/2 -translate-x-1/2"; + break; + } + + return createPortal( +
+ {toastQueue.visibleToasts.map((toast: QueuedToast) => { + return ( + + ); + })} +
, + document.body, ); } diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index a64477d34a..f628ed9144 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -31,6 +31,8 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { endContent, closeProgressBarValue, color, + hideIcon, + position, getToastProps, getContentProps, getTitleProps, @@ -43,11 +45,17 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { ref, }); - const toastVariants = { - hidden: {opacity: 0, y: 50}, - visible: {opacity: 1, y: 0}, - exit: {opacity: 0, y: 50}, - }; + const toastVariants = position.includes("bottom") + ? { + hidden: {opacity: 0, y: 50}, + visible: {opacity: 1, y: 0}, + exit: {opacity: 0, y: 50}, + } + : { + hidden: {opacity: 0, y: -50}, + visible: {opacity: 1, y: 0}, + exit: {opacity: 0, y: -50}, + }; const customIcon = icon && isValidElement(icon) ? cloneElement(icon, getIconProps()) : null; const IconComponent = iconMap[color] || iconMap.primary; @@ -63,7 +71,7 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { >
- {customIcon || } + {!hideIcon ? customIcon || : null}
{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 d0d182f5da..b4e7196b40 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -3,7 +3,7 @@ import type {SlotsToClasses, ToastSlots, ToastVariantProps} from "@nextui-org/th import {HTMLNextUIProps, PropGetter, mapPropsVariants} from "@nextui-org/system"; import {toast as toastTheme} from "@nextui-org/theme"; import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; -import {clsx, objectToDeps} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, isEmpty, objectToDeps} from "@nextui-org/shared-utils"; import {ReactNode, useCallback, useEffect, useMemo, useState} from "react"; import {useToast as useToastAria, AriaToastProps} from "@react-aria/toast"; import {mergeProps} from "@react-aria/utils"; @@ -16,6 +16,15 @@ export interface ToastProps extends ToastVariantProps { classNames?: SlotsToClasses; endContent?: ReactNode; icon?: ReactNode; + hideIcon?: boolean; + position?: + | "right-bottom" + | "left-bottom" + | "center-bottom" + | "right-top" + | "left-top" + | "center-top"; + onClose?: () => void; } interface Props extends HTMLNextUIProps<"div">, ToastProps { @@ -46,7 +55,19 @@ export function useToast(originalProps: UseToastProps) }; }); - const {ref, as, className, classNames, toast, endContent, ...otherProps} = props; + const { + ref, + as, + title, + description, + className, + classNames, + toast, + endContent, + hideIcon = false, + position = "right-bottom", + ...otherProps + } = props; const Component = as || "div"; const icon: ReactNode = props.icon; @@ -94,6 +115,8 @@ export function useToast(originalProps: UseToastProps) setIsToastClicked(false); toast.timer.resume(); }, + "data-has-title": dataAttr(!isEmpty(title)), + "data-has-description": dataAttr(!isEmpty(description)), ...mergeProps(props, otherProps, toastProps), }), [slots, classNames, toastProps], @@ -134,7 +157,8 @@ export function useToast(originalProps: UseToastProps) const getCloseButtonProps: PropGetter = useCallback( (props = {}) => ({ className: slots.closeButton({class: classNames?.closeButton}), - ...mergeProps(props, otherProps, closeButtonProps), + "aria-label": "close-button", + ...mergeProps(props, otherProps, closeButtonProps, {onPress: props.onClose}), }), [closeButtonProps], ); @@ -159,12 +183,16 @@ export function useToast(originalProps: UseToastProps) return { Component, + title, + description, icon, styles, domRef, classNames, closeProgressBarValue, color: variantProps["color"], + hideIcon, + position, getToastProps, getTitleProps, getContentProps, diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index fdad171e01..2f3d04f6b1 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -30,29 +30,45 @@ export default { type: "boolean", }, }, + hideIcon: { + control: { + type: "boolean", + }, + }, }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], } as Meta; const defaultProps = { ...toast.defaultVariants, }; -const Template = (args: ToastProps) => ( - <> - - - -); +const Template = (args: ToastProps) => { + return ( + <> + +
+ +
+ + ); +}; const TimeoutTemplate = (args: ToastProps) => { return ( diff --git a/packages/core/react/package.json b/packages/core/react/package.json index 8c2dd99e31..b0ffb12f61 100644 --- a/packages/core/react/package.json +++ b/packages/core/react/package.json @@ -89,6 +89,7 @@ "@heroui/drawer": "workspace:*", "@heroui/form": "workspace:*", "@heroui/alert": "workspace:*", + "@heroui/toast": "workspace:*", "@react-aria/visually-hidden": "3.8.18" }, "peerDependencies": { diff --git a/packages/core/react/src/index.ts b/packages/core/react/src/index.ts index 2b29b0ac5e..50aec9e35c 100644 --- a/packages/core/react/src/index.ts +++ b/packages/core/react/src/index.ts @@ -47,6 +47,7 @@ export * from "@heroui/form"; export * from "@heroui/alert"; export * from "@heroui/drawer"; export * from "@heroui/input-otp"; +export * from "@heroui/toast"; /** * React Aria - Exports diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 11f5160a67..9db44ea003 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -4,22 +4,10 @@ import {tv} from "../utils/tv"; const toast = tv({ slots: { - wrapper: [ - "flex", - "w-screen", - "min-h-10", - "fixed", - "inset-0", - "z-50", - "overflow-x-auto", - "justify-center", - ], base: [ "flex gap-x-4 items-center", "relative", - "bg-white", - "z-50", - "w-full", + "z-500", "box-border", "outline-none", "p-2 px-4 mx-1", @@ -31,10 +19,10 @@ const toast = tv({ "text-white", "shadow-inner", ], - 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"], + icon: ["w-6 h-6 fill-current"], + content: ["flex flex-grow flex-row gap-x-1 items-center"], progressBar: [ "absolute", "h-[2px]", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25ae47b742..f9c96d7ed6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3281,6 +3281,9 @@ importers: '@heroui/theme': specifier: workspace:* version: link:../theme + '@heroui/toast': + specifier: workspace:* + version: link:../../components/toast '@heroui/tooltip': specifier: workspace:* version: link:../../components/tooltip From d2b0e6a5f3aece7f81ac4caae8b09651ce3333b1 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Thu, 26 Dec 2024 17:32:18 +0530 Subject: [PATCH 06/49] chore: adding the swiping interaction for toast removal --- .../docs/app/examples/toast/position/page.tsx | 1 - .../app/examples/toast/with-timeout/page.tsx | 22 ++++ apps/docs/content/components/toast/index.ts | 2 + .../components/toast/with-timeout.raw.jsx | 21 ++++ .../content/components/toast/with-timeout.ts | 9 ++ apps/docs/content/docs/components/toast.mdx | 25 +++++ .../components/toast/__tests__/toast.test.tsx | 60 ++++++++++ packages/components/toast/src/toast.tsx | 103 +++++++++++++----- packages/components/toast/src/use-toast.ts | 86 ++++++++++++--- .../toast/stories/toast.stories.tsx | 54 ++++++++- packages/core/theme/src/components/toast.ts | 43 ++++++-- 11 files changed, 370 insertions(+), 56 deletions(-) create mode 100644 apps/docs/app/examples/toast/with-timeout/page.tsx create mode 100644 apps/docs/content/components/toast/with-timeout.raw.jsx create mode 100644 apps/docs/content/components/toast/with-timeout.ts create mode 100644 packages/components/toast/__tests__/toast.test.tsx diff --git a/apps/docs/app/examples/toast/position/page.tsx b/apps/docs/app/examples/toast/position/page.tsx index 50cd1853a0..f78d4c9e0f 100644 --- a/apps/docs/app/examples/toast/position/page.tsx +++ b/apps/docs/app/examples/toast/position/page.tsx @@ -8,7 +8,6 @@ export default function App() {
+ + ); +} diff --git a/apps/docs/content/components/toast/index.ts b/apps/docs/content/components/toast/index.ts index 4dd575e88a..cbe6f8ea3a 100644 --- a/apps/docs/content/components/toast/index.ts +++ b/apps/docs/content/components/toast/index.ts @@ -5,6 +5,7 @@ import customIcon from "./custom-icon"; import hiddenIcon from "./hidden-icon"; import withAction from "./with-action"; import customStyles from "./custom-styles"; +import withTimeout from "./with-timeout"; export const toastContent = { color, @@ -14,4 +15,5 @@ export const toastContent = { hiddenIcon, withAction, customStyles, + withTimeout, }; diff --git a/apps/docs/content/components/toast/with-timeout.raw.jsx b/apps/docs/content/components/toast/with-timeout.raw.jsx new file mode 100644 index 0000000000..06e589d508 --- /dev/null +++ b/apps/docs/content/components/toast/with-timeout.raw.jsx @@ -0,0 +1,21 @@ +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/with-timeout.ts b/apps/docs/content/components/toast/with-timeout.ts new file mode 100644 index 0000000000..6c11096c6d --- /dev/null +++ b/apps/docs/content/components/toast/with-timeout.ts @@ -0,0 +1,9 @@ +import App from "./with-timeout.raw.jsx?raw"; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index 01dcc08e7c..07c6e4d006 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -117,6 +117,18 @@ Toast supports an `endContent` prop for additional actions. files={toastContent.withAction} /> +### With Timeout + +Toast supports an `endContent` prop for additional actions. + + + ### Toast Position { + let user: UserEvent; + + beforeEach(() => { + user = userEvent.setup(); + }); + + it("should render correctly", () => { + const wrapper = render( + <> + + + , + ); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it("ref should be forwarded", async () => { + const ref = React.createRef(); + + const wrapper = render( + <> + + + , + ); + + const button = wrapper.getByTestId("button"); + + await user.click(button); + expect(ref.current).not.toBeNull(); + }); +}); diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index f628ed9144..64f052633f 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -9,7 +9,7 @@ import { } from "@nextui-org/shared-icons"; import {motion, AnimatePresence} from "framer-motion"; import {Progress} from "@nextui-org/progress"; -import {cloneElement, isValidElement} from "react"; +import {cloneElement, isValidElement, useState} from "react"; import {UseToastProps, useToast} from "./use-toast"; @@ -33,6 +33,9 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { color, hideIcon, position, + toast, + state, + disableAnimation, getToastProps, getContentProps, getTitleProps, @@ -59,36 +62,86 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { const customIcon = icon && isValidElement(icon) ? cloneElement(icon, getIconProps()) : null; const IconComponent = iconMap[color] || iconMap.primary; + const [isOut, setIsOut] = useState(false); - return ( - - - -
- {!hideIcon ? customIcon || : null} -
-
{props.toast.content.title}
-
{props.toast.content.description}
-
-
- - {endContent} + const handleDragEnd = (offsetX: number, offsetY: number) => { + if (position.includes("right")) { + if (offsetX < 50) { + return; + } + setIsOut(true); + state.close(toast.key); + } + if (position.includes("left")) { + if (offsetX > -50) { + return; + } + setIsOut(true); + state.close(toast.key); + } + if (position == "center-top") { + if (offsetY > -50) { + return; + } + setIsOut(true); + state.close(toast.key); + } + if (position == "center-bottom") { + if (offsetY < 50) { + return; + } + setIsOut(true); + state.close(toast.key); + } + }; + + const toastContent = ( + +
+ {hideIcon ? null : customIcon || } +
+
{props.toast.content.title}
+
{props.toast.content.description}
- - - +
+
+ + {endContent} +
+ ); + + return ( + <> + {disableAnimation ? ( + toastContent + ) : ( + + { + const offsetX = info.offset.x; + const offsetY = info.offset.y; + + handleDragEnd(offsetX, offsetY); + }} + > + {toastContent} + + + )} + ); }); diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index b4e7196b40..7e534b2357 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -1,6 +1,11 @@ import type {SlotsToClasses, ToastSlots, ToastVariantProps} from "@nextui-org/theme"; -import {HTMLNextUIProps, PropGetter, mapPropsVariants} from "@nextui-org/system"; +import { + HTMLNextUIProps, + PropGetter, + mapPropsVariants, + useProviderContext, +} from "@nextui-org/system"; import {toast as toastTheme} from "@nextui-org/theme"; import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; import {clsx, dataAttr, isEmpty, objectToDeps} from "@nextui-org/shared-utils"; @@ -10,13 +15,57 @@ import {mergeProps} from "@react-aria/utils"; import {QueuedToast, ToastState} from "@react-stately/toast"; export interface ToastProps extends ToastVariantProps { + /** + * Ref to the DOM node. + */ ref?: ReactRef; + /** + * title of the toast + */ title?: string; + /** + * description of the toast + */ description?: string; + /** + * Classname or List of classes to change the classNames of the element. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * addToast({ + * classNames={{ + * base:"base-classes", + * content: "content-classes" + * description: "description-classes" + * title: "title-classes" + * icon: "icon-classes", + * progressBar: "progress-bar-classes", + * progressTrack: "progress-track-classes", + * progressIndicator: "progress-indicator-classes", + * closeButton: "closeButton-classes" + * closeIcon: "closeIcon-classes" + * }} + * }) + * ``` + */ classNames?: SlotsToClasses; + /** + * Content to be displayed in the end side of the alert + */ endContent?: ReactNode; + /** + * Icon to be displayed in the alert - overrides the default icon + */ icon?: ReactNode; + /** + * Whether the toast-icon is hidden. + * @default false + */ hideIcon?: boolean; + /** + * Position of the toast in the view-port. + */ position?: | "right-bottom" | "left-bottom" @@ -24,6 +73,9 @@ export interface ToastProps extends ToastVariantProps { | "right-top" | "left-top" | "center-top"; + /** + * function which is called when toast is closed. + */ onClose?: () => void; } @@ -37,14 +89,17 @@ export type UseToastProps = Props & Omit, "div">; export function useToast(originalProps: UseToastProps) { + const globalContext = useProviderContext(); const [props, variantProps] = mapPropsVariants(originalProps, toastTheme.variantKeys); const [closeProgressBarValue, setCloseProgressBarValue] = useState(0); - const [isToastClicked, setIsToastClicked] = useState(false); + const [isToastHovered, setIsToastHovered] = useState(false); + const disableAnimation = + originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false; useEffect(() => { const interval = setInterval(async () => { - if (isToastClicked) { + if (isToastHovered) { return; } setCloseProgressBarValue(closeProgressBarValue + 10); @@ -66,6 +121,7 @@ export function useToast(originalProps: UseToastProps) endContent, hideIcon = false, position = "right-bottom", + state, ...otherProps } = props; @@ -80,19 +136,11 @@ export function useToast(originalProps: UseToastProps) domRef, ); - const styles = useMemo( - () => - toastTheme({ - ...variantProps, - className, - }), - [objectToDeps(variantProps), className], - ); - const slots = useMemo( () => toastTheme({ ...variantProps, + disableAnimation, }), [objectToDeps(variantProps)], ); @@ -101,18 +149,18 @@ export function useToast(originalProps: UseToastProps) (props = {}) => ({ ref: domRef, className: slots.base({class: clsx(baseStyles, classNames?.base)}), - onMouseDown: () => { + onMouseEnter: () => { if (!toast.timer) { return; } - setIsToastClicked(true); + setIsToastHovered(true); toast.timer.pause(); }, - onMouseUp: () => { + onMouseLeave: () => { if (!toast.timer) { return; } - setIsToastClicked(false); + setIsToastHovered(false); toast.timer.resume(); }, "data-has-title": dataAttr(!isEmpty(title)), @@ -167,7 +215,7 @@ export function useToast(originalProps: UseToastProps) const progressBarProps = { classNames: { track: slots.progressTrack({class: clsx(classNames?.progressTrack)}), - indicator: "bg-default-600", + indicator: slots.progressIndicator({class: clsx(classNames?.progressIndicator)}), }, radius: "none", isDisabled: true, @@ -186,13 +234,15 @@ export function useToast(originalProps: UseToastProps) title, description, icon, - styles, domRef, classNames, closeProgressBarValue, color: variantProps["color"], hideIcon, position, + state, + toast: props.toast, + disableAnimation, getToastProps, getTitleProps, getContentProps, diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 2f3d04f6b1..105b9b4d08 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -35,6 +35,22 @@ export default { type: "boolean", }, }, + disableAnimation: { + control: { + type: "boolean", + }, + }, + position: { + control: {type: "select"}, + options: [ + "right-bottom", + "left-bottom", + "center-bottom", + "right-top", + "left-top", + "center-top", + ], + }, }, decorators: [ (Story) => ( @@ -116,6 +132,27 @@ const WithEndContentTemplate = (args) => { ); }; +const PositionTemplate = (args: ToastProps) => { + return ( + <> + +
+ +
+ + ); +}; + const CustomToastComponent = (args) => { const color = args.color; const colorMap = { @@ -191,7 +228,7 @@ export const Default = { }, }; -export const WithIcon = { +export const WithCustomIcon = { render: Template, args: { ...defaultProps, @@ -217,6 +254,14 @@ export const WithIcon = { }, }; +export const iconHidden = { + render: Template, + args: { + ...defaultProps, + hideIcon: true, + }, +}; + export const WithTimeout = { render: TimeoutTemplate, args: { @@ -224,6 +269,13 @@ export const WithTimeout = { }, }; +export const Position = { + render: PositionTemplate, + args: { + ...defaultProps, + }, +}; + export const WithEndContent = { render: WithEndContentTemplate, args: { diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 9db44ea003..b4ebe26326 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -6,11 +6,13 @@ const toast = tv({ slots: { base: [ "flex gap-x-4 items-center", + "group", + "cursor-pointer", "relative", "z-500", "box-border", "outline-none", - "p-2 px-4 mx-1", + "p-4 px-6 mx-1", "my-1", "sm:mx-4", "sm:my-4", @@ -19,39 +21,45 @@ const toast = tv({ "text-white", "shadow-inner", ], - title: ["font-medium", "ms-4"], - description: ["font-light", "ms-4"], + title: ["font-medium", "ms-4", "text-sm"], + description: ["font-light", "ms-4", "text-xs"], icon: ["w-6 h-6 fill-current"], - content: ["flex flex-grow flex-row gap-x-1 items-center"], + content: ["flex flex-grow flex-row gap-x-1 items-center relative"], progressBar: [ "absolute", "h-[2px]", "right-0", - "bottom-0", + "-bottom-3", "w-full", "overflow-hidden", - "bg-green-500", - "rounded-none", + "rounded-full", ], progressTrack: ["bg-default-200"], + progressIndicator: ["bg-default-400"], closeButton: [ - "w-4 h-4 min-w-4 p-0.5 absolute -right-1 -top-1 flex items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", + "opacity-0 group-hover:opacity-100 w-4 h-4 min-w-4 p-0.5 absolute -right-1 -top-1 items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", ], }, variants: { size: { sm: { icon: "w-4 h-4", + title: "text-sm font-medium", + description: "text-xs font-light", }, md: { icon: "w-6 h-6", + title: "text-sm font-semibold", + description: "text-xs font-light", }, lg: { icon: "w-8 h-8", + title: "text-md font-semibold", + description: "text-sm font-light", }, }, variant: { - flat: "bg-default", + flat: "bg-default-50", faded: "bg-default border border-1 border-default-400", solid: "bg-default shadow-inner", bordered: "bg-white dark:bg-black border border-1 border-default-400", @@ -60,18 +68,23 @@ const toast = tv({ default: "", primary: { progressTrack: "bg-primary-200", + progressIndicator: "bg-primary-400", }, secondary: { progressTrack: "bg-secondary-200", + progressIndicator: "bg-secondary-400", }, success: { progressTrack: "bg-success-200", + progressIndicator: "bg-success-400", }, warning: { progressTrack: "bg-warning-200", + progressIndicator: "bg-warning-400", }, danger: { progressTrack: "bg-danger-200", + progressIndicator: "bg-danger-400", }, }, radius: { @@ -91,11 +104,19 @@ const toast = tv({ base: "rounded-full", }, }, + disableAnimation: { + true: { + closeButton: "transition-none", + }, + false: { + closeButton: "transition-opacity ease-in duration-300", + }, + }, }, defaultVariants: { - size: "sm", + size: "md", variant: "flat", - radius: "none", + radius: "md", }, compoundVariants: [ // flat and color From 4a74835fa04c4d0691abb582a6f7095b5e6141c9 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Fri, 27 Dec 2024 12:22:26 +0530 Subject: [PATCH 07/49] chore: adding the tests --- .../components/toast/__tests__/toast.test.tsx | 66 ++++++++++++++++++- packages/components/toast/src/use-toast.ts | 2 +- .../toast/stories/toast.stories.tsx | 2 +- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/packages/components/toast/__tests__/toast.test.tsx b/packages/components/toast/__tests__/toast.test.tsx index 332570a564..201614cc05 100644 --- a/packages/components/toast/__tests__/toast.test.tsx +++ b/packages/components/toast/__tests__/toast.test.tsx @@ -1,9 +1,12 @@ import * as React from "react"; -import {render} from "@testing-library/react"; +import {render, screen} from "@testing-library/react"; import userEvent, {UserEvent} from "@testing-library/user-event"; import {addToast, ToastProvider} from "../src"; +const title = "Testing Title"; +const description = "Testing Description"; + describe("Toast", () => { let user: UserEvent; @@ -57,4 +60,65 @@ describe("Toast", () => { await user.click(button); expect(ref.current).not.toBeNull(); }); + + it("should display title and description when component is rendered", async () => { + const wrapper = render( + <> + + + , + ); + + const button = wrapper.getByTestId("button"); + + await user.click(button); + + const region = screen.getByRole("region"); + + expect(region).toContainHTML(title); + expect(region).toContainHTML(description); + }); + + it("should close", async () => { + const wrapper = render( + <> + + + , + ); + + const button = wrapper.getByTestId("button"); + + await user.click(button); + + const initialCloseButtons = wrapper.getAllByRole("button"); + const initialButtonLength = initialCloseButtons.length; + + await user.click(initialCloseButtons[initialButtonLength - 1]); + + const finalCloseButtons = wrapper.getAllByRole("button"); + const finalButtonLength = finalCloseButtons.length; + + expect(initialButtonLength).toEqual(finalButtonLength + 1); + }); }); diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 7e534b2357..8190b620ac 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -206,7 +206,7 @@ export function useToast(originalProps: UseToastProps) (props = {}) => ({ className: slots.closeButton({class: classNames?.closeButton}), "aria-label": "close-button", - ...mergeProps(props, otherProps, closeButtonProps, {onPress: props.onClose}), + ...mergeProps(props, closeButtonProps, {onPress: originalProps.onClose}), }), [closeButtonProps], ); diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 105b9b4d08..fd735c8908 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -283,6 +283,6 @@ export const WithEndContent = { }, }; -export const CustomTemplate = { +export const CustomStyles = { render: CustomToastTemplate, }; From c5325f222e83bfa474460b46841070623159f7bc Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Fri, 27 Dec 2024 16:07:17 +0530 Subject: [PATCH 08/49] fix: improving the progress bar logix --- apps/docs/content/docs/components/toast.mdx | 1 - packages/components/toast/package.json | 1 - packages/components/toast/src/toast.tsx | 20 +++--- packages/components/toast/src/use-toast.ts | 80 ++++++++++++--------- packages/core/theme/src/components/toast.ts | 13 +--- pnpm-lock.yaml | 3 - 6 files changed, 62 insertions(+), 56 deletions(-) diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index 07c6e4d006..201fcccb70 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -171,7 +171,6 @@ Toast has the following slots: - `description`: The description element - `icon`: The icon element - `content`: The wrapper for the title, description and icon content -- `progressBar`: The progressBar element that display timer to close the toast. - `progressTrack`: The track of the progressBar. - `progressIndicator`: The indicator of the progressBar. - `closeButton`: The close button element diff --git a/packages/components/toast/package.json b/packages/components/toast/package.json index f4d1ccd6ff..2b86beb11c 100644 --- a/packages/components/toast/package.json +++ b/packages/components/toast/package.json @@ -43,7 +43,6 @@ "@nextui-org/react-utils": "workspace:*", "@nextui-org/shared-utils": "workspace:*", "@nextui-org/shared-icons": "workspace:*", - "@nextui-org/progress": "workspace:*", "@react-aria/button": "3.9.5", "@react-aria/toast": "3.0.0-beta.15", "@react-aria/utils": "3.24.1", diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index 64f052633f..b453b24f8e 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -8,7 +8,6 @@ import { WarningIcon, } from "@nextui-org/shared-icons"; import {motion, AnimatePresence} from "framer-motion"; -import {Progress} from "@nextui-org/progress"; import {cloneElement, isValidElement, useState} from "react"; import {UseToastProps, useToast} from "./use-toast"; @@ -29,18 +28,20 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { icon, domRef, endContent, - closeProgressBarValue, color, hideIcon, position, toast, state, disableAnimation, + progressBarRef, + classNames, + slots, + isProgressBarVisible, getToastProps, getContentProps, getTitleProps, getDescriptionProps, - getProgressBarProps, getCloseButtonProps, getIconProps, } = useToast({ @@ -102,11 +103,14 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => {
{props.toast.content.title}
{props.toast.content.description}
- + {isProgressBarVisible && ( +
+
+
+ )}
+ + + ); +}; + +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 b809c94ab9..387af00287 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3023,6 +3023,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:* From 30daf7c2b99a00512109644b269260d1bbb98375 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 1 Jan 2025 22:11:30 +0530 Subject: [PATCH 18/49] chore: updating the styles --- packages/core/theme/src/components/toast.ts | 84 +++++++++++++++------ 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 9e074bd5e0..e273c4e95c 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -46,8 +46,8 @@ const toast = tv({ }, variant: { flat: "bg-default-50", - faded: "bg-default border border-1 border-default-400", - solid: "bg-default shadow-inner", + faded: "bg-default-50 border border-1 border-default-400", + solid: "bg-default-50 shadow-inner", bordered: "bg-white dark:bg-black border border-1 border-default-400", }, color: { @@ -111,41 +111,51 @@ const toast = tv({ variant: "flat", color: "primary", class: { - base: "bg-primary-50 text-primary-400", + base: "bg-primary-50 text-primary-600", closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + title: "text-primary-600", + description: "text-primary-400", }, }, { variant: "flat", color: "secondary", class: { - base: "bg-secondary-50 text-secondary-400", + base: "bg-secondary-50 text-secondary-600", closeButton: "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + title: "text-secondary-600", + description: "text-secondary-400", }, }, { variant: "flat", color: "success", class: { - base: "bg-success-50 text-success-400", + base: "bg-success-50 text-success-600", closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + title: "text-success-600", + description: "text-success-400", }, }, { variant: "flat", color: "warning", class: { - base: "bg-warning-50 text-warning-400", + base: "bg-warning-50 text-warning-600", closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + title: "text-warning-600", + description: "text-warning-400", }, }, { variant: "flat", color: "danger", class: { - base: "bg-danger-50 text-danger-400", + base: "bg-danger-50 text-danger-600", closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + title: "text-danger-600", + description: "text-danger-400", }, }, // faded and color @@ -153,41 +163,51 @@ const toast = tv({ variant: "faded", color: "primary", class: { - base: "bg-primary-50 text-primary-400 border-primary-400", + base: "bg-primary-50 text-primary-400 border-primary-600", closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + title: "text-primary-600", + description: "text-primary-400", }, }, { variant: "faded", color: "secondary", class: { - base: "bg-secondary-50 text-secondary-400 border-secondary-400", + base: "bg-secondary-50 text-secondary-400 border-secondary-600", closeButton: "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + title: "text-secondary-600", + description: "text-secondary-400", }, }, { variant: "faded", color: "success", class: { - base: "bg-success-50 text-success-400 border-success-400", + base: "bg-success-50 text-success-400 border-success-600", closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + title: "text-success-600", + description: "text-success-400", }, }, { variant: "faded", color: "warning", class: { - base: "bg-warning-50 text-warning-400 border-warning-400", + base: "bg-warning-50 text-warning-400 border-warning-600", closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + title: "text-warning-600", + description: "text-warning-400", }, }, { variant: "faded", color: "danger", class: { - base: "bg-danger-50 text-danger-400 border-danger-400", + base: "bg-danger-50 text-danger-400 border-danger-600", closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + title: "text-danger-600", + description: "text-danger-400", }, }, // bordered and color @@ -195,41 +215,51 @@ const toast = tv({ variant: "bordered", color: "primary", class: { - base: "border-primary-400 text-primary-400", + base: "border-primary-400 text-primary-600", closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + title: "text-primary-600", + description: "text-primary-400", }, }, { variant: "bordered", color: "secondary", class: { - base: "border-secondary-400 text-secondary-400", + base: "border-secondary-400 text-secondary-600", closeButton: "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + title: "text-secondary-600", + description: "text-secondary-400", }, }, { variant: "bordered", color: "success", class: { - base: "border-success-400 text-success-400", + base: "border-success-400 text-success-600", closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + title: "text-success-600", + description: "text-success-400", }, }, { variant: "bordered", color: "warning", class: { - base: "border-warning-400 text-warning-400", + base: "border-warning-400 text-warning-600", closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + title: "text-warning-600", + description: "text-warning-400", }, }, { variant: "bordered", color: "danger", class: { - base: "border-danger-400 text-danger-400", + base: "border-danger-400 text-danger-600", closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + title: "text-danger-600", + description: "text-danger-400", }, }, // solid and color @@ -237,41 +267,51 @@ const toast = tv({ variant: "solid", color: "primary", class: { - base: "bg-primary-100 text-default-600", + base: "bg-primary-100 text-primary-600", closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + title: "text-primary-600", + description: "text-primary-400", }, }, { variant: "solid", color: "secondary", class: { - base: "bg-secondary-100 text-default-600", + base: "bg-secondary-100 text-secondary-600", closeButton: "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + title: "text-secondary-600", + description: "text-secondary-400", }, }, { variant: "solid", color: "success", class: { - base: "bg-success-100 text-default-600", + base: "bg-success-100 text-success-600", closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + title: "text-success-600", + description: "text-success-400", }, }, { variant: "solid", color: "warning", class: { - base: "bg-warning-100 text-default-600", + base: "bg-warning-100 text-warning-600", closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + title: "text-warning-600", + description: "text-warning-400", }, }, { variant: "solid", color: "danger", class: { - base: "bg-danger-100 text-default-600", + base: "bg-danger-100 text-danger-600", closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + title: "text-danger-600", + description: "text-danger-400", }, }, ], From e938e09365d2baaacfc9215eb1b1353b5885ee97 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Thu, 2 Jan 2025 18:21:49 +0530 Subject: [PATCH 19/49] chore: improving styles --- packages/components/toast/src/toast.tsx | 17 ++++++++++++----- packages/core/theme/src/components/toast.ts | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index d5ac7869ab..1d13ae2622 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -91,11 +91,11 @@ 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", + "right-bottom": "bottom-0 right-0 mx-auto w-max mr-2", + "left-bottom": "bottom-0 left-0 mx-auto w-max ml-2", "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", + "right-top": "top-0 right-0 mx-auto w-max mr-2", + "left-top": "top-0 left-0 mx-auto w-max ml-2", "center-top": "top-0 left-0 right-0 w-max mx-auto", }; const positionStyle = position ? positionStyles[position] : positionStyles["right-bottom"]; @@ -166,7 +166,14 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { setDrag(true); }} > - {toastContent} + + {toastContent} + )} diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index e273c4e95c..e56f4e5aa7 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -25,7 +25,7 @@ const toast = tv({ progressTrack: ["absolute h-[2px] left-0 -bottom-2 w-full bg-default-200"], progressIndicator: ["absolute h-[2px] left-0 bg-default-400"], closeButton: [ - "opacity-0 group-hover:opacity-100 w-4 h-4 min-w-4 p-0.5 absolute -right-1 -top-1 items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", + "opacity-0 group-hover:opacity-100 w-5 h-5 min-w-4 p-1 absolute -right-1 -top-1 items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", ], }, variants: { @@ -46,9 +46,9 @@ const toast = tv({ }, variant: { flat: "bg-default-50", - faded: "bg-default-50 border border-1 border-default-400", + faded: "bg-default-50 border border-1 border-default-200", solid: "bg-default-50 shadow-inner", - bordered: "bg-white dark:bg-black border border-1 border-default-400", + bordered: "bg-white dark:bg-black border border-1 border-default-200", }, color: { default: "", From 153857d054341e59fe2f0984e005643aed764ee3 Mon Sep 17 00:00:00 2001 From: Junior Garcia Date: Sun, 5 Jan 2025 09:44:46 -0300 Subject: [PATCH 20/49] chore: styles correction --- packages/core/theme/src/components/toast.ts | 24 ++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index e56f4e5aa7..f462b8c9fe 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -9,17 +9,16 @@ const toast = tv({ "group", "cursor-pointer", "relative", - "z-500", + "z-[9999]", "box-border", "outline-none", "p-3 mx-1", "my-1", "w-[210px] sm:w-[270px] md:w-[300px]", "min-h-4", - "drop-shadow", ], - title: ["font-medium", "text-sm", "me-4", "text-foreground"], - description: ["text-sm", "me-4", "text-default-600"], + title: ["font-medium", "text-small", "me-4", "text-foreground"], + description: ["text-small", "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"], @@ -45,7 +44,7 @@ const toast = tv({ }, }, variant: { - flat: "bg-default-50", + flat: "bg-content1", faded: "bg-default-50 border border-1 border-default-200", solid: "bg-default-50 shadow-inner", bordered: "bg-white dark:bg-black border border-1 border-default-200", @@ -99,11 +98,26 @@ const toast = tv({ closeButton: "transition-opacity ease-in duration-300", }, }, + shadow: { + none: { + base: "shadow-none", + }, + sm: { + base: "shadow-small", + }, + md: { + base: "shadow-medium", + }, + lg: { + base: "shadow-large", + }, + }, }, defaultVariants: { size: "md", variant: "flat", radius: "md", + shadow: "sm", }, compoundVariants: [ // flat and color From ad25bff487ab25d7b7244ccb61476750c3c8113a Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Mon, 6 Jan 2025 15:06:45 +0530 Subject: [PATCH 21/49] fix: adding junior's suggestions --- .../components/toast/__tests__/toast.test.tsx | 2 +- .../components/toast/src/toast-region.tsx | 7 +- packages/components/toast/src/toast.tsx | 91 ++-------------- packages/components/toast/src/use-toast.ts | 102 ++++++++++++++++++ .../toast/stories/toast.stories.tsx | 2 +- packages/core/theme/src/components/toast.ts | 63 ++++++++++- 6 files changed, 175 insertions(+), 92 deletions(-) diff --git a/packages/components/toast/__tests__/toast.test.tsx b/packages/components/toast/__tests__/toast.test.tsx index 201614cc05..42c1b7753d 100644 --- a/packages/components/toast/__tests__/toast.test.tsx +++ b/packages/components/toast/__tests__/toast.test.tsx @@ -114,7 +114,7 @@ describe("Toast", () => { const initialCloseButtons = wrapper.getAllByRole("button"); const initialButtonLength = initialCloseButtons.length; - await user.click(initialCloseButtons[initialButtonLength - 1]); + await user.click(initialCloseButtons[0]); const finalCloseButtons = wrapper.getAllByRole("button"); const finalButtonLength = finalCloseButtons.length; diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index d229793402..c520027a9a 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -1,7 +1,6 @@ import {useEffect, useRef, useState} from "react"; import {useToastRegion, AriaToastRegionProps} from "@react-aria/toast"; import {QueuedToast, ToastState} from "@react-stately/toast"; -import {createPortal} from "react-dom"; import {useHover} from "@react-aria/interactions"; import {mergeProps} from "@react-aria/utils"; import {clsx} from "@nextui-org/shared-utils"; @@ -70,11 +69,12 @@ export function ToastRegion({ setIsTouched(true); }; - return createPortal( + return (
{toastQueue.visibleToasts.map((toast: QueuedToast, index) => { @@ -102,7 +102,6 @@ export function ToastRegion({ return null; })} -
, - document.body, +
); } diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index 1d13ae2622..f78187ca63 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -9,8 +9,7 @@ import { LoadingIcon, } from "@nextui-org/shared-icons"; import {motion, AnimatePresence} from "framer-motion"; -import {cloneElement, isValidElement, useState} from "react"; -import {clsx} from "@nextui-org/shared-utils"; +import {cloneElement, isValidElement} from "react"; import {UseToastProps, useToast} from "./use-toast"; @@ -32,76 +31,29 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { endContent, color, hideIcon, - position, - toast, - state, disableAnimation, progressBarRef, classNames, slots, isProgressBarVisible, - total, - index, - isRegionExpanded, getToastProps, getContentProps, getTitleProps, getDescriptionProps, getCloseButtonProps, getIconProps, - liftHeight, - initialHeight, - frontHeight, + getMotionDivProps, + getCloseIconProps, isLoading, } = useToast({ ...props, ref, }); - const toastVariants = position.includes("bottom") - ? { - hidden: {opacity: 0, y: 50}, - visible: {opacity: 1, y: 0}, - exit: {opacity: 0, y: 50}, - } - : { - hidden: {opacity: 0, y: -50}, - visible: {opacity: 1, y: 0}, - exit: {opacity: 0, y: -50}, - }; - 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"); - const isLeft = position.includes("left"); - const isTop = position === "center-top"; - const isBottom = position === "center-bottom"; - - if ( - (isRight && offsetX >= 50) || - (isLeft && offsetX <= -50) || - (isTop && offsetY <= -50) || - (isBottom && offsetY >= 50) - ) { - state.close(toast.key); - } - }; - - const positionStyles: Record = { - "right-bottom": "bottom-0 right-0 mx-auto w-max mr-2", - "left-bottom": "bottom-0 left-0 mx-auto w-max ml-2", - "center-bottom": "bottom-0 left-0 right-0 w-max mx-auto", - "right-top": "top-0 right-0 mx-auto w-max mr-2", - "left-top": "top-0 left-0 mx-auto w-max ml-2", - "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 = (
@@ -121,8 +73,8 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { )}
- {endContent}
@@ -134,38 +86,7 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { toastContent ) : ( - { - setDrag(false); - const offsetX = info.offset.x; - const offsetY = info.offset.y; - - handleDragEnd(offsetX, offsetY); - }} - onDragStart={() => { - setDrag(true); - }} - > + (originalProps: UseToastProps) [objectToDeps(variantProps)], ); + const multiplier = position.includes("top") ? 1 : -1; + const toastVariants = position.includes("bottom") + ? { + hidden: {opacity: 0, y: 50}, + visible: {opacity: 1, y: 0}, + exit: {opacity: 0, y: 50}, + } + : { + hidden: {opacity: 0, y: -50}, + visible: {opacity: 1, y: 0}, + exit: {opacity: 0, y: -50}, + }; + const [drag, setDrag] = useState(false); + const handleDragEnd = (offsetX: number, offsetY: number) => { + const isRight = position.includes("right"); + const isLeft = position.includes("left"); + const isTop = position === "center-top"; + const isBottom = position === "center-bottom"; + + if ( + (isRight && offsetX >= 50) || + (isLeft && offsetX <= -50) || + (isTop && offsetY <= -50) || + (isBottom && offsetY >= 50) + ) { + state.close(toast.key); + } + }; + const getToastProps: PropGetter = useCallback( (props = {}) => ({ ref: domRef, @@ -311,6 +341,76 @@ export function useToast(originalProps: UseToastProps) [closeButtonProps], ); + const getCloseIconProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.closeIcon({class: classNames?.closeIcon}), + "aria-label": "close-icon", + ...props, + }), + [], + ); + + const getMotionDivProps = useCallback( + ( + props = {}, + ): MotionProps & { + "data-drag": string | boolean; + "data-position": string; + className: string; + } => { + const isCloseToEnd = total - index - 1 <= 2; + const dragDirection = position.includes("center") ? "y" : "x"; + const dragConstraints = {left: 0, right: 0, top: 0, bottom: 0}; + + return { + animate: { + opacity: isCloseToEnd ? 1 : 0, + pointerEvents: isCloseToEnd ? "all" : "none", + y: isRegionExpanded ? liftHeight * multiplier : (total - 1 - index) * 8 * multiplier, + scaleX: isRegionExpanded ? 1 : 1 - (total - 1 - index) * 0.1, + height: isRegionExpanded ? initialHeight : frontHeight, + }, + drag: dragDirection, + dragConstraints: dragConstraints, + exit: {opacity: 0, y: 100}, + initial: {opacity: 0, y: -40 * multiplier, scale: 1}, + transition: {duration: 0.3, ease: "easeOut"}, + variants: toastVariants, + onDragEnd: (_, info) => { + setDrag(false); + const {x: offsetX, y: offsetY} = info.offset; + + handleDragEnd(offsetX, offsetY); + }, + onDragStart: () => { + setDrag(true); + }, + "data-drag": dataAttr(drag), + "data-position": position, + className: slots.motionDiv({class: classNames?.motionDiv}), + ...props, + }; + }, + [ + closeButtonProps, + total, + index, + position, + isRegionExpanded, + liftHeight, + multiplier, + initialHeight, + frontHeight, + toastVariants, + classNames, + drag, + dataAttr, + setDrag, + handleDragEnd, + slots, + ], + ); + return { Component, title, @@ -333,6 +433,8 @@ export function useToast(originalProps: UseToastProps) getDescriptionProps, getCloseButtonProps, getIconProps, + getMotionDivProps, + getCloseIconProps, progressBarRef, endContent, slots, diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 29d0b849cc..60a2dd5334 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -15,7 +15,7 @@ export default { }, color: { control: {type: "select"}, - options: ["default", "primary", "secondary", "success", "warning", "danger"], + options: ["default", "foreground", "primary", "secondary", "success", "warning", "danger"], }, radius: { control: {type: "select"}, diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index f462b8c9fe..19f09829e5 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -23,8 +23,21 @@ const toast = tv({ 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"], progressIndicator: ["absolute h-[2px] left-0 bg-default-400"], + motionDiv: [ + "fixed", + "data-[drag=true]:before:content-[''] data-[drag=true]:before:absolute data-[drag=true]:before:left-0 data-[drag=true]:before:right-0 data-[drag=true]:before:h-full data-[drag=true]:before:-z-10", + "data-[position=right-bottom]:bottom-0 data-[position=right-bottom]:right-0 data-[position=right-bottom]:mx-auto data-[position=right-bottom]:w-max data-[position=right-bottom]:mr-2", + "data-[position=left-bottom]:bottom-0 data-[position=left-bottom]:left-0 data-[position=left-bottom]:mx-auto data-[position=left-bottom]:w-max data-[position=left-bottom]:ml-2", + "data-[position=center-bottom]:bottom-0 data-[position=center-bottom]:left-0 data-[position=center-bottom]:right-0 data-[position=center-bottom]:w-max data-[position=center-bottom]:mx-auto", + "data-[position=right-top]:top-0 data-[position=right-top]:right-0 data-[position=right-top]:mx-auto data-[position=right-top]:w-max data-[position=right-top]:mr-2", + "data-[position=left-top]:top-0 data-[position=left-top]:left-0 data-[position=left-top]:mx-auto data-[position=left-top]:w-max data-[position=left-top]:ml-2", + "data-[position=center-top]:top-0 data-[position=center-top]:left-0 data-[position=center-top]:right-0 data-[position=center-top]:w-max data-[position=center-top]:mx-auto", + ], closeButton: [ - "opacity-0 group-hover:opacity-100 w-5 h-5 min-w-4 p-1 absolute -right-1 -top-1 items-center justify-center bg-default-100 hover:bg-default-200 text-default-400 hover:text-default-600 border border-1 border-default-400", + "opacity-0 p-0 group-hover:opacity-100 w-6 h-6 min-w-4 absolute -right-2 -top-2 items-center justify-center bg-transparent text-default-400 hover:text-default-600 border border-3 border-transparent", + ], + closeIcon: [ + "rounded-full w-full h-full p-0.5 border border-1 border-default-400 bg-default-100", ], }, variants: { @@ -51,6 +64,10 @@ const toast = tv({ }, color: { default: "", + foreground: { + progressTrack: "bg-foreground-200", + progressIndicator: "bg-foreground-400", + }, primary: { progressTrack: "bg-primary-200", progressIndicator: "bg-primary-400", @@ -121,6 +138,17 @@ const toast = tv({ }, compoundVariants: [ // flat and color + { + variant: "flat", + color: "foreground", + class: { + base: "bg-foreground-50 text-foreground-600", + closeButton: + "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + title: "text-foreground-600", + description: "text-foreground-400", + }, + }, { variant: "flat", color: "primary", @@ -173,6 +201,17 @@ const toast = tv({ }, }, // faded and color + { + variant: "faded", + color: "foreground", + class: { + base: "bg-foreground-50 text-foreground-400 border-foreground-600", + closeButton: + "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + title: "text-foreground-600", + description: "text-foreground-400", + }, + }, { variant: "faded", color: "primary", @@ -235,6 +274,17 @@ const toast = tv({ description: "text-primary-400", }, }, + { + variant: "bordered", + color: "foreground", + class: { + base: "border-foreground-400 text-foreground-600", + closeButton: + "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + title: "text-foreground-600", + description: "text-foreground-400", + }, + }, { variant: "bordered", color: "secondary", @@ -277,6 +327,17 @@ const toast = tv({ }, }, // solid and color + { + variant: "solid", + color: "foreground", + class: { + base: "bg-foreground-100 text-foreground-600", + closeButton: + "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + title: "text-foreground-600", + description: "text-foreground-400", + }, + }, { variant: "solid", color: "primary", From 4a79ed7c3f155fc8a196c1439ff54d496f7fecde Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Mon, 6 Jan 2025 18:47:29 +0530 Subject: [PATCH 22/49] chore: correcting styles --- packages/core/theme/src/components/toast.ts | 96 ++++++++++++--------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 19f09829e5..a20c127cd8 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -143,8 +143,8 @@ const toast = tv({ color: "foreground", class: { base: "bg-foreground-50 text-foreground-600", - closeButton: - "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + closeButton: "text-foreground-400 hover:text-foreground-600", + closeIcon: "border border-1 border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -154,7 +154,8 @@ const toast = tv({ color: "primary", class: { base: "bg-primary-50 text-primary-600", - closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + closeButton: "text-primary-400 hover:text-primary-600", + closeIcon: "border border-1 border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -164,8 +165,8 @@ const toast = tv({ color: "secondary", class: { base: "bg-secondary-50 text-secondary-600", - closeButton: - "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + closeButton: "text-secondary-400 hover:text-secondary-600", + closeIcon: "border border-1 border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -175,7 +176,8 @@ const toast = tv({ color: "success", class: { base: "bg-success-50 text-success-600", - closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + closeButton: "text-success-400 hover:text-success-600", + closeIcon: "border border-1 border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -185,7 +187,8 @@ const toast = tv({ color: "warning", class: { base: "bg-warning-50 text-warning-600", - closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + closeButton: "text-warning-400 hover:text-warning-600", + closeIcon: "border border-1 border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -195,7 +198,8 @@ const toast = tv({ color: "danger", class: { base: "bg-danger-50 text-danger-600", - closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + closeButton: "text-danger-400 hover:text-danger-600", + closeIcon: "border border-1 border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, @@ -206,8 +210,8 @@ const toast = tv({ color: "foreground", class: { base: "bg-foreground-50 text-foreground-400 border-foreground-600", - closeButton: - "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + closeButton: "text-foreground-400 hover:text-foreground-600", + closeIcon: "border border-1 border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -217,7 +221,8 @@ const toast = tv({ color: "primary", class: { base: "bg-primary-50 text-primary-400 border-primary-600", - closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + closeButton: "text-primary-400 hover:text-primary-600", + closeIcon: "border border-1 border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -227,8 +232,8 @@ const toast = tv({ color: "secondary", class: { base: "bg-secondary-50 text-secondary-400 border-secondary-600", - closeButton: - "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + closeButton: "text-secondary-400 hover:text-secondary-600", + closeIcon: "border border-1 border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -238,7 +243,8 @@ const toast = tv({ color: "success", class: { base: "bg-success-50 text-success-400 border-success-600", - closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + closeButton: "text-success-400 hover:text-success-600", + closeIcon: "border border-1 border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -248,7 +254,8 @@ const toast = tv({ color: "warning", class: { base: "bg-warning-50 text-warning-400 border-warning-600", - closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + closeButton: "text-warning-400 hover:text-warning-600", + closeIcon: "border border-1 border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -258,7 +265,8 @@ const toast = tv({ color: "danger", class: { base: "bg-danger-50 text-danger-400 border-danger-600", - closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + closeButton: "text-danger-400 hover:text-danger-600", + closeIcon: "border border-1 border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, @@ -266,23 +274,24 @@ const toast = tv({ // bordered and color { variant: "bordered", - color: "primary", + color: "foreground", class: { - base: "border-primary-400 text-primary-600", - closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", - title: "text-primary-600", - description: "text-primary-400", + base: "border-foreground-400 text-foreground-600", + closeButton: "text-foreground-400 hover:text-foreground-600", + closeIcon: "border border-1 border-foreground-400 bg-foreground-100", + title: "text-foreground-600", + description: "text-foreground-400", }, }, { variant: "bordered", - color: "foreground", + color: "primary", class: { - base: "border-foreground-400 text-foreground-600", - closeButton: - "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", - title: "text-foreground-600", - description: "text-foreground-400", + base: "border-primary-400 text-primary-600", + closeButton: "text-primary-400 hover:text-primary-600", + closeIcon: "border border-1 border-primary-400 bg-primary-100", + title: "text-primary-600", + description: "text-primary-400", }, }, { @@ -290,8 +299,8 @@ const toast = tv({ color: "secondary", class: { base: "border-secondary-400 text-secondary-600", - closeButton: - "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + closeButton: "text-secondary-400 hover:text-secondary-600", + closeIcon: "border border-1 border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -301,7 +310,8 @@ const toast = tv({ color: "success", class: { base: "border-success-400 text-success-600", - closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + closeButton: "text-success-400 hover:text-success-600", + closeIcon: "border border-1 border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -311,7 +321,8 @@ const toast = tv({ color: "warning", class: { base: "border-warning-400 text-warning-600", - closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + closeButton: "text-warning-400 hover:text-warning-600", + closeIcon: "border border-1 border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -321,7 +332,8 @@ const toast = tv({ color: "danger", class: { base: "border-danger-400 text-danger-600", - closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + closeButton: "text-danger-400 hover:text-danger-600", + closeIcon: "border border-1 border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, @@ -332,8 +344,8 @@ const toast = tv({ color: "foreground", class: { base: "bg-foreground-100 text-foreground-600", - closeButton: - "bg-foreground-100 hover:bg-foreground-200 border-foreground-400 text-foreground-400", + closeButton: "text-foreground-400 hover:text-foreground-600", + closeIcon: "border border-1 border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -343,7 +355,8 @@ const toast = tv({ color: "primary", class: { base: "bg-primary-100 text-primary-600", - closeButton: "bg-primary-100 hover:bg-primary-200 border-primary-400 text-primary-400", + closeButton: "text-primary-400 hover:text-primary-600", + closeIcon: "border border-1 border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -353,8 +366,8 @@ const toast = tv({ color: "secondary", class: { base: "bg-secondary-100 text-secondary-600", - closeButton: - "bg-secondary-100 hover:bg-secondary-200 border-secondary-400 text-secondary-400", + closeButton: "text-secondary-400 hover:text-secondary-600", + closeIcon: "border border-1 border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -364,7 +377,8 @@ const toast = tv({ color: "success", class: { base: "bg-success-100 text-success-600", - closeButton: "bg-success-100 hover:bg-success-200 border-success-400 text-success-400", + closeButton: "text-success-400 hover:text-success-600", + closeIcon: "border border-1 border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -374,7 +388,8 @@ const toast = tv({ color: "warning", class: { base: "bg-warning-100 text-warning-600", - closeButton: "bg-warning-100 hover:bg-warning-200 border-warning-400 text-warning-400", + closeButton: "text-warning-400 hover:text-warning-600", + closeIcon: "border border-1 border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -384,7 +399,8 @@ const toast = tv({ color: "danger", class: { base: "bg-danger-100 text-danger-600", - closeButton: "bg-danger-100 hover:bg-danger-200 border-danger-400 text-danger-400", + closeButton: "text-danger-400 hover:text-danger-600", + closeIcon: "border border-1 border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, From db3ad3a6786631b38329320079d220ffd5b998bc Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 13:05:49 +0530 Subject: [PATCH 23/49] fix: fixing the timer behavior --- .../components/toast/src/toast-provider.tsx | 1 - packages/components/toast/src/use-toast.ts | 82 +++++++++---------- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx index 94ce305b06..ef064fbf66 100644 --- a/packages/components/toast/src/toast-provider.tsx +++ b/packages/components/toast/src/toast-provider.tsx @@ -57,7 +57,6 @@ export const addToast = ({...props}: ToastProps & ToastOptions) => { } const options: Partial = { - timeout: props?.timeout, priority: props?.priority, }; diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index f505a5cd93..a663ed92c8 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -9,6 +9,7 @@ import {useToast as useToastAria, AriaToastProps} from "@react-aria/toast"; import {mergeProps} from "@react-aria/utils"; import {QueuedToast, ToastState} from "@react-stately/toast"; import {MotionProps} from "framer-motion"; +import {useHover} from "@react-aria/interactions"; export interface ToastProps extends ToastVariantProps { /** @@ -70,6 +71,10 @@ export interface ToastProps extends ToastVariantProps { * @default false */ hideIcon?: boolean; + /** + * Time to auto-close the toast. + */ + timeout?: number; /** * Position of the toast in the view-port. */ @@ -101,8 +106,30 @@ export type UseToastProps = Props & export function useToast(originalProps: UseToastProps) { const [props, variantProps] = mapPropsVariants(originalProps, toastTheme.variantKeys); + const { + ref, + as, + title, + description, + className, + classNames, + toast, + endContent, + hideIcon = false, + position = "right-bottom", + isRegionExpanded, + state, + total = 1, + index = 0, + heights, + promise: promiseProp, + setHeights, + ...otherProps + } = props; - const [isToastHovered, setIsToastHovered] = useState(false); + const {isHovered: isToastHovered, hoverProps} = useHover({ + isDisabled: false, + }); const disableAnimation = originalProps.disableAnimation; const animationRef = useRef(null); @@ -110,10 +137,11 @@ export function useToast(originalProps: UseToastProps) const progressRef = useRef(0); const progressBarRef = useRef(null); const pausedTime = useRef(0); + const timeElapsed = useRef(0); useEffect(() => { const updateProgress = (timestamp: number) => { - const timeout = props.toast.timeout; + const timeout = props.timeout; if (!timeout) { return; @@ -123,7 +151,7 @@ export function useToast(originalProps: UseToastProps) startTime.current = timestamp; } - if (isToastHovered) { + if (isToastHovered || isRegionExpanded || index != total - 1) { pausedTime.current += timestamp - startTime.current; startTime.current = null; animationRef.current = requestAnimationFrame(updateProgress); @@ -133,6 +161,11 @@ export function useToast(originalProps: UseToastProps) const elapsed = timestamp - startTime.current + pausedTime.current; + timeElapsed.current = elapsed; + if (timeElapsed.current >= timeout) { + props.state.close(toast.key); + } + progressRef.current = Math.min((elapsed / timeout) * 100, 100); if (progressBarRef.current) { @@ -151,28 +184,7 @@ export function useToast(originalProps: UseToastProps) cancelAnimationFrame(animationRef.current); } }; - }, [props.toast.timeout, isToastHovered]); - - const { - ref, - as, - title, - description, - className, - classNames, - toast, - endContent, - hideIcon = false, - position = "right-bottom", - isRegionExpanded, - state, - total = 1, - index = 0, - heights, - promise: promiseProp, - setHeights, - ...otherProps - } = props; + }, [props.timeout, isToastHovered, index, total, isRegionExpanded]); const [isLoading, setIsLoading] = useState(!!promiseProp); @@ -278,26 +290,12 @@ export function useToast(originalProps: UseToastProps) (props = {}) => ({ ref: domRef, className: slots.base({class: clsx(baseStyles, classNames?.base)}), - onPointerEnter: () => { - if (!toast.timer) { - return; - } - setIsToastHovered(true); - toast.timer.pause(); - }, - onPointerLeave: () => { - if (!toast.timer) { - return; - } - setIsToastHovered(false); - toast.timer.resume(); - }, "data-has-title": dataAttr(!isEmpty(title)), "data-has-description": dataAttr(!isEmpty(description)), "data-toast": true, - ...mergeProps(props, otherProps, toastProps), + ...mergeProps(props, otherProps, toastProps, hoverProps), }), - [slots, classNames, toastProps], + [slots, classNames, toastProps, hoverProps], ); const getIconProps: PropGetter = useCallback( @@ -424,7 +422,7 @@ export function useToast(originalProps: UseToastProps) state, toast: props.toast, disableAnimation, - isProgressBarVisible: !!props.toast.timeout, + isProgressBarVisible: !!props.timeout, total, index, getToastProps, From 5d76c683a97f0749787d4a0ec6869fcf9ba0ad27 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 14:22:34 +0530 Subject: [PATCH 24/49] chore: adding the spinner to the toast --- packages/components/toast/src/toast.tsx | 17 ++++++++-- packages/components/toast/src/use-toast.ts | 15 +++++++++ packages/core/theme/src/components/toast.ts | 2 ++ packages/utilities/shared-icons/src/index.ts | 1 - .../utilities/shared-icons/src/loading.tsx | 31 ------------------- 5 files changed, 31 insertions(+), 35 deletions(-) delete mode 100644 packages/utilities/shared-icons/src/loading.tsx diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index f78187ca63..8142375833 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -6,11 +6,12 @@ import { InfoFilledIcon, SuccessIcon, WarningIcon, - LoadingIcon, } from "@nextui-org/shared-icons"; import {motion, AnimatePresence} from "framer-motion"; import {cloneElement, isValidElement} from "react"; +import {Spinner} from "../../spinner/src"; + import {UseToastProps, useToast} from "./use-toast"; export interface ToastProps extends UseToastProps {} @@ -27,6 +28,7 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { const { Component, icon, + loadingIcon, domRef, endContent, color, @@ -44,6 +46,7 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { getIconProps, getMotionDivProps, getCloseIconProps, + getLoadingIconProps, isLoading, } = useToast({ ...props, @@ -52,14 +55,22 @@ 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 customLoadingIcon = + loadingIcon && isValidElement(loadingIcon) + ? cloneElement(loadingIcon, getLoadingIconProps()) + : null; + const loadingIconComponent = isLoading + ? customLoadingIcon || ( + + ) + : null; const toastContent = (
{hideIcon && !isLoading ? null - : loadingIcon || customIcon || } + : loadingIconComponent || 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 a663ed92c8..18c9be198e 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -66,6 +66,10 @@ export interface ToastProps extends ToastVariantProps { * Icon to be displayed in the toast - overrides the default icon */ icon?: ReactNode; + /** + * Icon to be displayed in the loading toast - overrides the loading icon + */ + loadingIcon?: ReactNode; /** * Whether the toast-icon should be hidden. * @default false @@ -197,6 +201,7 @@ export function useToast(originalProps: UseToastProps) const Component = as || "div"; const icon: ReactNode = props.icon; + const loadingIcon: ReactNode = props.icon; const domRef = useDOMRef(ref); const baseStyles = clsx(className, classNames?.base); @@ -306,6 +311,14 @@ export function useToast(originalProps: UseToastProps) [], ); + const getLoadingIconProps: PropGetter = useCallback( + (props = {}) => ({ + className: slots.loadingIcon({class: classNames?.loadingIcon}), + ...props, + }), + [], + ); + const getContentProps: PropGetter = useCallback( (props = {}) => ({ className: slots.content({class: classNames?.content}), @@ -414,6 +427,7 @@ export function useToast(originalProps: UseToastProps) title, description, icon, + loadingIcon, domRef, classNames, color: variantProps["color"], @@ -433,6 +447,7 @@ export function useToast(originalProps: UseToastProps) getIconProps, getMotionDivProps, getCloseIconProps, + getLoadingIconProps, progressBarRef, endContent, slots, diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index a20c127cd8..c88355f8ff 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -20,6 +20,7 @@ const toast = tv({ title: ["font-medium", "text-small", "me-4", "text-foreground"], description: ["text-small", "me-4", "text-default-600"], icon: ["w-6 h-6 fill-current"], + loadingIcon: ["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"], progressIndicator: ["absolute h-[2px] left-0 bg-default-400"], @@ -44,6 +45,7 @@ const toast = tv({ size: { sm: { icon: "w-4 h-4", + loadingIcon: "w-4 h-4", title: "text-sm font-medium", description: "text-xs font-light", }, diff --git a/packages/utilities/shared-icons/src/index.ts b/packages/utilities/shared-icons/src/index.ts index 3a07b8aa00..664f7da714 100644 --- a/packages/utilities/shared-icons/src/index.ts +++ b/packages/utilities/shared-icons/src/index.ts @@ -38,7 +38,6 @@ 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 deleted file mode 100644 index 4f44f83c86..0000000000 --- a/packages/utilities/shared-icons/src/loading.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import {IconSvgProps} from "./types"; - -export const LoadingIcon = ( - props: IconSvgProps & { - className?: string; - }, -) => { - return ( - - - - - - ); -}; From 5b0f42413614887218e58f1183c16b5933e1e8e4 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 15:21:35 +0530 Subject: [PATCH 25/49] chore: full width for mobile --- packages/components/toast/src/use-toast.ts | 15 +++++++++++---- packages/core/theme/src/components/toast.ts | 10 ++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 18c9be198e..4d2ca6c9a8 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -6,7 +6,7 @@ import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; import {clsx, dataAttr, isEmpty, objectToDeps} from "@nextui-org/shared-utils"; import {ReactNode, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from "react"; import {useToast as useToastAria, AriaToastProps} from "@react-aria/toast"; -import {mergeProps} from "@react-aria/utils"; +import {mergeProps, isAndroid, isIPhone} from "@react-aria/utils"; import {QueuedToast, ToastState} from "@react-stately/toast"; import {MotionProps} from "framer-motion"; import {useHover} from "@react-aria/interactions"; @@ -120,7 +120,7 @@ export function useToast(originalProps: UseToastProps) toast, endContent, hideIcon = false, - position = "right-bottom", + position: positionProp, isRegionExpanded, state, total = 1, @@ -131,6 +131,13 @@ export function useToast(originalProps: UseToastProps) ...otherProps } = props; + const isMobile = isIPhone() || isAndroid(); + const position = isMobile + ? positionProp?.includes("top") + ? "top" + : "bottom" + : positionProp ?? "right-bottom"; + const {isHovered: isToastHovered, hoverProps} = useHover({ isDisabled: false, }); @@ -278,8 +285,8 @@ export function useToast(originalProps: UseToastProps) const handleDragEnd = (offsetX: number, offsetY: number) => { const isRight = position.includes("right"); const isLeft = position.includes("left"); - const isTop = position === "center-top"; - const isBottom = position === "center-bottom"; + const isTop = position.includes("top"); + const isBottom = position.includes("bottom"); if ( (isRight && offsetX >= 50) || diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index c88355f8ff..b777bf2465 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -12,9 +12,9 @@ const toast = tv({ "z-[9999]", "box-border", "outline-none", - "p-3 mx-1", + "p-3 sm:mx-1", "my-1", - "w-[210px] sm:w-[270px] md:w-[300px]", + "w-full sm:w-[270px] md:w-[300px]", "min-h-4", ], title: ["font-medium", "text-small", "me-4", "text-foreground"], @@ -33,6 +33,8 @@ const toast = tv({ "data-[position=right-top]:top-0 data-[position=right-top]:right-0 data-[position=right-top]:mx-auto data-[position=right-top]:w-max data-[position=right-top]:mr-2", "data-[position=left-top]:top-0 data-[position=left-top]:left-0 data-[position=left-top]:mx-auto data-[position=left-top]:w-max data-[position=left-top]:ml-2", "data-[position=center-top]:top-0 data-[position=center-top]:left-0 data-[position=center-top]:right-0 data-[position=center-top]:w-max data-[position=center-top]:mx-auto", + "data-[position=bottom]:bottom-0 data-[position=bottom]:left-0 data-[position=bottom]:right-0 w-full px-2", + "data-[position=top]:top-0 data-[position=top]:left-0 data-[position=top]:right-0 w-full px-2", ], closeButton: [ "opacity-0 p-0 group-hover:opacity-100 w-6 h-6 min-w-4 absolute -right-2 -top-2 items-center justify-center bg-transparent text-default-400 hover:text-default-600 border border-3 border-transparent", @@ -44,8 +46,8 @@ const toast = tv({ variants: { size: { sm: { - icon: "w-4 h-4", - loadingIcon: "w-4 h-4", + icon: "w-5 h-5", + loadingIcon: "w-5 h-5", title: "text-sm font-medium", description: "text-xs font-light", }, From db7dd1349fd41c496d2093c90f5ae2cd6b6359bf Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 15:49:57 +0530 Subject: [PATCH 26/49] chore: modifying styles --- packages/components/toast/src/toast.tsx | 16 ++-- packages/core/theme/src/components/toast.ts | 83 ++++++++++----------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index 8142375833..82ccda5d8e 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -74,16 +74,16 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => {
{props.toast.content.title}
{props.toast.content.description}
- {isProgressBarVisible && ( -
-
-
- )}
+ {isProgressBarVisible && ( +
+
+
+ )} diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index b777bf2465..649e19e6a6 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -22,8 +22,8 @@ const toast = tv({ icon: ["w-6 h-6 fill-current"], loadingIcon: ["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"], - progressIndicator: ["absolute h-[2px] left-0 bg-default-400"], + progressTrack: ["absolute top-0 inset-0 bg-transparent overflow-hidden"], + progressIndicator: ["h-full bg-default-400 opacity-20"], motionDiv: [ "fixed", "data-[drag=true]:before:content-[''] data-[drag=true]:before:absolute data-[drag=true]:before:left-0 data-[drag=true]:before:right-0 data-[drag=true]:before:h-full data-[drag=true]:before:-z-10", @@ -39,9 +39,7 @@ const toast = tv({ closeButton: [ "opacity-0 p-0 group-hover:opacity-100 w-6 h-6 min-w-4 absolute -right-2 -top-2 items-center justify-center bg-transparent text-default-400 hover:text-default-600 border border-3 border-transparent", ], - closeIcon: [ - "rounded-full w-full h-full p-0.5 border border-1 border-default-400 bg-default-100", - ], + closeIcon: ["rounded-full w-full h-full p-0.5 border border-default-400 bg-default-100"], }, variants: { size: { @@ -62,53 +60,52 @@ const toast = tv({ }, variant: { flat: "bg-content1", - faded: "bg-default-50 border border-1 border-default-200", + faded: "bg-default-50 border border-default-200", solid: "bg-default-50 shadow-inner", - bordered: "bg-white dark:bg-black border border-1 border-default-200", + bordered: "bg-white dark:bg-black border border-default-200", }, color: { default: "", foreground: { - progressTrack: "bg-foreground-200", - progressIndicator: "bg-foreground-400", + progressIndicator: "h-full opacity-20 bg-foreground-400", }, primary: { - progressTrack: "bg-primary-200", - progressIndicator: "bg-primary-400", + progressIndicator: "h-full opacity-20 bg-primary-400", }, secondary: { - progressTrack: "bg-secondary-200", - progressIndicator: "bg-secondary-400", + progressIndicator: "h-full opacity-20 bg-secondary-400", }, success: { - progressTrack: "bg-success-200", - progressIndicator: "bg-success-400", + progressIndicator: "h-full opacity-20 bg-success-400", }, warning: { - progressTrack: "bg-warning-200", - progressIndicator: "bg-warning-400", + progressIndicator: "h-full opacity-20 bg-warning-400", }, danger: { - progressTrack: "bg-danger-200", - progressIndicator: "bg-danger-400", + progressIndicator: "h-full opacity-20 bg-danger-400", }, }, radius: { none: { base: "rounded-none", + progressTrack: "rounded-none", }, sm: { base: "rounded-small", + progressTrack: "rounded-small", }, md: { base: "rounded-medium", + progressTrack: "rounded-medium", }, lg: { base: "rounded-large", + progressTrack: "rounded-large", }, full: { base: "rounded-full", closeButton: "top-0 right-px", + progressTrack: "rounded-full", }, }, disableAnimation: { @@ -148,7 +145,7 @@ const toast = tv({ class: { base: "bg-foreground-50 text-foreground-600", closeButton: "text-foreground-400 hover:text-foreground-600", - closeIcon: "border border-1 border-foreground-400 bg-foreground-100", + closeIcon: "border border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -159,7 +156,7 @@ const toast = tv({ class: { base: "bg-primary-50 text-primary-600", closeButton: "text-primary-400 hover:text-primary-600", - closeIcon: "border border-1 border-primary-400 bg-primary-100", + closeIcon: "border border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -170,7 +167,7 @@ const toast = tv({ class: { base: "bg-secondary-50 text-secondary-600", closeButton: "text-secondary-400 hover:text-secondary-600", - closeIcon: "border border-1 border-secondary-400 bg-secondary-100", + closeIcon: "border border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -181,7 +178,7 @@ const toast = tv({ class: { base: "bg-success-50 text-success-600", closeButton: "text-success-400 hover:text-success-600", - closeIcon: "border border-1 border-success-400 bg-success-100", + closeIcon: "border border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -192,7 +189,7 @@ const toast = tv({ class: { base: "bg-warning-50 text-warning-600", closeButton: "text-warning-400 hover:text-warning-600", - closeIcon: "border border-1 border-warning-400 bg-warning-100", + closeIcon: "border border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -203,7 +200,7 @@ const toast = tv({ class: { base: "bg-danger-50 text-danger-600", closeButton: "text-danger-400 hover:text-danger-600", - closeIcon: "border border-1 border-danger-400 bg-danger-100", + closeIcon: "border border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, @@ -215,7 +212,7 @@ const toast = tv({ class: { base: "bg-foreground-50 text-foreground-400 border-foreground-600", closeButton: "text-foreground-400 hover:text-foreground-600", - closeIcon: "border border-1 border-foreground-400 bg-foreground-100", + closeIcon: "border border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -226,7 +223,7 @@ const toast = tv({ class: { base: "bg-primary-50 text-primary-400 border-primary-600", closeButton: "text-primary-400 hover:text-primary-600", - closeIcon: "border border-1 border-primary-400 bg-primary-100", + closeIcon: "border border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -237,7 +234,7 @@ const toast = tv({ class: { base: "bg-secondary-50 text-secondary-400 border-secondary-600", closeButton: "text-secondary-400 hover:text-secondary-600", - closeIcon: "border border-1 border-secondary-400 bg-secondary-100", + closeIcon: "border border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -248,7 +245,7 @@ const toast = tv({ class: { base: "bg-success-50 text-success-400 border-success-600", closeButton: "text-success-400 hover:text-success-600", - closeIcon: "border border-1 border-success-400 bg-success-100", + closeIcon: "border border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -259,7 +256,7 @@ const toast = tv({ class: { base: "bg-warning-50 text-warning-400 border-warning-600", closeButton: "text-warning-400 hover:text-warning-600", - closeIcon: "border border-1 border-warning-400 bg-warning-100", + closeIcon: "border border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -270,7 +267,7 @@ const toast = tv({ class: { base: "bg-danger-50 text-danger-400 border-danger-600", closeButton: "text-danger-400 hover:text-danger-600", - closeIcon: "border border-1 border-danger-400 bg-danger-100", + closeIcon: "border border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, @@ -282,7 +279,7 @@ const toast = tv({ class: { base: "border-foreground-400 text-foreground-600", closeButton: "text-foreground-400 hover:text-foreground-600", - closeIcon: "border border-1 border-foreground-400 bg-foreground-100", + closeIcon: "border border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -293,7 +290,7 @@ const toast = tv({ class: { base: "border-primary-400 text-primary-600", closeButton: "text-primary-400 hover:text-primary-600", - closeIcon: "border border-1 border-primary-400 bg-primary-100", + closeIcon: "border border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -304,7 +301,7 @@ const toast = tv({ class: { base: "border-secondary-400 text-secondary-600", closeButton: "text-secondary-400 hover:text-secondary-600", - closeIcon: "border border-1 border-secondary-400 bg-secondary-100", + closeIcon: "border border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -315,7 +312,7 @@ const toast = tv({ class: { base: "border-success-400 text-success-600", closeButton: "text-success-400 hover:text-success-600", - closeIcon: "border border-1 border-success-400 bg-success-100", + closeIcon: "border border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -326,7 +323,7 @@ const toast = tv({ class: { base: "border-warning-400 text-warning-600", closeButton: "text-warning-400 hover:text-warning-600", - closeIcon: "border border-1 border-warning-400 bg-warning-100", + closeIcon: "border border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -337,7 +334,7 @@ const toast = tv({ class: { base: "border-danger-400 text-danger-600", closeButton: "text-danger-400 hover:text-danger-600", - closeIcon: "border border-1 border-danger-400 bg-danger-100", + closeIcon: "border border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, @@ -349,7 +346,7 @@ const toast = tv({ class: { base: "bg-foreground-100 text-foreground-600", closeButton: "text-foreground-400 hover:text-foreground-600", - closeIcon: "border border-1 border-foreground-400 bg-foreground-100", + closeIcon: "border border-foreground-400 bg-foreground-100", title: "text-foreground-600", description: "text-foreground-400", }, @@ -360,7 +357,7 @@ const toast = tv({ class: { base: "bg-primary-100 text-primary-600", closeButton: "text-primary-400 hover:text-primary-600", - closeIcon: "border border-1 border-primary-400 bg-primary-100", + closeIcon: "border border-primary-400 bg-primary-100", title: "text-primary-600", description: "text-primary-400", }, @@ -371,7 +368,7 @@ const toast = tv({ class: { base: "bg-secondary-100 text-secondary-600", closeButton: "text-secondary-400 hover:text-secondary-600", - closeIcon: "border border-1 border-secondary-400 bg-secondary-100", + closeIcon: "border border-secondary-400 bg-secondary-100", title: "text-secondary-600", description: "text-secondary-400", }, @@ -382,7 +379,7 @@ const toast = tv({ class: { base: "bg-success-100 text-success-600", closeButton: "text-success-400 hover:text-success-600", - closeIcon: "border border-1 border-success-400 bg-success-100", + closeIcon: "border border-success-400 bg-success-100", title: "text-success-600", description: "text-success-400", }, @@ -393,7 +390,7 @@ const toast = tv({ class: { base: "bg-warning-100 text-warning-600", closeButton: "text-warning-400 hover:text-warning-600", - closeIcon: "border border-1 border-warning-400 bg-warning-100", + closeIcon: "border border-warning-400 bg-warning-100", title: "text-warning-600", description: "text-warning-400", }, @@ -404,7 +401,7 @@ const toast = tv({ class: { base: "bg-danger-100 text-danger-600", closeButton: "text-danger-400 hover:text-danger-600", - closeIcon: "border border-1 border-danger-400 bg-danger-100", + closeIcon: "border border-danger-400 bg-danger-100", title: "text-danger-600", description: "text-danger-400", }, From 0fa2031e928c0478adbde0b6ee1041e4598268e3 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 16:23:35 +0530 Subject: [PATCH 27/49] chore: fixing the positions on smaller devices --- packages/components/toast/src/use-toast.ts | 11 ++--------- packages/core/theme/src/components/toast.ts | 15 +++++++-------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 4d2ca6c9a8..74e681f0a9 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -6,7 +6,7 @@ import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; import {clsx, dataAttr, isEmpty, objectToDeps} from "@nextui-org/shared-utils"; import {ReactNode, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from "react"; import {useToast as useToastAria, AriaToastProps} from "@react-aria/toast"; -import {mergeProps, isAndroid, isIPhone} from "@react-aria/utils"; +import {mergeProps} from "@react-aria/utils"; import {QueuedToast, ToastState} from "@react-stately/toast"; import {MotionProps} from "framer-motion"; import {useHover} from "@react-aria/interactions"; @@ -120,7 +120,7 @@ export function useToast(originalProps: UseToastProps) toast, endContent, hideIcon = false, - position: positionProp, + position = "right-bottom", isRegionExpanded, state, total = 1, @@ -131,13 +131,6 @@ export function useToast(originalProps: UseToastProps) ...otherProps } = props; - const isMobile = isIPhone() || isAndroid(); - const position = isMobile - ? positionProp?.includes("top") - ? "top" - : "bottom" - : positionProp ?? "right-bottom"; - const {isHovered: isToastHovered, hoverProps} = useHover({ isDisabled: false, }); diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 649e19e6a6..b3ed32b456 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -26,15 +26,14 @@ const toast = tv({ progressIndicator: ["h-full bg-default-400 opacity-20"], motionDiv: [ "fixed", + "px-4 sm:px-0", "data-[drag=true]:before:content-[''] data-[drag=true]:before:absolute data-[drag=true]:before:left-0 data-[drag=true]:before:right-0 data-[drag=true]:before:h-full data-[drag=true]:before:-z-10", - "data-[position=right-bottom]:bottom-0 data-[position=right-bottom]:right-0 data-[position=right-bottom]:mx-auto data-[position=right-bottom]:w-max data-[position=right-bottom]:mr-2", - "data-[position=left-bottom]:bottom-0 data-[position=left-bottom]:left-0 data-[position=left-bottom]:mx-auto data-[position=left-bottom]:w-max data-[position=left-bottom]:ml-2", - "data-[position=center-bottom]:bottom-0 data-[position=center-bottom]:left-0 data-[position=center-bottom]:right-0 data-[position=center-bottom]:w-max data-[position=center-bottom]:mx-auto", - "data-[position=right-top]:top-0 data-[position=right-top]:right-0 data-[position=right-top]:mx-auto data-[position=right-top]:w-max data-[position=right-top]:mr-2", - "data-[position=left-top]:top-0 data-[position=left-top]:left-0 data-[position=left-top]:mx-auto data-[position=left-top]:w-max data-[position=left-top]:ml-2", - "data-[position=center-top]:top-0 data-[position=center-top]:left-0 data-[position=center-top]:right-0 data-[position=center-top]:w-max data-[position=center-top]:mx-auto", - "data-[position=bottom]:bottom-0 data-[position=bottom]:left-0 data-[position=bottom]:right-0 w-full px-2", - "data-[position=top]:top-0 data-[position=top]:left-0 data-[position=top]:right-0 w-full px-2", + "data-[position=right-bottom]:bottom-0 data-[position=right-bottom]:right-0 data-[position=right-bottom]:mx-auto w-full sm:data-[position=right-bottom]:w-max mb-1 sm:data-[position=right-bottom]:mr-2", + "data-[position=left-bottom]:bottom-0 data-[position=left-bottom]:left-0 data-[position=left-bottom]:mx-auto w-full sm:data-[position=left-bottom]:w-max mb-1 sm:data-[position=left-bottom]:ml-2", + "data-[position=center-bottom]:bottom-0 data-[position=center-bottom]:left-0 data-[position=center-bottom]:right-0 w-full sm:data-[position=center-bottom]:w-max sm:data-[position=center-bottom]:mx-auto", + "data-[position=right-top]:top-0 data-[position=right-top]:right-0 data-[position=right-top]:mx-auto w-full sm:data-[position=right-top]:w-max sm:data-[position=right-top]:mr-2", + "data-[position=left-top]:top-0 data-[position=left-top]:left-0 data-[position=left-top]:mx-auto w-full sm:data-[position=left-top]:w-max sm:data-[position=left-top]:ml-2", + "data-[position=center-top]:top-0 data-[position=center-top]:left-0 data-[position=center-top]:right-0 w-full sm:data-[position=center-top]:w-max sm:data-[position=center-top]:mx-auto", ], closeButton: [ "opacity-0 p-0 group-hover:opacity-100 w-6 h-6 min-w-4 absolute -right-2 -top-2 items-center justify-center bg-transparent text-default-400 hover:text-default-600 border border-3 border-transparent", From 42130bb5fbcd2e2ee32c4ee35656bc4abd6604dc Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 16:53:23 +0530 Subject: [PATCH 28/49] chore: adding story with description --- packages/components/toast/src/toast.tsx | 5 ++++- packages/components/toast/stories/toast.stories.tsx | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index 82ccda5d8e..97c7277ce5 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -61,7 +61,10 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { : null; const loadingIconComponent = isLoading ? customLoadingIcon || ( - + ) : null; diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 60a2dd5334..c0f90cca0a 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -78,7 +78,6 @@ const Template = (args: ToastProps) => { onPress={() => { addToast({ title: "Toast Title", - description: "Toast Displayed Successfully", ...args, }); }} @@ -274,6 +273,14 @@ export const Default = { }, }; +export const WithDescription = { + render: Template, + args: { + description: "Toast displayed successfully.", + ...defaultProps, + }, +}; + export const WithCustomIcon = { render: Template, args: { From df8e41cae71c2a377de5aaadd16ad127f9724165 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 8 Jan 2025 16:58:10 +0530 Subject: [PATCH 29/49] chore: adding credits for sonner --- packages/components/toast/src/use-toast.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 74e681f0a9..d4b8675cfd 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -219,6 +219,7 @@ export function useToast(originalProps: UseToastProps) const [initialHeight, setInitialHeight] = useState(0); + // Following was inspired from sonner ❤️ useLayoutEffect(() => { if (!domRef.current || !mounted) { return; From da2820b91de8bac852c9c5237892f7665745a784 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Thu, 9 Jan 2025 00:05:10 +0530 Subject: [PATCH 30/49] fix: adding junior's suggestions --- .../components/toast/src/toast-provider.tsx | 6 +- .../components/toast/src/toast-region.tsx | 14 +-- packages/components/toast/src/use-toast.ts | 28 ++--- .../toast/stories/toast.stories.tsx | 33 +++-- packages/core/theme/src/components/toast.ts | 116 ++++-------------- 5 files changed, 64 insertions(+), 133 deletions(-) diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx index ef064fbf66..f719f53272 100644 --- a/packages/components/toast/src/toast-provider.tsx +++ b/packages/components/toast/src/toast-provider.tsx @@ -8,7 +8,7 @@ let globalToastQueue: ToastQueue | null = null; interface ToastProviderProps { maxVisibleToasts?: number; - position?: + placement?: | "right-bottom" | "left-bottom" | "center-bottom" @@ -29,7 +29,7 @@ export const getToastQueue = () => { }; export const ToastProvider = ({ - position = "right-bottom", + placement = "right-bottom", disableAnimation: disableAnimationProp = false, maxVisibleToasts = 3, }: ToastProviderProps) => { @@ -45,7 +45,7 @@ export const ToastProvider = ({ ); diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index c520027a9a..bc5a6595f8 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -10,7 +10,7 @@ import {ToastProps} from "./use-toast"; interface ToastRegionProps extends AriaToastRegionProps { toastQueue: ToastState; - position?: + placement?: | "right-bottom" | "left-bottom" | "center-bottom" @@ -23,7 +23,7 @@ interface ToastRegionProps extends AriaToastRegionProps { export function ToastRegion({ toastQueue, - position, + placement, disableAnimation, maxVisibleToasts, ...props @@ -54,7 +54,7 @@ export function ToastRegion({ }; }, []); - const positionStyles: Record = { + const placementStyles: Record = { "right-bottom": "fixed flex flex-col bottom-0 right-0 pr-2", "left-bottom": "fixed flex flex-col bottom-0 left-0 pl-2", "center-bottom": "fixed flex flex-col bottom-0 left-1/2 -translate-x-1/2", @@ -62,7 +62,7 @@ export function ToastRegion({ "left-top": "fixed flex flex-col top-0 left-0 pl-2", "center-top": "fixed flex flex-col top-0 left-1/2 -translate-x-1/2", }; - const positionStyle = position ? positionStyles[position] : positionStyles["right-bottom"]; + const placementStyle = placement ? placementStyles[placement] : placementStyles["right-bottom"]; const [heights, setHeights] = useState([]); const total = toastQueue.visibleToasts.length; const handleTouchStart = () => { @@ -73,8 +73,8 @@ export function ToastRegion({
{toastQueue.visibleToasts.map((toast: QueuedToast, index) => { @@ -93,7 +93,7 @@ export function ToastRegion({ heights={heights} index={index} isRegionExpanded={isHovered || isTouched} - position={position} + placement={placement} setHeights={setHeights} total={total} /> diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index d4b8675cfd..094556529d 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -80,9 +80,9 @@ export interface ToastProps extends ToastVariantProps { */ timeout?: number; /** - * Position of the toast in the view-port. + * Placement of the toast in the view-port. */ - position?: + placement?: | "right-bottom" | "left-bottom" | "center-bottom" @@ -120,7 +120,7 @@ export function useToast(originalProps: UseToastProps) toast, endContent, hideIcon = false, - position = "right-bottom", + placement = "right-bottom", isRegionExpanded, state, total = 1, @@ -263,8 +263,8 @@ export function useToast(originalProps: UseToastProps) [objectToDeps(variantProps)], ); - const multiplier = position.includes("top") ? 1 : -1; - const toastVariants = position.includes("bottom") + const multiplier = placement.includes("top") ? 1 : -1; + const toastVariants = placement.includes("bottom") ? { hidden: {opacity: 0, y: 50}, visible: {opacity: 1, y: 0}, @@ -277,10 +277,10 @@ export function useToast(originalProps: UseToastProps) }; const [drag, setDrag] = useState(false); const handleDragEnd = (offsetX: number, offsetY: number) => { - const isRight = position.includes("right"); - const isLeft = position.includes("left"); - const isTop = position.includes("top"); - const isBottom = position.includes("bottom"); + const isRight = placement.includes("right"); + const isLeft = placement.includes("left"); + const isTop = placement.includes("top"); + const isBottom = placement.includes("bottom"); if ( (isRight && offsetX >= 50) || @@ -367,11 +367,11 @@ export function useToast(originalProps: UseToastProps) props = {}, ): MotionProps & { "data-drag": string | boolean; - "data-position": string; + "data-placement": string; className: string; } => { const isCloseToEnd = total - index - 1 <= 2; - const dragDirection = position.includes("center") ? "y" : "x"; + const dragDirection = placement.includes("center") ? "y" : "x"; const dragConstraints = {left: 0, right: 0, top: 0, bottom: 0}; return { @@ -398,7 +398,7 @@ export function useToast(originalProps: UseToastProps) setDrag(true); }, "data-drag": dataAttr(drag), - "data-position": position, + "data-placement": placement, className: slots.motionDiv({class: classNames?.motionDiv}), ...props, }; @@ -407,7 +407,7 @@ export function useToast(originalProps: UseToastProps) closeButtonProps, total, index, - position, + placement, isRegionExpanded, liftHeight, multiplier, @@ -433,7 +433,7 @@ export function useToast(originalProps: UseToastProps) classNames, color: variantProps["color"], hideIcon, - position, + placement, state, toast: props.toast, disableAnimation, diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index c0f90cca0a..a063049e86 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -11,7 +11,7 @@ export default { argTypes: { variant: { control: {type: "select"}, - options: ["faded", "flat", "bordered", "solid"], + options: ["flat", "bordered", "solid"], }, color: { control: {type: "select"}, @@ -25,17 +25,16 @@ export default { control: {type: "select"}, options: ["sm", "md", "lg"], }, - isDisabled: { - control: { - type: "boolean", - }, - }, hideIcon: { control: { type: "boolean", }, }, - position: { + shadow: { + control: {type: "select"}, + options: ["sm", "md", "lg"], + }, + placement: { control: {type: "select"}, options: [ "right-bottom", @@ -72,7 +71,7 @@ const defaultProps = { const Template = (args: ToastProps) => { return ( <> - +
+ , + ); + + const region = wrapper.getByRole("region"); + + expect(region).toHaveAttribute("data-placement", "left-bottom"); + }); + + it("should have loading-icon when promise prop is passed.", async () => { + const wrapper = render( + <> + + + , + ); + + const button = wrapper.getByTestId("button"); + + await user.click(button); + + const loadingIcon = wrapper.getByLabelText("loadingIcon"); + + expect(loadingIcon).toBeTruthy(); + }); }); diff --git a/packages/components/toast/src/toast.tsx b/packages/components/toast/src/toast.tsx index b5e7482daa..a1f1c8c4e0 100644 --- a/packages/components/toast/src/toast.tsx +++ b/packages/components/toast/src/toast.tsx @@ -63,6 +63,7 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => { ) : null; diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 26fc3f4436..a55e5e7447 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -16,14 +16,6 @@ export interface ToastProps extends ToastVariantProps { * Ref to the DOM node. */ ref?: ReactRef; - /** - * Index of the toast - */ - index?: number; - /** - * Total number of the toasts - */ - total?: number; /** * title of the toast */ @@ -79,16 +71,6 @@ export interface ToastProps extends ToastVariantProps { * Time to auto-close the toast. */ timeout?: number; - /** - * Placement of the toast in the view-port. - */ - placement?: - | "right-bottom" - | "left-bottom" - | "center-bottom" - | "right-top" - | "left-top" - | "center-top"; /** * function which is called when toast is closed. */ @@ -97,11 +79,20 @@ export interface ToastProps extends ToastVariantProps { interface Props extends HTMLNextUIProps<"div">, ToastProps { toast: QueuedToast; + index: number; + total: number; state: ToastState; heights: number[]; setHeights: (val: number[]) => void; disableAnimation: boolean; isRegionExpanded: boolean; + placement?: + | "right-bottom" + | "left-bottom" + | "center-bottom" + | "right-top" + | "left-top" + | "center-top"; } export type UseToastProps = Props & @@ -322,6 +313,7 @@ export function useToast(originalProps: UseToastProps) "data-has-description": dataAttr(!isEmpty(description)), "data-toast": true, "data-animation": originalProps.toast.animation, + "aria-label": "toast", onTransitionEnd: () => { if (originalProps.toast.animation === "exiting") { state.remove(originalProps.toast.key); @@ -337,6 +329,7 @@ export function useToast(originalProps: UseToastProps) const getIconProps: PropGetter = useCallback( (props = {}) => ({ + "aria-label": "descriptionIcon", className: slots.icon({class: classNames?.icon}), ...props, }), @@ -378,7 +371,7 @@ export function useToast(originalProps: UseToastProps) const getCloseButtonProps: PropGetter = useCallback( (props = {}) => ({ className: slots.closeButton({class: classNames?.closeButton}), - "aria-label": "close-button", + "aria-label": "closeButton", ...mergeProps(props, closeButtonProps, {onPress: originalProps.onClose}), }), [closeButtonProps], @@ -387,7 +380,7 @@ export function useToast(originalProps: UseToastProps) const getCloseIconProps: PropGetter = useCallback( (props = {}) => ({ className: slots.closeIcon({class: classNames?.closeIcon}), - "aria-label": "close-icon", + "aria-label": "closeIcon", ...props, }), [], From 8352cc80486d90448c661d83d959b34e42e40f76 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Fri, 10 Jan 2025 16:28:19 +0530 Subject: [PATCH 36/49] chore: adding swipe threshild and initial position variable --- packages/components/toast/src/use-toast.ts | 26 +++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index a55e5e7447..1248883347 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -126,6 +126,8 @@ export function useToast(originalProps: UseToastProps) isDisabled: false, }); const disableAnimation = originalProps.disableAnimation; + const SWIPE_THRESHOLD = 100; + const INITIAL_POSITION = 50; const animationRef = useRef(null); const startTime = useRef(null); @@ -255,17 +257,11 @@ export function useToast(originalProps: UseToastProps) ); const multiplier = placement.includes("top") ? 1 : -1; - const toastVariants = placement.includes("bottom") - ? { - hidden: {opacity: 0, y: 50}, - visible: {opacity: 1, y: 0}, - exit: {opacity: 0, y: 50}, - } - : { - hidden: {opacity: 0, y: -50}, - visible: {opacity: 1, y: 0}, - exit: {opacity: 0, y: -50}, - }; + const toastVariants = { + hidden: {opacity: 0, y: -INITIAL_POSITION * multiplier}, + visible: {opacity: 1, y: 0}, + exit: {opacity: 0, y: -INITIAL_POSITION * multiplier}, + }; const [drag, setDrag] = useState(false); const [dragValue, setDragValue] = useState(0); @@ -277,9 +273,9 @@ export function useToast(originalProps: UseToastProps) const isCenterBottom = placement === "center-bottom"; if ( - (isRight && offsetX >= 50) || - (isLeft && offsetX <= -50) || - ((isCenterTop || isCenterBottom) && Math.abs(offsetX) >= 50) + (isRight && offsetX >= SWIPE_THRESHOLD) || + (isLeft && offsetX <= -SWIPE_THRESHOLD) || + ((isCenterTop || isCenterBottom) && Math.abs(offsetX) >= SWIPE_THRESHOLD) ) { return true; } @@ -320,7 +316,7 @@ export function useToast(originalProps: UseToastProps) } }, style: { - opacity: Math.max(0, 1 - dragValue / 50), + opacity: Math.max(0, 1 - dragValue / SWIPE_THRESHOLD), }, ...mergeProps(props, otherProps, toastProps, hoverProps), }), From 5562ba10296d6e692be2e87d48b93b9fcb3fe010 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Fri, 10 Jan 2025 17:12:23 +0530 Subject: [PATCH 37/49] fix: fixing autoclose in timeout --- packages/components/toast/src/use-toast.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 1248883347..3d3c5c2d41 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -316,7 +316,7 @@ export function useToast(originalProps: UseToastProps) } }, style: { - opacity: Math.max(0, 1 - dragValue / SWIPE_THRESHOLD), + opacity: drag ? Math.max(0, 1 - dragValue / (SWIPE_THRESHOLD + 20)) : undefined, }, ...mergeProps(props, otherProps, toastProps, hoverProps), }), From 91b44bbb4aa43d6415a500d20381d78f8d068685 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Fri, 10 Jan 2025 19:53:31 +0530 Subject: [PATCH 38/49] chore: modifying the docs --- .../app/examples/toast/custom-style/page.tsx | 1 + .../{position => disable-animation}/page.tsx | 4 +- .../app/examples/toast/placement/page.tsx | 23 +++++++ apps/docs/app/examples/toast/promise/page.tsx | 23 +++++++ apps/docs/app/examples/toast/radius/page.tsx | 1 - apps/docs/app/examples/toast/usage/page.tsx | 1 - .../app/examples/toast/with-action/page.tsx | 1 - .../examples/toast/with-description/page.tsx | 21 ++++++ .../components/toast/color-root.raw.jsx | 12 ++++ .../content/components/toast/color.raw.jsx | 3 +- apps/docs/content/components/toast/color.ts | 4 +- .../components/toast/custom-icon-root.raw.jsx | 12 ++++ .../components/toast/custom-icon.raw.jsx | 3 +- .../content/components/toast/custom-icon.ts | 4 +- .../toast/custom-styles-root.raw.jsx | 12 ++++ .../components/toast/custom-styles.raw.jsx | 3 +- .../content/components/toast/custom-styles.ts | 4 +- .../components/toast/description-root.raw.jsx | 12 ++++ .../components/toast/description.raw.jsx | 17 +++++ .../content/components/toast/description.ts | 11 +++ .../toast/disable-animation-root.raw.jsx | 12 ++++ .../toast/disable-animation.raw.jsx | 21 ++++++ .../components/toast/disable-animation.ts | 11 +++ .../components/toast/hidden-icon-root.raw.jsx | 12 ++++ .../components/toast/hidden-icon.raw.jsx | 3 +- .../content/components/toast/hidden-icon.ts | 4 +- apps/docs/content/components/toast/index.ts | 8 +++ apps/docs/content/components/toast/page.tsx | 23 +++++++ .../components/toast/placement-root.raw.jsx | 12 ++++ .../{position.raw.jsx => placement.raw.jsx} | 5 +- .../content/components/toast/placement.ts | 11 +++ .../docs/content/components/toast/position.ts | 9 --- .../components/toast/promise-root.raw.jsx | 12 ++++ .../content/components/toast/promise.raw.jsx | 21 ++++++ apps/docs/content/components/toast/promise.ts | 11 +++ .../components/toast/radius-root.raw.jsx | 12 ++++ .../content/components/toast/radius.raw.jsx | 3 +- apps/docs/content/components/toast/radius.ts | 4 +- .../components/toast/usage-root.raw.jsx | 12 ++++ .../content/components/toast/usage.raw.jsx | 3 +- apps/docs/content/components/toast/usage.ts | 4 +- .../components/toast/variants-root.raw.jsx | 12 ++++ .../content/components/toast/variants.raw.jsx | 3 +- .../docs/content/components/toast/variants.ts | 4 +- .../components/toast/with-action-root.raw.jsx | 12 ++++ .../components/toast/with-action.raw.jsx | 3 +- .../content/components/toast/with-action.ts | 4 +- .../toast/with-timeout-root.raw.jsx | 12 ++++ .../components/toast/with-timeout.raw.jsx | 3 +- .../content/components/toast/with-timeout.ts | 2 + apps/docs/content/docs/components/toast.mdx | 68 +++++++++++++++++-- packages/components/toast/src/toast.tsx | 2 +- packages/components/toast/src/use-toast.ts | 5 +- 53 files changed, 462 insertions(+), 53 deletions(-) rename apps/docs/app/examples/toast/{position => disable-animation}/page.tsx (84%) create mode 100644 apps/docs/app/examples/toast/placement/page.tsx create mode 100644 apps/docs/app/examples/toast/promise/page.tsx create mode 100644 apps/docs/app/examples/toast/with-description/page.tsx create mode 100644 apps/docs/content/components/toast/color-root.raw.jsx create mode 100644 apps/docs/content/components/toast/custom-icon-root.raw.jsx create mode 100644 apps/docs/content/components/toast/custom-styles-root.raw.jsx create mode 100644 apps/docs/content/components/toast/description-root.raw.jsx create mode 100644 apps/docs/content/components/toast/description.raw.jsx create mode 100644 apps/docs/content/components/toast/description.ts create mode 100644 apps/docs/content/components/toast/disable-animation-root.raw.jsx create mode 100644 apps/docs/content/components/toast/disable-animation.raw.jsx create mode 100644 apps/docs/content/components/toast/disable-animation.ts create mode 100644 apps/docs/content/components/toast/hidden-icon-root.raw.jsx create mode 100644 apps/docs/content/components/toast/page.tsx create mode 100644 apps/docs/content/components/toast/placement-root.raw.jsx rename apps/docs/content/components/toast/{position.raw.jsx => placement.raw.jsx} (81%) create mode 100644 apps/docs/content/components/toast/placement.ts delete mode 100644 apps/docs/content/components/toast/position.ts create mode 100644 apps/docs/content/components/toast/promise-root.raw.jsx create mode 100644 apps/docs/content/components/toast/promise.raw.jsx create mode 100644 apps/docs/content/components/toast/promise.ts create mode 100644 apps/docs/content/components/toast/radius-root.raw.jsx create mode 100644 apps/docs/content/components/toast/usage-root.raw.jsx create mode 100644 apps/docs/content/components/toast/variants-root.raw.jsx create mode 100644 apps/docs/content/components/toast/with-action-root.raw.jsx create mode 100644 apps/docs/content/components/toast/with-timeout-root.raw.jsx diff --git a/apps/docs/app/examples/toast/custom-style/page.tsx b/apps/docs/app/examples/toast/custom-style/page.tsx index 93839249e9..c0ef4d0695 100644 --- a/apps/docs/app/examples/toast/custom-style/page.tsx +++ b/apps/docs/app/examples/toast/custom-style/page.tsx @@ -11,6 +11,7 @@ const CustomToastComponent = () => { addToast({ title: "Sucessful!", description: "Document uploaded to cloud successful.", + color: "primary", classNames: { base: cn([ "bg-default-50 dark:bg-background shadow-sm", diff --git a/apps/docs/app/examples/toast/position/page.tsx b/apps/docs/app/examples/toast/disable-animation/page.tsx similarity index 84% rename from apps/docs/app/examples/toast/position/page.tsx rename to apps/docs/app/examples/toast/disable-animation/page.tsx index f78d4c9e0f..350e4cbe79 100644 --- a/apps/docs/app/examples/toast/position/page.tsx +++ b/apps/docs/app/examples/toast/disable-animation/page.tsx @@ -4,7 +4,7 @@ import {addToast, Button, ToastProvider} from "@nextui-org/react"; export default function App() { return ( <> - +
diff --git a/apps/docs/app/examples/toast/placement/page.tsx b/apps/docs/app/examples/toast/placement/page.tsx new file mode 100644 index 0000000000..3592a13bde --- /dev/null +++ b/apps/docs/app/examples/toast/placement/page.tsx @@ -0,0 +1,23 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ +
+ + ); +} diff --git a/apps/docs/app/examples/toast/promise/page.tsx b/apps/docs/app/examples/toast/promise/page.tsx new file mode 100644 index 0000000000..d337c5e0d9 --- /dev/null +++ b/apps/docs/app/examples/toast/promise/page.tsx @@ -0,0 +1,23 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + +
+ +
+ + ); +} diff --git a/apps/docs/app/examples/toast/radius/page.tsx b/apps/docs/app/examples/toast/radius/page.tsx index e726e30e10..1d2ccf9b67 100644 --- a/apps/docs/app/examples/toast/radius/page.tsx +++ b/apps/docs/app/examples/toast/radius/page.tsx @@ -18,7 +18,6 @@ export default function App() { description: "Toast displayed successfully", // @ts-ignore radius: radius, - color: "primary", }) } > diff --git a/apps/docs/app/examples/toast/usage/page.tsx b/apps/docs/app/examples/toast/usage/page.tsx index 28cf52f177..52bfe3779c 100644 --- a/apps/docs/app/examples/toast/usage/page.tsx +++ b/apps/docs/app/examples/toast/usage/page.tsx @@ -10,7 +10,6 @@ export default function App() { onPress={() => addToast({ title: "Toast title", - description: "Toast displayed successfully", }) } > diff --git a/apps/docs/app/examples/toast/with-action/page.tsx b/apps/docs/app/examples/toast/with-action/page.tsx index 77d2d1828f..dfb0808151 100644 --- a/apps/docs/app/examples/toast/with-action/page.tsx +++ b/apps/docs/app/examples/toast/with-action/page.tsx @@ -17,7 +17,6 @@ export default function App() { ), color: "warning", - variant: "faded", }); }} > diff --git a/apps/docs/app/examples/toast/with-description/page.tsx b/apps/docs/app/examples/toast/with-description/page.tsx new file mode 100644 index 0000000000..28cf52f177 --- /dev/null +++ b/apps/docs/app/examples/toast/with-description/page.tsx @@ -0,0 +1,21 @@ +"use client"; +import {addToast, Button, ToastProvider} from "@nextui-org/react"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/color-root.raw.jsx b/apps/docs/content/components/toast/color-root.raw.jsx new file mode 100644 index 0000000000..c4c22c8713 --- /dev/null +++ b/apps/docs/content/components/toast/color-root.raw.jsx @@ -0,0 +1,12 @@ +import {ToastProvider} from "@nextui-org/react"; + +import ColorDemo from "./color.raw.jsx?raw"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/color.raw.jsx b/apps/docs/content/components/toast/color.raw.jsx index e9772bc692..d78eb3c427 100644 --- a/apps/docs/content/components/toast/color.raw.jsx +++ b/apps/docs/content/components/toast/color.raw.jsx @@ -1,9 +1,8 @@ -import {addToast, Button, ToastProvider} from "@nextui-org/react"; +import {addToast, Button} from "@nextui-org/react"; export default function App() { return ( <> -
{["default", "primary", "secondary", "success", "warning", "danger"].map((color) => ( + + ); +} diff --git a/apps/docs/content/components/toast/description.ts b/apps/docs/content/components/toast/description.ts new file mode 100644 index 0000000000..9f76b3182b --- /dev/null +++ b/apps/docs/content/components/toast/description.ts @@ -0,0 +1,11 @@ +import App from "./description-root.raw.jsx?raw"; +import Usage from "./description.raw.jsx?raw"; + +const react = { + "/App.jsx": App, + "/Description.jsx": Usage, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/disable-animation-root.raw.jsx b/apps/docs/content/components/toast/disable-animation-root.raw.jsx new file mode 100644 index 0000000000..54af9c4a49 --- /dev/null +++ b/apps/docs/content/components/toast/disable-animation-root.raw.jsx @@ -0,0 +1,12 @@ +import {ToastProvider} from "@nextui-org/react"; + +import DisableAnimation from "./disable-animation.raw.jsx?raw"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/disable-animation.raw.jsx b/apps/docs/content/components/toast/disable-animation.raw.jsx new file mode 100644 index 0000000000..a8cfaa9b45 --- /dev/null +++ b/apps/docs/content/components/toast/disable-animation.raw.jsx @@ -0,0 +1,21 @@ +import {addToast, Button} from "@nextui-org/react"; + +export default function App() { + return ( + <> +
+ +
+ + ); +} diff --git a/apps/docs/content/components/toast/disable-animation.ts b/apps/docs/content/components/toast/disable-animation.ts new file mode 100644 index 0000000000..1de45af967 --- /dev/null +++ b/apps/docs/content/components/toast/disable-animation.ts @@ -0,0 +1,11 @@ +import App from "./disable-animation-root.raw.jsx?raw"; +import DisableAnimation from "./disable-animation.raw.jsx?raw"; + +const react = { + "/App.jsx": App, + "Position.jsx": DisableAnimation, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/hidden-icon-root.raw.jsx b/apps/docs/content/components/toast/hidden-icon-root.raw.jsx new file mode 100644 index 0000000000..201be3b801 --- /dev/null +++ b/apps/docs/content/components/toast/hidden-icon-root.raw.jsx @@ -0,0 +1,12 @@ +import {ToastProvider} from "@nextui-org/react"; + +import HiddenIcon from "./hidden-icon.raw.jsx?raw"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/hidden-icon.raw.jsx b/apps/docs/content/components/toast/hidden-icon.raw.jsx index 93cc1ca305..c3428c4518 100644 --- a/apps/docs/content/components/toast/hidden-icon.raw.jsx +++ b/apps/docs/content/components/toast/hidden-icon.raw.jsx @@ -1,9 +1,8 @@ -import {addToast, Button, ToastProvider} from "@nextui-org/react"; +import {addToast, Button} from "@nextui-org/react"; export default function App() { return ( <> -
+
+ + ); +} diff --git a/apps/docs/content/components/toast/placement-root.raw.jsx b/apps/docs/content/components/toast/placement-root.raw.jsx new file mode 100644 index 0000000000..bbf63a969d --- /dev/null +++ b/apps/docs/content/components/toast/placement-root.raw.jsx @@ -0,0 +1,12 @@ +import {ToastProvider} from "@nextui-org/react"; + +import Position from "./placement.raw.jsx?raw"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/position.raw.jsx b/apps/docs/content/components/toast/placement.raw.jsx similarity index 81% rename from apps/docs/content/components/toast/position.raw.jsx rename to apps/docs/content/components/toast/placement.raw.jsx index d5ea6353cc..94821f30c6 100644 --- a/apps/docs/content/components/toast/position.raw.jsx +++ b/apps/docs/content/components/toast/placement.raw.jsx @@ -1,9 +1,8 @@ -import {addToast, Button, ToastProvider} from "@nextui-org/react"; +import {addToast, Button} from "@nextui-org/react"; export default function App() { return ( <> -
{[ "left-top", @@ -21,8 +20,6 @@ export default function App() { addToast({ title: "Toast title", description: "Toast displayed successfully", - // @ts-ignore - position: position, }) } > diff --git a/apps/docs/content/components/toast/placement.ts b/apps/docs/content/components/toast/placement.ts new file mode 100644 index 0000000000..5676481105 --- /dev/null +++ b/apps/docs/content/components/toast/placement.ts @@ -0,0 +1,11 @@ +import App from "./placement-root.raw.jsx?raw"; +import Position from "./placement.raw.jsx?raw"; + +const react = { + "/App.jsx": App, + "Position.jsx": Position, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/position.ts b/apps/docs/content/components/toast/position.ts deleted file mode 100644 index e386fb1848..0000000000 --- a/apps/docs/content/components/toast/position.ts +++ /dev/null @@ -1,9 +0,0 @@ -import App from "./position.raw.jsx?raw"; - -const react = { - "/App.jsx": App, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/promise-root.raw.jsx b/apps/docs/content/components/toast/promise-root.raw.jsx new file mode 100644 index 0000000000..117bf739db --- /dev/null +++ b/apps/docs/content/components/toast/promise-root.raw.jsx @@ -0,0 +1,12 @@ +import {ToastProvider} from "@nextui-org/react"; + +import Promise from "./promise.raw.jsx?raw"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/promise.raw.jsx b/apps/docs/content/components/toast/promise.raw.jsx new file mode 100644 index 0000000000..cd7287015d --- /dev/null +++ b/apps/docs/content/components/toast/promise.raw.jsx @@ -0,0 +1,21 @@ +import {addToast, Button} from "@nextui-org/react"; + +export default function App() { + return ( + <> +
+ +
+ + ); +} diff --git a/apps/docs/content/components/toast/promise.ts b/apps/docs/content/components/toast/promise.ts new file mode 100644 index 0000000000..5b0ec47d48 --- /dev/null +++ b/apps/docs/content/components/toast/promise.ts @@ -0,0 +1,11 @@ +import App from "./promise-root.raw.jsx?raw"; +import Promise from "./promise.raw.jsx?raw"; + +const react = { + "/App.jsx": App, + "/Promise.jsx": Promise, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/radius-root.raw.jsx b/apps/docs/content/components/toast/radius-root.raw.jsx new file mode 100644 index 0000000000..94bd78a851 --- /dev/null +++ b/apps/docs/content/components/toast/radius-root.raw.jsx @@ -0,0 +1,12 @@ +import {ToastProvider} from "@nextui-org/react"; + +import Radius from "./radius.raw.jsx?raw"; + +export default function App() { + return ( + <> + + + + ); +} diff --git a/apps/docs/content/components/toast/radius.raw.jsx b/apps/docs/content/components/toast/radius.raw.jsx index 020aadaa99..7547b111c6 100644 --- a/apps/docs/content/components/toast/radius.raw.jsx +++ b/apps/docs/content/components/toast/radius.raw.jsx @@ -1,9 +1,8 @@ -import {addToast, Button, ToastProvider} from "@nextui-org/react"; +import {addToast, Button} from "@nextui-org/react"; export default function App() { return ( <> -
{["none", "sm", "md", "lg", "full"].map((radius) => ( - ))} -
- - ); -} diff --git a/apps/docs/app/examples/toast/custom-icon/page.tsx b/apps/docs/app/examples/toast/custom-icon/page.tsx deleted file mode 100644 index df57c8659f..0000000000 --- a/apps/docs/app/examples/toast/custom-icon/page.tsx +++ /dev/null @@ -1,39 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/app/examples/toast/custom-style/page.tsx b/apps/docs/app/examples/toast/custom-style/page.tsx deleted file mode 100644 index ebb6977fb2..0000000000 --- a/apps/docs/app/examples/toast/custom-style/page.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client"; - -import {addToast, Button, cn, ToastProvider} from "@heroui/react"; - -const CustomToastComponent = () => { - return ( - <> - - -
- ), - }); - }} - > - Show Toast - - - ); -}; - -export default function App() { - return ( - <> - -
- -
- - ); -} diff --git a/apps/docs/app/examples/toast/disable-animation/page.tsx b/apps/docs/app/examples/toast/disable-animation/page.tsx deleted file mode 100644 index a04ac2372e..0000000000 --- a/apps/docs/app/examples/toast/disable-animation/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - -
- -
- - ); -} diff --git a/apps/docs/app/examples/toast/hidden-icon/page.tsx b/apps/docs/app/examples/toast/hidden-icon/page.tsx deleted file mode 100644 index b88d773d53..0000000000 --- a/apps/docs/app/examples/toast/hidden-icon/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/app/examples/toast/placement/page.tsx b/apps/docs/app/examples/toast/placement/page.tsx deleted file mode 100644 index f388fd162f..0000000000 --- a/apps/docs/app/examples/toast/placement/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - -
- -
- - ); -} diff --git a/apps/docs/app/examples/toast/promise/page.tsx b/apps/docs/app/examples/toast/promise/page.tsx deleted file mode 100644 index 19e9bc2eed..0000000000 --- a/apps/docs/app/examples/toast/promise/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - -
- -
- - ); -} diff --git a/apps/docs/app/examples/toast/radius/page.tsx b/apps/docs/app/examples/toast/radius/page.tsx deleted file mode 100644 index c34c6d69eb..0000000000 --- a/apps/docs/app/examples/toast/radius/page.tsx +++ /dev/null @@ -1,30 +0,0 @@ -"use client"; - -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - -
- {["none", "sm", "md", "lg", "full"].map((radius) => ( - - ))} -
- - ); -} diff --git a/apps/docs/app/examples/toast/usage/page.tsx b/apps/docs/app/examples/toast/usage/page.tsx deleted file mode 100644 index 21050bce3b..0000000000 --- a/apps/docs/app/examples/toast/usage/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/app/examples/toast/variant/page.tsx b/apps/docs/app/examples/toast/variant/page.tsx deleted file mode 100644 index c3e023c174..0000000000 --- a/apps/docs/app/examples/toast/variant/page.tsx +++ /dev/null @@ -1,30 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - -
- {["solid", "bordered", "flat", "faded"].map((variant) => ( - - ))} -
- - ); -} diff --git a/apps/docs/app/examples/toast/with-action/page.tsx b/apps/docs/app/examples/toast/with-action/page.tsx deleted file mode 100644 index 9c0824c72e..0000000000 --- a/apps/docs/app/examples/toast/with-action/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - - - ), - color: "warning", - }); - }} - > - Show Toast - - - ); -} diff --git a/apps/docs/app/examples/toast/with-description/page.tsx b/apps/docs/app/examples/toast/with-description/page.tsx deleted file mode 100644 index 405340eac8..0000000000 --- a/apps/docs/app/examples/toast/with-description/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/app/examples/toast/with-timeout/page.tsx b/apps/docs/app/examples/toast/with-timeout/page.tsx deleted file mode 100644 index 17c071237f..0000000000 --- a/apps/docs/app/examples/toast/with-timeout/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/color-root.raw.jsx b/apps/docs/content/components/toast/color-root.raw.jsx deleted file mode 100644 index f832dac4b6..0000000000 --- a/apps/docs/content/components/toast/color-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import ColorDemo from "./color.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/color.ts b/apps/docs/content/components/toast/color.ts index 8816057710..b97ae00b84 100644 --- a/apps/docs/content/components/toast/color.ts +++ b/apps/docs/content/components/toast/color.ts @@ -1,8 +1,6 @@ -import App from "./color-root.raw.jsx?raw"; import Color from "./color.raw.jsx?raw"; const react = { - "/App.jsx": App, "/Color.jsx": Color, }; diff --git a/apps/docs/content/components/toast/custom-icon-root.raw.jsx b/apps/docs/content/components/toast/custom-icon-root.raw.jsx deleted file mode 100644 index 1ee28a07c8..0000000000 --- a/apps/docs/content/components/toast/custom-icon-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import CustomIcon from "./custom-icon.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/custom-icon.ts b/apps/docs/content/components/toast/custom-icon.ts index 8ddc9666a8..652b428602 100644 --- a/apps/docs/content/components/toast/custom-icon.ts +++ b/apps/docs/content/components/toast/custom-icon.ts @@ -1,8 +1,6 @@ -import App from "./custom-icon-root.raw.jsx?raw"; import CustomIcon from "./custom-icon.raw.jsx?raw"; const react = { - "/App.jsx": App, "/CustomIcon.jsx": CustomIcon, }; diff --git a/apps/docs/content/components/toast/custom-styles-root.raw.jsx b/apps/docs/content/components/toast/custom-styles-root.raw.jsx deleted file mode 100644 index 06430d5cd2..0000000000 --- a/apps/docs/content/components/toast/custom-styles-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import CustomStyles from "./custom-styles.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/custom-styles.ts b/apps/docs/content/components/toast/custom-styles.ts index 34717608eb..b48bc3735c 100644 --- a/apps/docs/content/components/toast/custom-styles.ts +++ b/apps/docs/content/components/toast/custom-styles.ts @@ -1,8 +1,6 @@ -import App from "./custom-styles-root.raw.jsx?raw"; import CustomStyles from "./custom-styles.raw.jsx?raw"; const react = { - "/App.jsx": App, "CustomStyles.jsx": CustomStyles, }; diff --git a/apps/docs/content/components/toast/description-root.raw.jsx b/apps/docs/content/components/toast/description-root.raw.jsx deleted file mode 100644 index ec55e5754e..0000000000 --- a/apps/docs/content/components/toast/description-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import Description from "./description.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/description.ts b/apps/docs/content/components/toast/description.ts index 9f76b3182b..51cfb6c296 100644 --- a/apps/docs/content/components/toast/description.ts +++ b/apps/docs/content/components/toast/description.ts @@ -1,8 +1,6 @@ -import App from "./description-root.raw.jsx?raw"; import Usage from "./description.raw.jsx?raw"; const react = { - "/App.jsx": App, "/Description.jsx": Usage, }; diff --git a/apps/docs/content/components/toast/disable-animation-root.raw.jsx b/apps/docs/content/components/toast/disable-animation-root.raw.jsx deleted file mode 100644 index 064938ccb5..0000000000 --- a/apps/docs/content/components/toast/disable-animation-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import DisableAnimation from "./disable-animation.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/disable-animation.raw.jsx b/apps/docs/content/components/toast/disable-animation.raw.jsx deleted file mode 100644 index 7521421461..0000000000 --- a/apps/docs/content/components/toast/disable-animation.raw.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> -
- -
- - ); -} diff --git a/apps/docs/content/components/toast/disable-animation.ts b/apps/docs/content/components/toast/disable-animation.ts deleted file mode 100644 index 1de45af967..0000000000 --- a/apps/docs/content/components/toast/disable-animation.ts +++ /dev/null @@ -1,11 +0,0 @@ -import App from "./disable-animation-root.raw.jsx?raw"; -import DisableAnimation from "./disable-animation.raw.jsx?raw"; - -const react = { - "/App.jsx": App, - "Position.jsx": DisableAnimation, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/hidden-icon-root.raw.jsx b/apps/docs/content/components/toast/hidden-icon-root.raw.jsx deleted file mode 100644 index 75bcfed4ad..0000000000 --- a/apps/docs/content/components/toast/hidden-icon-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import HiddenIcon from "./hidden-icon.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/hidden-icon.ts b/apps/docs/content/components/toast/hidden-icon.ts index 67e758e000..d3061e5cf3 100644 --- a/apps/docs/content/components/toast/hidden-icon.ts +++ b/apps/docs/content/components/toast/hidden-icon.ts @@ -1,8 +1,6 @@ -import App from "./hidden-icon-root.raw.jsx?raw"; import HiddenIcon from "./hidden-icon.raw.jsx?raw"; const react = { - "/App.jsx": App, "./HiddenIcon.jsx": HiddenIcon, }; diff --git a/apps/docs/content/components/toast/index.ts b/apps/docs/content/components/toast/index.ts index d0139eab1f..de8c8052d9 100644 --- a/apps/docs/content/components/toast/index.ts +++ b/apps/docs/content/components/toast/index.ts @@ -9,7 +9,7 @@ import withTimeout from "./with-timeout"; import radius from "./radius"; import placement from "./placement"; import description from "./description"; -import disableAnimation from "./disable-animation"; +import promise from "./promise"; export const toastContent = { color, @@ -23,5 +23,5 @@ export const toastContent = { radius, placement, description, - disableAnimation, + promise, }; diff --git a/apps/docs/content/components/toast/page.tsx b/apps/docs/content/components/toast/page.tsx deleted file mode 100644 index fb861e5bf2..0000000000 --- a/apps/docs/content/components/toast/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import {addToast, Button, ToastProvider} from "@heroui/react"; - -export default function App() { - return ( - <> - -
- -
- - ); -} diff --git a/apps/docs/content/components/toast/placement-root.raw.jsx b/apps/docs/content/components/toast/placement-root.raw.jsx deleted file mode 100644 index e65d5d9d95..0000000000 --- a/apps/docs/content/components/toast/placement-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import Position from "./placement.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/placement.raw.jsx b/apps/docs/content/components/toast/placement.raw.jsx index 4971929bf4..0073845139 100644 --- a/apps/docs/content/components/toast/placement.raw.jsx +++ b/apps/docs/content/components/toast/placement.raw.jsx @@ -1,8 +1,12 @@ -import {addToast, Button} from "@heroui/react"; +import {addToast, Button, ToastProvider} from "@heroui/react"; +import React from "react"; export default function App() { + const [placement, setPlacement] = React.useState("right-bottom"); + return ( <> +
{[ "left-top", @@ -16,12 +20,13 @@ export default function App() { key={position} className="w-fit m-2" variant={"bordered"} - onPress={() => + onPress={() => { + setPlacement(position); addToast({ title: "Toast title", description: "Toast displayed successfully", - }) - } + }); + }} > Show toast at {position} diff --git a/apps/docs/content/components/toast/placement.ts b/apps/docs/content/components/toast/placement.ts index 5676481105..a745201749 100644 --- a/apps/docs/content/components/toast/placement.ts +++ b/apps/docs/content/components/toast/placement.ts @@ -1,8 +1,6 @@ -import App from "./placement-root.raw.jsx?raw"; import Position from "./placement.raw.jsx?raw"; const react = { - "/App.jsx": App, "Position.jsx": Position, }; diff --git a/apps/docs/content/components/toast/promise-root.raw.jsx b/apps/docs/content/components/toast/promise-root.raw.jsx deleted file mode 100644 index e276ede923..0000000000 --- a/apps/docs/content/components/toast/promise-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import Promise from "./promise.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/promise.ts b/apps/docs/content/components/toast/promise.ts index 5b0ec47d48..bca86211eb 100644 --- a/apps/docs/content/components/toast/promise.ts +++ b/apps/docs/content/components/toast/promise.ts @@ -1,8 +1,6 @@ -import App from "./promise-root.raw.jsx?raw"; import Promise from "./promise.raw.jsx?raw"; const react = { - "/App.jsx": App, "/Promise.jsx": Promise, }; diff --git a/apps/docs/content/components/toast/radius-root.raw.jsx b/apps/docs/content/components/toast/radius-root.raw.jsx deleted file mode 100644 index 2860f73233..0000000000 --- a/apps/docs/content/components/toast/radius-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import Radius from "./radius.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/radius.ts b/apps/docs/content/components/toast/radius.ts index e69eff0068..0f8b2b3df7 100644 --- a/apps/docs/content/components/toast/radius.ts +++ b/apps/docs/content/components/toast/radius.ts @@ -1,8 +1,6 @@ -import App from "./radius-root.raw.jsx?raw"; import Radius from "./radius.raw.jsx?raw"; const react = { - "/App.jsx": App, "/Radius.jsx": Radius, }; diff --git a/apps/docs/content/components/toast/usage-root.raw.jsx b/apps/docs/content/components/toast/usage-root.raw.jsx deleted file mode 100644 index a79bb5d750..0000000000 --- a/apps/docs/content/components/toast/usage-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import Usage from "./usage.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/usage.ts b/apps/docs/content/components/toast/usage.ts index cfc51afbe7..cc1f7a7a1a 100644 --- a/apps/docs/content/components/toast/usage.ts +++ b/apps/docs/content/components/toast/usage.ts @@ -1,8 +1,6 @@ -import App from "./usage-root.raw.jsx?raw"; import Usage from "./usage.raw.jsx?raw"; const react = { - "/App.jsx": App, "/Usage.jsx": Usage, }; diff --git a/apps/docs/content/components/toast/variants-root.raw.jsx b/apps/docs/content/components/toast/variants-root.raw.jsx deleted file mode 100644 index cb09d4c60a..0000000000 --- a/apps/docs/content/components/toast/variants-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import Variants from "./variants.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/variants.ts b/apps/docs/content/components/toast/variants.ts index 8fa6c21c0d..1d12fb0360 100644 --- a/apps/docs/content/components/toast/variants.ts +++ b/apps/docs/content/components/toast/variants.ts @@ -1,8 +1,6 @@ -import App from "./variants-root.raw.jsx?raw"; import Variants from "./variants.raw.jsx?raw"; const react = { - "/App.jsx": App, "/Variants.jsx": Variants, }; diff --git a/apps/docs/content/components/toast/with-action-root.raw.jsx b/apps/docs/content/components/toast/with-action-root.raw.jsx deleted file mode 100644 index 60f3c39a40..0000000000 --- a/apps/docs/content/components/toast/with-action-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import WithAction from "./with-action.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/with-action.ts b/apps/docs/content/components/toast/with-action.ts index e157c3b206..f9321e7d5f 100644 --- a/apps/docs/content/components/toast/with-action.ts +++ b/apps/docs/content/components/toast/with-action.ts @@ -1,8 +1,6 @@ -import App from "./with-action-root.raw.jsx?raw"; import WithAction from "./with-action.raw.jsx?raw"; const react = { - "/App.jsx": App, "/WithAction.jsx": WithAction, }; diff --git a/apps/docs/content/components/toast/with-timeout-root.raw.jsx b/apps/docs/content/components/toast/with-timeout-root.raw.jsx deleted file mode 100644 index 5bc1889f75..0000000000 --- a/apps/docs/content/components/toast/with-timeout-root.raw.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import {ToastProvider} from "@heroui/react"; - -import WithTimeout from "./with-timeout.raw.jsx?raw"; - -export default function App() { - return ( - <> - - - - ); -} diff --git a/apps/docs/content/components/toast/with-timeout.ts b/apps/docs/content/components/toast/with-timeout.ts index eaa3cd7bb7..afc509b915 100644 --- a/apps/docs/content/components/toast/with-timeout.ts +++ b/apps/docs/content/components/toast/with-timeout.ts @@ -1,8 +1,6 @@ -import App from "./with-timeout.raw.jsx?raw"; import WithTimeout from "./with-timeout.raw.jsx?raw"; const react = { - "/App.jsx": App, "/WithTimeout": WithTimeout, }; diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index 6d259bfc11..2a5be20982 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -41,53 +41,29 @@ Toasts are temporary notifications that provide concise feedback about an action ### Usage - + ### With Description - + ### Colors Toast comes with 6 color variants to convey different meanings. - + ### Variants ### Radius @@ -96,10 +72,7 @@ Toast comes with 6 color variants to convey different meanings. By default, Toast displays an appropriate icon based on the `color` prop. You can override this by providing a custom icon using the `icon` prop. @@ -108,10 +81,7 @@ By default, Toast displays an appropriate icon based on the `color` prop. You ca You can hide the icon by setting the `hideIcon` prop to `true`. @@ -120,10 +90,7 @@ You can hide the icon by setting the `hideIcon` prop to `true`. Toast supports an `endContent` prop for additional actions. @@ -132,40 +99,21 @@ Toast supports an `endContent` prop for additional actions. Toast supports an `endContent` prop for additional actions. ### Toast Placement -### Disable Animation - - - ### Promise @@ -174,10 +122,7 @@ Toast supports an `endContent` prop for additional actions. You can customize the alert by passing custom Tailwind CSS classes to the component slots. @@ -323,6 +268,12 @@ Toast has the following slots: description: "Disables the animation.", default: "false" }, + { + attribute: "toastOffset", + type: "number", + description: "offset distance from the top or bottom", + default: "0" + } ]} /> diff --git a/packages/components/toast/src/toast-provider.tsx b/packages/components/toast/src/toast-provider.tsx index 400aa21431..888a9588d5 100644 --- a/packages/components/toast/src/toast-provider.tsx +++ b/packages/components/toast/src/toast-provider.tsx @@ -16,6 +16,7 @@ interface ToastProviderProps { | "left-top" | "center-top"; disableAnimation?: boolean; + toastOffset?: number; } export const getToastQueue = () => { @@ -33,6 +34,7 @@ export const ToastProvider = ({ placement = "right-bottom", disableAnimation: disableAnimationProp = false, maxVisibleToasts = 3, + toastOffset = 0, }: ToastProviderProps) => { const toastQueue = useToastQueue(getToastQueue()); const globalContext = useProviderContext(); @@ -47,6 +49,7 @@ export const ToastProvider = ({ disableAnimation={disableAnimation} maxVisibleToasts={maxVisibleToasts} placement={placement} + toastOffset={toastOffset} toastQueue={toastQueue} /> ); diff --git a/packages/components/toast/src/toast-region.tsx b/packages/components/toast/src/toast-region.tsx index f68e02abf1..d499efca21 100644 --- a/packages/components/toast/src/toast-region.tsx +++ b/packages/components/toast/src/toast-region.tsx @@ -19,6 +19,7 @@ interface ToastRegionProps extends AriaToastRegionProps { | "center-top"; disableAnimation: boolean; maxVisibleToasts: number; + toastOffset?: number; } export function ToastRegion({ @@ -26,6 +27,7 @@ export function ToastRegion({ placement, disableAnimation, maxVisibleToasts, + toastOffset, ...props }: ToastRegionProps) { const ref = useRef(null); @@ -89,6 +91,7 @@ export function ToastRegion({ isRegionExpanded={isHovered || isTouched} placement={placement} setHeights={setHeights} + toastOffset={toastOffset} total={total} /> ); diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 771e6975d1..75b6489c9c 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -95,6 +95,7 @@ interface Props extends HTMLHeroUIProps<"div">, ToastProps { | "right-top" | "left-top" | "center-top"; + toastOffset?: number; } export type UseToastProps = Props & @@ -121,6 +122,7 @@ export function useToast(originalProps: UseToastProps) heights, promise: promiseProp, setHeights, + toastOffset = 0, ...otherProps } = props; @@ -434,12 +436,18 @@ export function useToast(originalProps: UseToastProps) const animateProps = (() => { if (placement.includes("top")) { return { - top: isRegionExpanded || drag ? liftHeight : (total - 1 - index) * 8, + top: + isRegionExpanded || drag + ? liftHeight + toastOffset + : (total - 1 - index) * 8 + toastOffset, bottom: "auto", }; } else if (placement.includes("bottom")) { return { - bottom: isRegionExpanded || drag ? liftHeight : (total - 1 - index) * 8, + bottom: + isRegionExpanded || drag + ? liftHeight + toastOffset + : (total - 1 - index) * 8 + toastOffset, top: "auto", }; } diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 46ec5b457c..4e5328c9cd 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -4,7 +4,7 @@ import {tv} from "../utils/tv"; const toastRegion = tv({ slots: { - base: "", + base: "relative z-50", }, variants: { disableAnimation: { @@ -35,7 +35,7 @@ const toast = tv({ "group", "cursor-pointer", "relative", - "z-[9999]", + "z-50", "box-border", "outline-none", "p-3 sm:mx-1", From f08752be9d3909bf9066e2689215e8e95b0c555d Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Tue, 21 Jan 2025 19:25:10 +0530 Subject: [PATCH 43/49] chore: removing nextui references --- apps/docs/content/docs/components/toast.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index 2a5be20982..d005aafded 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -21,10 +21,10 @@ Toasts are temporary notifications that provide concise feedback about an action showGlobalInstallWarning commands={{ cli: "npx nextui-cli@latest add toast", - npm: "npm install @nextui-org/toast", - yarn: "yarn add @nextui-org/toast", - pnpm: "pnpm add @nextui-org/toast", - bun: "bun add @nextui-org/toast", + npm: "npm install @heroui/toast", + yarn: "yarn add @heroui/toast", + pnpm: "pnpm add @heroui/toast", + bun: "bun add @heroui/toast", }} /> @@ -33,7 +33,7 @@ Toasts are temporary notifications that provide concise feedback about an action From 383833e7f8f06e27b9d0dc2ab66bc2f61d3c8c08 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Tue, 21 Jan 2025 19:57:40 +0530 Subject: [PATCH 44/49] chore: adding info about the provider --- apps/docs/content/components/toast/index.ts | 2 ++ apps/docs/content/components/toast/provider.raw.jsx | 5 +++++ apps/docs/content/components/toast/provider.ts | 9 +++++++++ apps/docs/content/docs/components/toast.mdx | 6 +++++- packages/core/theme/src/components/toast.ts | 1 + 5 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 apps/docs/content/components/toast/provider.raw.jsx create mode 100644 apps/docs/content/components/toast/provider.ts diff --git a/apps/docs/content/components/toast/index.ts b/apps/docs/content/components/toast/index.ts index de8c8052d9..75c266e711 100644 --- a/apps/docs/content/components/toast/index.ts +++ b/apps/docs/content/components/toast/index.ts @@ -10,6 +10,7 @@ import radius from "./radius"; import placement from "./placement"; import description from "./description"; import promise from "./promise"; +import provider from "./provider"; export const toastContent = { color, @@ -24,4 +25,5 @@ export const toastContent = { placement, description, promise, + provider, }; diff --git a/apps/docs/content/components/toast/provider.raw.jsx b/apps/docs/content/components/toast/provider.raw.jsx new file mode 100644 index 0000000000..a5c8fe6dce --- /dev/null +++ b/apps/docs/content/components/toast/provider.raw.jsx @@ -0,0 +1,5 @@ +import {ToastProvider} from "@heroui/toast"; + +export default function App({children}) { + return {children}; +} diff --git a/apps/docs/content/components/toast/provider.ts b/apps/docs/content/components/toast/provider.ts new file mode 100644 index 0000000000..25c433ea86 --- /dev/null +++ b/apps/docs/content/components/toast/provider.ts @@ -0,0 +1,9 @@ +import Provider from "./provider.raw.jsx?raw"; + +const react = { + "/App.jsx": Provider, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index d005aafded..38f99e27e0 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -37,7 +37,11 @@ Toasts are temporary notifications that provide concise feedback about an action }} /> -> **Note**: Before using the addToast function, ensure you have added `ToastProvider` to your application (or the relevant part of it). This is necessary to initialize the context for managing toasts. +## Requirement + +The ToastProvider must be added to the application's root (or the relevant part of it) before using the addToast function. This is required to initialize the context for managing toasts. + + ### Usage diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index 4e5328c9cd..daf91092a4 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -140,6 +140,7 @@ const toast = tv({ closeButton: "transition-opacity ease-in duration-300", base: [ "data-[animation=exiting]:transform", + "data-[animation=exiting]:delay-100", "data-[animation=exiting]:data-[placement=right-bottom]:translate-x-28", "data-[animation=exiting]:data-[placement=left-bottom]:-translate-x-28", "data-[animation=exiting]:data-[placement=center-bottom]:translate-y-28", From 993c64a26bfddeac5e41697f97f05d8b792e4613 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Tue, 21 Jan 2025 22:41:30 +0530 Subject: [PATCH 45/49] chore: updating the docs --- .../content/components/toast/color.raw.jsx | 5 +- .../components/toast/custom-icon.raw.jsx | 37 ------ .../content/components/toast/custom-icon.ts | 9 -- .../components/toast/custom-styles.raw.jsx | 2 +- .../components/toast/description.raw.jsx | 17 --- .../content/components/toast/description.ts | 9 -- .../components/toast/hidden-icon.raw.jsx | 22 ---- .../content/components/toast/hidden-icon.ts | 9 -- apps/docs/content/components/toast/index.ts | 16 +-- .../components/toast/placement.raw.jsx | 5 +- .../content/components/toast/promise.raw.jsx | 21 ---- apps/docs/content/components/toast/promise.ts | 9 -- .../content/components/toast/radius.raw.jsx | 7 +- .../content/components/toast/types.raw.jsx | 114 ++++++++++++++++++ apps/docs/content/components/toast/types.ts | 9 ++ .../content/components/toast/usage.raw.jsx | 18 --- apps/docs/content/components/toast/usage.ts | 9 -- .../content/components/toast/variants.raw.jsx | 16 ++- .../components/toast/with-action.raw.jsx | 25 ---- .../content/components/toast/with-action.ts | 9 -- .../components/toast/with-timeout.raw.jsx | 20 --- .../content/components/toast/with-timeout.ts | 9 -- apps/docs/content/docs/components/toast.mdx | 49 +------- 23 files changed, 144 insertions(+), 302 deletions(-) delete mode 100644 apps/docs/content/components/toast/custom-icon.raw.jsx delete mode 100644 apps/docs/content/components/toast/custom-icon.ts delete mode 100644 apps/docs/content/components/toast/description.raw.jsx delete mode 100644 apps/docs/content/components/toast/description.ts delete mode 100644 apps/docs/content/components/toast/hidden-icon.raw.jsx delete mode 100644 apps/docs/content/components/toast/hidden-icon.ts delete mode 100644 apps/docs/content/components/toast/promise.raw.jsx delete mode 100644 apps/docs/content/components/toast/promise.ts create mode 100644 apps/docs/content/components/toast/types.raw.jsx create mode 100644 apps/docs/content/components/toast/types.ts delete mode 100644 apps/docs/content/components/toast/usage.raw.jsx delete mode 100644 apps/docs/content/components/toast/usage.ts delete mode 100644 apps/docs/content/components/toast/with-action.raw.jsx delete mode 100644 apps/docs/content/components/toast/with-action.ts delete mode 100644 apps/docs/content/components/toast/with-timeout.raw.jsx delete mode 100644 apps/docs/content/components/toast/with-timeout.ts diff --git a/apps/docs/content/components/toast/color.raw.jsx b/apps/docs/content/components/toast/color.raw.jsx index 4ba2590025..707054c1e4 100644 --- a/apps/docs/content/components/toast/color.raw.jsx +++ b/apps/docs/content/components/toast/color.raw.jsx @@ -7,10 +7,9 @@ export default function App() { {["default", "primary", "secondary", "success", "warning", "danger"].map((color) => ( ))}
diff --git a/apps/docs/content/components/toast/custom-icon.raw.jsx b/apps/docs/content/components/toast/custom-icon.raw.jsx deleted file mode 100644 index 6a4ff51391..0000000000 --- a/apps/docs/content/components/toast/custom-icon.raw.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> - - - ); -} diff --git a/apps/docs/content/components/toast/custom-icon.ts b/apps/docs/content/components/toast/custom-icon.ts deleted file mode 100644 index 652b428602..0000000000 --- a/apps/docs/content/components/toast/custom-icon.ts +++ /dev/null @@ -1,9 +0,0 @@ -import CustomIcon from "./custom-icon.raw.jsx?raw"; - -const react = { - "/CustomIcon.jsx": CustomIcon, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/custom-styles.raw.jsx b/apps/docs/content/components/toast/custom-styles.raw.jsx index 004003b942..f312540a67 100644 --- a/apps/docs/content/components/toast/custom-styles.raw.jsx +++ b/apps/docs/content/components/toast/custom-styles.raw.jsx @@ -4,7 +4,7 @@ const CustomToastComponent = () => { return ( <> - - ); -} diff --git a/apps/docs/content/components/toast/description.ts b/apps/docs/content/components/toast/description.ts deleted file mode 100644 index 51cfb6c296..0000000000 --- a/apps/docs/content/components/toast/description.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Usage from "./description.raw.jsx?raw"; - -const react = { - "/Description.jsx": Usage, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/hidden-icon.raw.jsx b/apps/docs/content/components/toast/hidden-icon.raw.jsx deleted file mode 100644 index 95cba0041a..0000000000 --- a/apps/docs/content/components/toast/hidden-icon.raw.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> -
- -
- - ); -} diff --git a/apps/docs/content/components/toast/hidden-icon.ts b/apps/docs/content/components/toast/hidden-icon.ts deleted file mode 100644 index d3061e5cf3..0000000000 --- a/apps/docs/content/components/toast/hidden-icon.ts +++ /dev/null @@ -1,9 +0,0 @@ -import HiddenIcon from "./hidden-icon.raw.jsx?raw"; - -const react = { - "./HiddenIcon.jsx": HiddenIcon, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/index.ts b/apps/docs/content/components/toast/index.ts index 75c266e711..e0fa7a3ccc 100644 --- a/apps/docs/content/components/toast/index.ts +++ b/apps/docs/content/components/toast/index.ts @@ -1,29 +1,17 @@ import color from "./color"; -import usage from "./usage"; import variants from "./variants"; -import customIcon from "./custom-icon"; -import hiddenIcon from "./hidden-icon"; -import withAction from "./with-action"; import customStyles from "./custom-styles"; -import withTimeout from "./with-timeout"; import radius from "./radius"; import placement from "./placement"; -import description from "./description"; -import promise from "./promise"; import provider from "./provider"; +import types from "./types"; export const toastContent = { color, - usage, variants, - customIcon, - hiddenIcon, - withAction, customStyles, - withTimeout, radius, placement, - description, - promise, provider, + types, }; diff --git a/apps/docs/content/components/toast/placement.raw.jsx b/apps/docs/content/components/toast/placement.raw.jsx index 0073845139..6cce5eec69 100644 --- a/apps/docs/content/components/toast/placement.raw.jsx +++ b/apps/docs/content/components/toast/placement.raw.jsx @@ -18,8 +18,7 @@ export default function App() { ].map((position) => ( ))}
diff --git a/apps/docs/content/components/toast/promise.raw.jsx b/apps/docs/content/components/toast/promise.raw.jsx deleted file mode 100644 index 22ae33ca2c..0000000000 --- a/apps/docs/content/components/toast/promise.raw.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> -
- -
- - ); -} diff --git a/apps/docs/content/components/toast/promise.ts b/apps/docs/content/components/toast/promise.ts deleted file mode 100644 index bca86211eb..0000000000 --- a/apps/docs/content/components/toast/promise.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Promise from "./promise.raw.jsx?raw"; - -const react = { - "/Promise.jsx": Promise, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/radius.raw.jsx b/apps/docs/content/components/toast/radius.raw.jsx index b2f3f05420..ff1b66b66e 100644 --- a/apps/docs/content/components/toast/radius.raw.jsx +++ b/apps/docs/content/components/toast/radius.raw.jsx @@ -7,19 +7,18 @@ export default function App() { {["none", "sm", "md", "lg", "full"].map((radius) => ( ))}
diff --git a/apps/docs/content/components/toast/types.raw.jsx b/apps/docs/content/components/toast/types.raw.jsx new file mode 100644 index 0000000000..79a2893450 --- /dev/null +++ b/apps/docs/content/components/toast/types.raw.jsx @@ -0,0 +1,114 @@ +import {addToast, Button} from "@heroui/react"; + +export default function App() { + return ( +
+ + + + + + + + + + ), + variant: "faded", + }); + }} + > + With Action + + + + + +
+ ); +} diff --git a/apps/docs/content/components/toast/types.ts b/apps/docs/content/components/toast/types.ts new file mode 100644 index 0000000000..1e9d3ad1b4 --- /dev/null +++ b/apps/docs/content/components/toast/types.ts @@ -0,0 +1,9 @@ +import Types from "./types.raw.jsx?raw"; + +const react = { + "/Types.jsx": Types, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/toast/usage.raw.jsx b/apps/docs/content/components/toast/usage.raw.jsx deleted file mode 100644 index 76be12764d..0000000000 --- a/apps/docs/content/components/toast/usage.raw.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> - - - ); -} diff --git a/apps/docs/content/components/toast/usage.ts b/apps/docs/content/components/toast/usage.ts deleted file mode 100644 index cc1f7a7a1a..0000000000 --- a/apps/docs/content/components/toast/usage.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Usage from "./usage.raw.jsx?raw"; - -const react = { - "/Usage.jsx": Usage, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/variants.raw.jsx b/apps/docs/content/components/toast/variants.raw.jsx index db526feef0..b74e4f215f 100644 --- a/apps/docs/content/components/toast/variants.raw.jsx +++ b/apps/docs/content/components/toast/variants.raw.jsx @@ -4,22 +4,26 @@ export default function App() { return ( <>
- {["solid", "bordered", "flat", "faded"].map((variant) => ( + {[ + ["solid", "solid"], + ["bordered", "bordered"], + ["flat", "faded"], + ].map((variant) => ( ))}
diff --git a/apps/docs/content/components/toast/with-action.raw.jsx b/apps/docs/content/components/toast/with-action.raw.jsx deleted file mode 100644 index 59351874d3..0000000000 --- a/apps/docs/content/components/toast/with-action.raw.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> - - ), - color: "warning", - variant: "faded", - }); - }} - > - Show Toast - - - ); -} diff --git a/apps/docs/content/components/toast/with-action.ts b/apps/docs/content/components/toast/with-action.ts deleted file mode 100644 index f9321e7d5f..0000000000 --- a/apps/docs/content/components/toast/with-action.ts +++ /dev/null @@ -1,9 +0,0 @@ -import WithAction from "./with-action.raw.jsx?raw"; - -const react = { - "/WithAction.jsx": WithAction, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/components/toast/with-timeout.raw.jsx b/apps/docs/content/components/toast/with-timeout.raw.jsx deleted file mode 100644 index e91ad63c91..0000000000 --- a/apps/docs/content/components/toast/with-timeout.raw.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import {addToast, Button} from "@heroui/react"; - -export default function App() { - return ( - <> - - - ); -} diff --git a/apps/docs/content/components/toast/with-timeout.ts b/apps/docs/content/components/toast/with-timeout.ts deleted file mode 100644 index afc509b915..0000000000 --- a/apps/docs/content/components/toast/with-timeout.ts +++ /dev/null @@ -1,9 +0,0 @@ -import WithTimeout from "./with-timeout.raw.jsx?raw"; - -const react = { - "/WithTimeout": WithTimeout, -}; - -export default { - ...react, -}; diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index 38f99e27e0..651a4b381c 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -45,11 +45,7 @@ The ToastProvider must be added to the application's root (or the relevant part ### Usage - - -### With Description - - + ### Colors @@ -71,42 +67,6 @@ Toast comes with 6 color variants to convey different meanings. files={toastContent.radius} /> -### Custom Icon - -By default, Toast displays an appropriate icon based on the `color` prop. You can override this by providing a custom icon using the `icon` prop. - - - -### Icon Hidden - -You can hide the icon by setting the `hideIcon` prop to `true`. - - - -### With Action - -Toast supports an `endContent` prop for additional actions. - - - -### With Timeout - -Toast supports an `endContent` prop for additional actions. - - - ### Toast Placement -### Promise - - - ### Custom Styles You can customize the alert by passing custom Tailwind CSS classes to the component slots. From 6190836ba007182d18d556780526d50df865ffc5 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Tue, 21 Jan 2025 23:06:52 +0530 Subject: [PATCH 46/49] chore: versions in package.json --- packages/components/toast/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/toast/package.json b/packages/components/toast/package.json index 71efef54fb..09f7e7c2cd 100644 --- a/packages/components/toast/package.json +++ b/packages/components/toast/package.json @@ -34,8 +34,8 @@ "postpack": "clean-package restore" }, "peerDependencies": { - "@heroui/system": ">=2.4.8", - "@heroui/theme": ">=2.4.7", + "@heroui/system": ">=2.4.7", + "@heroui/theme": ">=2.4.6", "react": ">=18 || >=19.0.0-rc.0", "react-dom": ">=18 || >=19.0.0-rc.0", "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1" From 05e06b97604ba56f7ed0e93486795925adee4fe6 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Tue, 21 Jan 2025 23:34:51 +0530 Subject: [PATCH 47/49] chore: nits --- apps/docs/content/components/toast/color.ts | 2 +- apps/docs/content/components/toast/custom-styles.ts | 2 +- apps/docs/content/components/toast/placement.ts | 2 +- apps/docs/content/components/toast/radius.ts | 2 +- apps/docs/content/components/toast/types.ts | 2 +- apps/docs/content/components/toast/variants.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/docs/content/components/toast/color.ts b/apps/docs/content/components/toast/color.ts index b97ae00b84..aa4bbbef42 100644 --- a/apps/docs/content/components/toast/color.ts +++ b/apps/docs/content/components/toast/color.ts @@ -1,7 +1,7 @@ import Color from "./color.raw.jsx?raw"; const react = { - "/Color.jsx": Color, + "/App.jsx": Color, }; export default { diff --git a/apps/docs/content/components/toast/custom-styles.ts b/apps/docs/content/components/toast/custom-styles.ts index b48bc3735c..c06cbb432a 100644 --- a/apps/docs/content/components/toast/custom-styles.ts +++ b/apps/docs/content/components/toast/custom-styles.ts @@ -1,7 +1,7 @@ import CustomStyles from "./custom-styles.raw.jsx?raw"; const react = { - "CustomStyles.jsx": CustomStyles, + "/App.jsx": CustomStyles, }; export default { diff --git a/apps/docs/content/components/toast/placement.ts b/apps/docs/content/components/toast/placement.ts index a745201749..10b1290e9a 100644 --- a/apps/docs/content/components/toast/placement.ts +++ b/apps/docs/content/components/toast/placement.ts @@ -1,7 +1,7 @@ import Position from "./placement.raw.jsx?raw"; const react = { - "Position.jsx": Position, + "/App.jsx": Position, }; export default { diff --git a/apps/docs/content/components/toast/radius.ts b/apps/docs/content/components/toast/radius.ts index 0f8b2b3df7..3ea70cfc93 100644 --- a/apps/docs/content/components/toast/radius.ts +++ b/apps/docs/content/components/toast/radius.ts @@ -1,7 +1,7 @@ import Radius from "./radius.raw.jsx?raw"; const react = { - "/Radius.jsx": Radius, + "/App.jsx": Radius, }; export default { diff --git a/apps/docs/content/components/toast/types.ts b/apps/docs/content/components/toast/types.ts index 1e9d3ad1b4..18f08c4d0b 100644 --- a/apps/docs/content/components/toast/types.ts +++ b/apps/docs/content/components/toast/types.ts @@ -1,7 +1,7 @@ import Types from "./types.raw.jsx?raw"; const react = { - "/Types.jsx": Types, + "/App.jsx": Types, }; export default { diff --git a/apps/docs/content/components/toast/variants.ts b/apps/docs/content/components/toast/variants.ts index 1d12fb0360..a713048338 100644 --- a/apps/docs/content/components/toast/variants.ts +++ b/apps/docs/content/components/toast/variants.ts @@ -1,7 +1,7 @@ import Variants from "./variants.raw.jsx?raw"; const react = { - "/Variants.jsx": Variants, + "/App.jsx": Variants, }; export default { From 18455c7971257359da5cfd2cbbca0e7c0b2270e7 Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 22 Jan 2025 00:18:33 +0530 Subject: [PATCH 48/49] chore: adding junior's suggestions --- .changeset/shaggy-beers-breathe.md | 6 +- .../content/components/toast/color.raw.jsx | 40 ++++----- .../components/toast/custom-styles.raw.jsx | 82 +++++++++---------- apps/docs/content/components/toast/index.ts | 4 +- .../components/toast/placement.raw.jsx | 2 +- .../content/components/toast/radius.raw.jsx | 39 ++++----- .../toast/{types.raw.jsx => usage.raw.jsx} | 11 ++- .../components/toast/{types.ts => usage.ts} | 2 +- .../content/components/toast/variants.raw.jsx | 50 ++++++----- apps/docs/content/docs/components/toast.mdx | 22 +++-- packages/components/toast/src/use-toast.ts | 6 ++ .../toast/stories/toast.stories.tsx | 5 ++ packages/core/theme/src/components/toast.ts | 1 + 13 files changed, 142 insertions(+), 128 deletions(-) rename apps/docs/content/components/toast/{types.raw.jsx => usage.raw.jsx} (94%) rename apps/docs/content/components/toast/{types.ts => usage.ts} (64%) diff --git a/.changeset/shaggy-beers-breathe.md b/.changeset/shaggy-beers-breathe.md index 3e6f439b12..2b643c4369 100644 --- a/.changeset/shaggy-beers-breathe.md +++ b/.changeset/shaggy-beers-breathe.md @@ -1,7 +1,7 @@ --- -"@nextui-org/shared-icons": patch -"@nextui-org/toast": patch -"@nextui-org/theme": patch +"@heroui/shared-icons": patch +"@heroui/toast": patch +"@heroui/theme": patch --- Introducing the toast component(#2560) diff --git a/apps/docs/content/components/toast/color.raw.jsx b/apps/docs/content/components/toast/color.raw.jsx index 707054c1e4..dfe8aa87ca 100644 --- a/apps/docs/content/components/toast/color.raw.jsx +++ b/apps/docs/content/components/toast/color.raw.jsx @@ -2,27 +2,23 @@ import {addToast, Button} from "@heroui/react"; export default function App() { return ( - <> -
- {["default", "primary", "secondary", "success", "warning", "danger"].map((color) => ( - - ))} -
- +
+ {["default", "primary", "secondary", "success", "warning", "danger"].map((color) => ( + + ))} +
); } diff --git a/apps/docs/content/components/toast/custom-styles.raw.jsx b/apps/docs/content/components/toast/custom-styles.raw.jsx index f312540a67..1c69523148 100644 --- a/apps/docs/content/components/toast/custom-styles.raw.jsx +++ b/apps/docs/content/components/toast/custom-styles.raw.jsx @@ -2,53 +2,49 @@ import {addToast, Button, cn} from "@heroui/react"; const CustomToastComponent = () => { return ( - <> - - -
- ), - }); - }} - > - Show Toast - - + + +
+ ), + }); + }} + > + Show Toast + ); }; export default function App() { return ( - <> -
- -
- +
+ +
); } diff --git a/apps/docs/content/components/toast/index.ts b/apps/docs/content/components/toast/index.ts index e0fa7a3ccc..5804cb6cb7 100644 --- a/apps/docs/content/components/toast/index.ts +++ b/apps/docs/content/components/toast/index.ts @@ -4,7 +4,7 @@ import customStyles from "./custom-styles"; import radius from "./radius"; import placement from "./placement"; import provider from "./provider"; -import types from "./types"; +import usage from "./usage"; export const toastContent = { color, @@ -13,5 +13,5 @@ export const toastContent = { radius, placement, provider, - types, + usage, }; diff --git a/apps/docs/content/components/toast/placement.raw.jsx b/apps/docs/content/components/toast/placement.raw.jsx index 6cce5eec69..ead0ab32a1 100644 --- a/apps/docs/content/components/toast/placement.raw.jsx +++ b/apps/docs/content/components/toast/placement.raw.jsx @@ -18,7 +18,7 @@ export default function App() { ].map((position) => ( - ))} - - +
+ {["none", "sm", "md", "lg", "full"].map((radius) => ( + + ))} +
); } diff --git a/apps/docs/content/components/toast/types.raw.jsx b/apps/docs/content/components/toast/usage.raw.jsx similarity index 94% rename from apps/docs/content/components/toast/types.raw.jsx rename to apps/docs/content/components/toast/usage.raw.jsx index 79a2893450..ff007553eb 100644 --- a/apps/docs/content/components/toast/types.raw.jsx +++ b/apps/docs/content/components/toast/usage.raw.jsx @@ -4,7 +4,7 @@ export default function App() { return (
- ))} -
- +
+ {[ + ["solid", "solid"], + ["bordered", "bordered"], + ["flat", "faded"], + ].map((variant) => ( + + ))} +
); } diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx index 651a4b381c..b492d81dd2 100644 --- a/apps/docs/content/docs/components/toast.mdx +++ b/apps/docs/content/docs/components/toast.mdx @@ -20,7 +20,7 @@ Toasts are temporary notifications that provide concise feedback about an action ### Usage - + ### Colors @@ -154,7 +154,7 @@ Toast has the following slots: }, { attribute: "variant", - type: "solid | bordered | flat | faded", + type: "solid | bordered | flat", description: "The alert variant", default: "flat" }, @@ -197,9 +197,21 @@ Toast has the following slots: { attribute: "hideIcon", type: "boolean", - description: "Whether the icon is hidden", + description: "Hides icon when true", default: "false" }, + { + attribute: "hideCloseButton", + type: "boolean", + description: "Hides closeButton when true", + default: "false" + }, + { + attribute: "classNames", + type: "Partial>", + description: "Allows to set custom class names for the toast slots.", + default: "-" + } ]} /> diff --git a/packages/components/toast/src/use-toast.ts b/packages/components/toast/src/use-toast.ts index 75b6489c9c..ab7ffe1718 100644 --- a/packages/components/toast/src/use-toast.ts +++ b/packages/components/toast/src/use-toast.ts @@ -73,6 +73,10 @@ export interface ToastProps extends ToastVariantProps { * Time to auto-close the toast. */ timeout?: number; + /** + * hides the close button + */ + hideCloseButton?: boolean; /** * function which is called when toast is closed. */ @@ -116,6 +120,7 @@ export function useToast(originalProps: UseToastProps) hideIcon = false, placement: placementProp = "right-bottom", isRegionExpanded, + hideCloseButton = false, state, total = 1, index = 0, @@ -405,6 +410,7 @@ export function useToast(originalProps: UseToastProps) (props = {}) => ({ className: slots.closeButton({class: classNames?.closeButton}), "aria-label": "closeButton", + "data-hidden": dataAttr(hideCloseButton), ...mergeProps(props, closeButtonProps, {onPress: originalProps.onClose}), }), [closeButtonProps], diff --git a/packages/components/toast/stories/toast.stories.tsx b/packages/components/toast/stories/toast.stories.tsx index 1546c67ab5..2165e2f1d0 100644 --- a/packages/components/toast/stories/toast.stories.tsx +++ b/packages/components/toast/stories/toast.stories.tsx @@ -45,6 +45,11 @@ export default { "center-top", ], }, + hideCloseButton: { + control: { + type: "boolean", + }, + }, }, decorators: [ (Story) => ( diff --git a/packages/core/theme/src/components/toast.ts b/packages/core/theme/src/components/toast.ts index daf91092a4..4704a52ab6 100644 --- a/packages/core/theme/src/components/toast.ts +++ b/packages/core/theme/src/components/toast.ts @@ -62,6 +62,7 @@ const toast = tv({ ], closeButton: [ "opacity-0 p-0 group-hover:opacity-100 w-6 h-6 min-w-4 absolute -right-2 -top-2 items-center justify-center bg-transparent text-default-400 hover:text-default-600 border border-3 border-transparent", + "data-[hidden=true]:hidden", ], closeIcon: ["rounded-full w-full h-full p-0.5 border border-default-400 bg-default-100"], }, From 5904d13d17fa2e4a80ff68092c28c074a9d6a32e Mon Sep 17 00:00:00 2001 From: Maharshi Alpesh Date: Wed, 22 Jan 2025 10:20:41 +0530 Subject: [PATCH 49/49] chore: nits --- apps/docs/content/components/toast/color.raw.jsx | 2 +- apps/docs/content/components/toast/placement.raw.jsx | 2 +- apps/docs/content/components/toast/radius.raw.jsx | 2 +- apps/docs/content/components/toast/variants.raw.jsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/components/toast/color.raw.jsx b/apps/docs/content/components/toast/color.raw.jsx index dfe8aa87ca..32c6c8ddaa 100644 --- a/apps/docs/content/components/toast/color.raw.jsx +++ b/apps/docs/content/components/toast/color.raw.jsx @@ -2,7 +2,7 @@ import {addToast, Button} from "@heroui/react"; export default function App() { return ( -
+
{["default", "primary", "secondary", "success", "warning", "danger"].map((color) => (