From 9e2c652849d68856cacb8a74f428a3e3f45c91b7 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 25 Aug 2025 16:24:36 +0530 Subject: [PATCH 1/9] * chore: migrated toast to base ui toast * chore: added toast to propel package --- .../src/spinners/circular-bar-spinner.tsx | 35 +++ .../propel/src/spinners/circular-spinner.tsx | 33 +++ packages/propel/src/spinners/index.ts | 2 + packages/propel/src/toast/index.tsx | 219 ++++++++++++++++++ 4 files changed, 289 insertions(+) create mode 100644 packages/propel/src/spinners/circular-bar-spinner.tsx create mode 100644 packages/propel/src/spinners/circular-spinner.tsx create mode 100644 packages/propel/src/spinners/index.ts create mode 100644 packages/propel/src/toast/index.tsx diff --git a/packages/propel/src/spinners/circular-bar-spinner.tsx b/packages/propel/src/spinners/circular-bar-spinner.tsx new file mode 100644 index 00000000000..3be8af43aad --- /dev/null +++ b/packages/propel/src/spinners/circular-bar-spinner.tsx @@ -0,0 +1,35 @@ +import * as React from "react"; + +interface ICircularBarSpinner extends React.SVGAttributes { + height?: string; + width?: string; + className?: string | undefined; +} + +export const CircularBarSpinner: React.FC = ({ + height = "16px", + width = "16px", + className = "", +}) => ( +
+ + + + + + + + + + + + +
+); diff --git a/packages/propel/src/spinners/circular-spinner.tsx b/packages/propel/src/spinners/circular-spinner.tsx new file mode 100644 index 00000000000..f447020e83f --- /dev/null +++ b/packages/propel/src/spinners/circular-spinner.tsx @@ -0,0 +1,33 @@ +import * as React from "react"; +// helpers +import clsx from "clsx"; + +export interface ISpinner extends React.SVGAttributes { + height?: string; + width?: string; + className?: string | undefined; +} + +export const Spinner: React.FC = ({ height = "32px", width = "32px", className = "" }) => ( +
+ + Loading... +
+); diff --git a/packages/propel/src/spinners/index.ts b/packages/propel/src/spinners/index.ts new file mode 100644 index 00000000000..a871a9b77b8 --- /dev/null +++ b/packages/propel/src/spinners/index.ts @@ -0,0 +1,2 @@ +export * from "./circular-spinner"; +export * from "./circular-bar-spinner"; diff --git a/packages/propel/src/toast/index.tsx b/packages/propel/src/toast/index.tsx new file mode 100644 index 00000000000..15d686faa4f --- /dev/null +++ b/packages/propel/src/toast/index.tsx @@ -0,0 +1,219 @@ +import { Toast as BaseToast } from "@base-ui-components/react/toast"; +import { AlertTriangle, CheckCircle2, X, XCircle } from "lucide-react"; +import * as React from "react"; +// spinner +import { CircularBarSpinner } from "../spinners/circular-bar-spinner"; +// helper +import clsx from "clsx"; + +export enum TOAST_TYPE { + SUCCESS = "success", + ERROR = "error", + INFO = "info", + WARNING = "warning", + LOADING = "loading", +} + +type SetToastProps = + | { + type: TOAST_TYPE.LOADING; + title?: string; + } + | { + id?: string | number; + type: Exclude; + title: string; + message?: string; + actionItems?: React.ReactNode; + }; + +type PromiseToastCallback = (data: ToastData) => string; +type ActionItemsPromiseToastCallback = (data: ToastData) => React.ReactNode; + +type PromiseToastData = { + title: string; + message?: PromiseToastCallback; + actionItems?: ActionItemsPromiseToastCallback; +}; + +type PromiseToastOptions = { + loading?: string; + success: PromiseToastData; + error: PromiseToastData; +}; + +type ToastContentProps = { + toastId: string | number; + icon?: React.ReactNode; + textColorClassName: string; + backgroundColorClassName: string; + borderColorClassName: string; +}; + +export type ToastProps = { + theme: "light" | "dark" | "system"; +}; + +const toastManager = BaseToast.createToastManager(); + +export const Toast = (props: ToastProps) => ( + + + + + + + +); + +const TOAST_DATA = { + [TOAST_TYPE.SUCCESS]: { + icon: , + textColorClassName: "text-toast-text-success", + backgroundColorClassName: "bg-toast-background-success", + borderColorClassName: "border-toast-border-success", + }, + [TOAST_TYPE.ERROR]: { + icon: , + textColorClassName: "text-toast-text-error", + backgroundColorClassName: "bg-toast-background-error", + borderColorClassName: "border-toast-border-error", + }, + [TOAST_TYPE.WARNING]: { + icon: , + textColorClassName: "text-toast-text-warning", + backgroundColorClassName: "bg-toast-background-warning", + borderColorClassName: "border-toast-border-warning", + }, + [TOAST_TYPE.INFO]: { + icon: <>, + textColorClassName: "text-toast-text-info", + backgroundColorClassName: "bg-toast-background-info", + borderColorClassName: "border-toast-border-info", + }, + [TOAST_TYPE.LOADING]: { + icon: , + textColorClassName: "text-toast-text-loading", + backgroundColorClassName: "bg-toast-background-loading", + borderColorClassName: "border-toast-border-loading", + }, +}; +const ToastList = () => { + const { toasts } = BaseToast.useToastManager(); + return toasts.map((toast) => ); +}; + +const ToastRender = ({ id, toast }: { id: string; toast: BaseToast.Root.ToastObject }) => { + const toastData = toast.data as SetToastProps; + const type = toastData.type as TOAST_TYPE; + const data = TOAST_DATA[type]; + + return ( + { + e.stopPropagation(); + e.preventDefault(); + }} + > + {toastData.type === TOAST_TYPE.LOADING ? ( +
+ {data.icon &&
{data.icon}
} +
+
+ {toastData.title ?? "Loading..."} +
+ + + +
+
+ ) : ( + <> + + + +
+
+ {data.icon &&
{data.icon}
} +
+ + {toastData.title} + + {toastData.message && ( + + {toastData.message} + + )} +
+
+ {toastData.actionItems &&
{toastData.actionItems}
} +
+ + )} +
+ ); +}; + +export const setToast = (props: SetToastProps) => { + if (props.type != TOAST_TYPE.LOADING) { + toastManager.add({ + data: { + type: props.type, + title: props.title, + message: props.message, + actionItems: props.actionItems, + }, + }); + } +}; + +export const setPromiseToast = ( + promise: Promise, + options: PromiseToastOptions +): void => { + toastManager.promise(promise, { + loading: { + data: { + title: options.loading ?? "Loading...", + type: TOAST_TYPE.LOADING, + message: undefined, + actionItems: undefined, + }, + }, + success: (data) => { + return { + data: { + type: TOAST_TYPE.SUCCESS, + title: options.success.title, + message: options.success.message?.(data), + actionItems: options.success.actionItems?.(data), + }, + }; + }, + error: (data) => { + return { + data: { + type: TOAST_TYPE.ERROR, + title: options.error.title, + message: options.error.message?.(data), + actionItems: options.error.actionItems?.(data), + }, + }; + }, + }); +}; From b5df4ef092bfe8cc2d3a748bb11f08c7027bc13f Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 25 Aug 2025 17:04:12 +0530 Subject: [PATCH 2/9] fix: lint errors --- packages/propel/package.json | 3 +- .../propel/src/spinners/circular-spinner.tsx | 4 +- packages/propel/src/toast/index.tsx | 59 +++++++++++-------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/propel/package.json b/packages/propel/package.json index b18bd730c65..e3b0a0cbee3 100644 --- a/packages/propel/package.json +++ b/packages/propel/package.json @@ -23,7 +23,8 @@ "./combobox": "./src/combobox/index.ts", "./tooltip": "./src/tooltip/index.ts", "./styles/fonts": "./src/styles/fonts/index.css", - "./switch": "./src/switch/index.ts" + "./switch": "./src/switch/index.ts", + "./toast": "./src/toast/index.ts" }, "dependencies": { "@base-ui-components/react": "^1.0.0-beta.2", diff --git a/packages/propel/src/spinners/circular-spinner.tsx b/packages/propel/src/spinners/circular-spinner.tsx index f447020e83f..21dc1cb629e 100644 --- a/packages/propel/src/spinners/circular-spinner.tsx +++ b/packages/propel/src/spinners/circular-spinner.tsx @@ -14,7 +14,7 @@ export const Spinner: React.FC = ({ height = "32px", width = "32px", c aria-hidden="true" height={height} width={width} - className={clsx("animate-spin fill-custom-primary-100 text-custom-text-200", className)} + className={clsx("animate-spin text-custom-text-200", className)} viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg" @@ -24,8 +24,8 @@ export const Spinner: React.FC = ({ height = "32px", width = "32px", c fill="currentColor" /> Loading... diff --git a/packages/propel/src/toast/index.tsx b/packages/propel/src/toast/index.tsx index 15d686faa4f..bfa1de37054 100644 --- a/packages/propel/src/toast/index.tsx +++ b/packages/propel/src/toast/index.tsx @@ -170,8 +170,9 @@ const ToastRender = ({ id, toast }: { id: string; toast: BaseToast.Root.ToastObj }; export const setToast = (props: SetToastProps) => { - if (props.type != TOAST_TYPE.LOADING) { - toastManager.add({ + let toastId: string | undefined; + if (props.type !== TOAST_TYPE.LOADING) { + toastId = toastManager.add({ data: { type: props.type, title: props.title, @@ -179,7 +180,23 @@ export const setToast = (props: SetToastProps) => { actionItems: props.actionItems, }, }); + } else { + toastId = toastManager.add({ + data: { + type: props.type, + title: props.title, + }, + }); } + return toastId; +}; + +export const updateToast = (id: string, props: SetToastProps) => { + toastManager.update(id, { + data: { + type: props.type, + }, + }); }; export const setPromiseToast = ( @@ -190,30 +207,26 @@ export const setPromiseToast = ( loading: { data: { title: options.loading ?? "Loading...", - type: TOAST_TYPE.LOADING, + type: TOAST_TYPE.LOADING, message: undefined, actionItems: undefined, }, }, - success: (data) => { - return { - data: { - type: TOAST_TYPE.SUCCESS, - title: options.success.title, - message: options.success.message?.(data), - actionItems: options.success.actionItems?.(data), - }, - }; - }, - error: (data) => { - return { - data: { - type: TOAST_TYPE.ERROR, - title: options.error.title, - message: options.error.message?.(data), - actionItems: options.error.actionItems?.(data), - }, - }; - }, + success: (data) => ({ + data: { + type: TOAST_TYPE.SUCCESS, + title: options.success.title, + message: options.success.message?.(data), + actionItems: options.success.actionItems?.(data), + }, + }), + error: (data) => ({ + data: { + type: TOAST_TYPE.ERROR, + title: options.error.title, + message: options.error.message?.(data), + actionItems: options.error.actionItems?.(data), + }, + }), }); }; From e77d0f014ff46f0ed87b403a4933c43982b9a226 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 25 Aug 2025 17:20:38 +0530 Subject: [PATCH 3/9] fix: export path --- packages/propel/src/toast/index.ts | 1 + packages/propel/src/toast/{index.tsx => toast.tsx} | 0 2 files changed, 1 insertion(+) create mode 100644 packages/propel/src/toast/index.ts rename packages/propel/src/toast/{index.tsx => toast.tsx} (100%) diff --git a/packages/propel/src/toast/index.ts b/packages/propel/src/toast/index.ts new file mode 100644 index 00000000000..da089861b93 --- /dev/null +++ b/packages/propel/src/toast/index.ts @@ -0,0 +1 @@ +export * from "./toast"; diff --git a/packages/propel/src/toast/index.tsx b/packages/propel/src/toast/toast.tsx similarity index 100% rename from packages/propel/src/toast/index.tsx rename to packages/propel/src/toast/toast.tsx From c5e0f7b74670ca215630cad0245e4c34f0d83b15 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 25 Aug 2025 17:29:06 +0530 Subject: [PATCH 4/9] fix: lint errors --- packages/propel/src/toast/toast.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/propel/src/toast/toast.tsx b/packages/propel/src/toast/toast.tsx index bfa1de37054..3b0db53d711 100644 --- a/packages/propel/src/toast/toast.tsx +++ b/packages/propel/src/toast/toast.tsx @@ -207,7 +207,7 @@ export const setPromiseToast = ( loading: { data: { title: options.loading ?? "Loading...", - type: TOAST_TYPE.LOADING, + type: TOAST_TYPE.LOADING, message: undefined, actionItems: undefined, }, From f57c2219e255e37dc47d41fbca6bd1160026ff03 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Thu, 28 Aug 2025 13:51:09 +0530 Subject: [PATCH 5/9] chore: imporoved props handling --- packages/propel/src/toast/toast.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/propel/src/toast/toast.tsx b/packages/propel/src/toast/toast.tsx index 3b0db53d711..f1b9af95007 100644 --- a/packages/propel/src/toast/toast.tsx +++ b/packages/propel/src/toast/toast.tsx @@ -103,7 +103,7 @@ const ToastList = () => { return toasts.map((toast) => ); }; -const ToastRender = ({ id, toast }: { id: string; toast: BaseToast.Root.ToastObject }) => { +const ToastRender = ({ id, toast }: { id: React.Key; toast: BaseToast.Root.ToastObject }) => { const toastData = toast.data as SetToastProps; const type = toastData.type as TOAST_TYPE; const data = TOAST_DATA[type]; @@ -193,9 +193,18 @@ export const setToast = (props: SetToastProps) => { export const updateToast = (id: string, props: SetToastProps) => { toastManager.update(id, { - data: { - type: props.type, - }, + data: + props.type === TOAST_TYPE.LOADING + ? { + type: TOAST_TYPE.LOADING, + title: props.title, + } + : { + type: props.type, + title: props.title, + message: props.message, + actionItems: props.actionItems, + }, }); }; From 4845338dd38bd965def2a4bbd9d8cdc892862fa1 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 8 Sep 2025 15:36:18 +0530 Subject: [PATCH 6/9] fix: lint errors --- packages/propel/src/charts/components/tooltip.tsx | 2 +- packages/propel/src/toast/toast.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/propel/src/charts/components/tooltip.tsx b/packages/propel/src/charts/components/tooltip.tsx index 44ed5177442..076bf94867e 100644 --- a/packages/propel/src/charts/components/tooltip.tsx +++ b/packages/propel/src/charts/components/tooltip.tsx @@ -1,9 +1,9 @@ import React from "react"; import { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent"; // plane imports +import { cn } from "@plane/utils"; import { Card, ECardSpacing } from "../../card"; -import { cn } from "@plane/utils"; type Props = { active: boolean | undefined; diff --git a/packages/propel/src/toast/toast.tsx b/packages/propel/src/toast/toast.tsx index f1b9af95007..ebf4dc9a27f 100644 --- a/packages/propel/src/toast/toast.tsx +++ b/packages/propel/src/toast/toast.tsx @@ -1,10 +1,10 @@ +import * as React from "react"; import { Toast as BaseToast } from "@base-ui-components/react/toast"; +import clsx from "clsx"; import { AlertTriangle, CheckCircle2, X, XCircle } from "lucide-react"; -import * as React from "react"; // spinner import { CircularBarSpinner } from "../spinners/circular-bar-spinner"; // helper -import clsx from "clsx"; export enum TOAST_TYPE { SUCCESS = "success", From ebab0234d5bb4fe588be693a698892cd2a867880 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 8 Sep 2025 15:41:42 +0530 Subject: [PATCH 7/9] chore: updated import paths --- packages/propel/src/charts/components/tooltip.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/propel/src/charts/components/tooltip.tsx b/packages/propel/src/charts/components/tooltip.tsx index 076bf94867e..a2fa06b3bfe 100644 --- a/packages/propel/src/charts/components/tooltip.tsx +++ b/packages/propel/src/charts/components/tooltip.tsx @@ -1,9 +1,7 @@ import React from "react"; import { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent"; -// plane imports -import { cn } from "@plane/utils"; import { Card, ECardSpacing } from "../../card"; - +import { cn } from "../../utils/classname"; type Props = { active: boolean | undefined; From c6ad87484f7b3f1997aa6c2b72da395e20c7e446 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Mon, 8 Sep 2025 15:56:58 +0530 Subject: [PATCH 8/9] chore: replaced clsx with cn --- packages/propel/src/toast/toast.tsx | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/propel/src/toast/toast.tsx b/packages/propel/src/toast/toast.tsx index ebf4dc9a27f..0b0955bd4e8 100644 --- a/packages/propel/src/toast/toast.tsx +++ b/packages/propel/src/toast/toast.tsx @@ -1,10 +1,9 @@ import * as React from "react"; import { Toast as BaseToast } from "@base-ui-components/react/toast"; -import clsx from "clsx"; import { AlertTriangle, CheckCircle2, X, XCircle } from "lucide-react"; // spinner import { CircularBarSpinner } from "../spinners/circular-bar-spinner"; -// helper +import { cn } from "../utils/classname"; export enum TOAST_TYPE { SUCCESS = "success", @@ -42,14 +41,6 @@ type PromiseToastOptions = { error: PromiseToastData; }; -type ToastContentProps = { - toastId: string | number; - icon?: React.ReactNode; - textColorClassName: string; - backgroundColorClassName: string; - borderColorClassName: string; -}; - export type ToastProps = { theme: "light" | "dark" | "system"; }; @@ -112,7 +103,7 @@ const ToastRender = ({ id, toast }: { id: React.Key; toast: BaseToast.Root.Toast {data.icon &&
{data.icon}
} -
-
+
+
{toastData.title ?? "Loading..."}
{data.icon &&
{data.icon}
} -
- +
+ {toastData.title} {toastData.message && ( From 1f959339beaacbd45bfbb388db302dc8246aef44 Mon Sep 17 00:00:00 2001 From: vamsikrishnamathala Date: Tue, 9 Sep 2025 13:46:02 +0530 Subject: [PATCH 9/9] * chore: updated tsdown config * chore: updated exports order --- packages/propel/package.json | 4 ++-- packages/propel/tsdown.config.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/propel/package.json b/packages/propel/package.json index 7bf16f29e71..58322d53d9e 100644 --- a/packages/propel/package.json +++ b/packages/propel/package.json @@ -32,9 +32,9 @@ "./switch": "./dist/switch/index.js", "./table": "./dist/table/index.js", "./tabs": "./dist/tabs/index.js", + "./toast": "./dist/toast/index.js", "./tooltip": "./dist/tooltip/index.js", - "./utils": "./dist/utils/index.js", - "./toast": "./dist/toast/index.js" + "./utils": "./dist/utils/index.js" }, "dependencies": { "@base-ui-components/react": "^1.0.0-beta.2", diff --git a/packages/propel/tsdown.config.ts b/packages/propel/tsdown.config.ts index 8f23c301cb8..9e4d7dbffff 100644 --- a/packages/propel/tsdown.config.ts +++ b/packages/propel/tsdown.config.ts @@ -17,6 +17,7 @@ export default defineConfig({ "src/switch/index.ts", "src/table/index.ts", "src/tabs/index.ts", + "src/toast/index.ts", "src/tooltip/index.ts", "src/utils/index.ts", ],