{ "name": "toast", "type": "registry:ui", "dependencies": [], "registryDependencies": [ "utils" ], "files": [ { "path": "ui/toast/Toast.vue", "content": "\n\n\n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/ToastAction.vue", "content": "\n\n\n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/ToastClose.vue", "content": "\n\n\n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/ToastDescription.vue", "content": "\n\n\n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/ToastProvider.vue", "content": "\n\n\n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/ToastTitle.vue", "content": "\n\n\n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/ToastViewport.vue", "content": "\n\n\n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/Toaster.vue", "content": "\n\n\n \n \n \n \n {{ toast.title }}\n \n \n \n \n \n \n {{ toast.description }}\n \n \n \n \n \n \n \n \n\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/index.ts", "content": "import type { ToastRootProps } from 'reka-ui'\nimport type { HTMLAttributes } from 'vue'\n\nexport { default as Toast } from './Toast.vue'\nexport { default as ToastAction } from './ToastAction.vue'\nexport { default as ToastClose } from './ToastClose.vue'\nexport { default as ToastDescription } from './ToastDescription.vue'\nexport { default as Toaster } from './Toaster.vue'\nexport { default as ToastProvider } from './ToastProvider.vue'\nexport { default as ToastTitle } from './ToastTitle.vue'\nexport { default as ToastViewport } from './ToastViewport.vue'\nexport { toast, useToast } from './use-toast'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nexport const toastVariants = cva(\n 'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[--reka-toast-swipe-end-x] data-[swipe=move]:translate-x-[--reka-toast-swipe-move-x] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',\n {\n variants: {\n variant: {\n default: 'border bg-background text-foreground',\n destructive:\n 'destructive group border-destructive bg-destructive text-destructive-foreground',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n)\n\ntype ToastVariants = VariantProps\n\nexport interface ToastProps extends ToastRootProps {\n class?: HTMLAttributes['class']\n variant?: ToastVariants['variant']\n onOpenChange?: ((value: boolean) => void) | undefined\n}\n", "type": "registry:ui", "target": "" }, { "path": "ui/toast/use-toast.ts", "content": "import type { Component, VNode } from 'vue'\nimport type { ToastProps } from '.'\nimport { computed, ref } from 'vue'\n\nconst TOAST_LIMIT = 1\nconst TOAST_REMOVE_DELAY = 1000000\n\nexport type StringOrVNode =\n | string\n | VNode\n | (() => VNode)\n\ntype ToasterToast = ToastProps & {\n id: string\n title?: string\n description?: StringOrVNode\n action?: Component\n}\n\nconst actionTypes = {\n ADD_TOAST: 'ADD_TOAST',\n UPDATE_TOAST: 'UPDATE_TOAST',\n DISMISS_TOAST: 'DISMISS_TOAST',\n REMOVE_TOAST: 'REMOVE_TOAST',\n} as const\n\nlet count = 0\n\nfunction genId() {\n count = (count + 1) % Number.MAX_VALUE\n return count.toString()\n}\n\ntype ActionType = typeof actionTypes\n\ntype Action =\n | {\n type: ActionType['ADD_TOAST']\n toast: ToasterToast\n }\n | {\n type: ActionType['UPDATE_TOAST']\n toast: Partial\n }\n | {\n type: ActionType['DISMISS_TOAST']\n toastId?: ToasterToast['id']\n }\n | {\n type: ActionType['REMOVE_TOAST']\n toastId?: ToasterToast['id']\n }\n\ninterface State {\n toasts: ToasterToast[]\n}\n\nconst toastTimeouts = new Map>()\n\nfunction addToRemoveQueue(toastId: string) {\n if (toastTimeouts.has(toastId))\n return\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId)\n dispatch({\n type: actionTypes.REMOVE_TOAST,\n toastId,\n })\n }, TOAST_REMOVE_DELAY)\n\n toastTimeouts.set(toastId, timeout)\n}\n\nconst state = ref({\n toasts: [],\n})\n\nfunction dispatch(action: Action) {\n switch (action.type) {\n case actionTypes.ADD_TOAST:\n state.value.toasts = [action.toast, ...state.value.toasts].slice(0, TOAST_LIMIT)\n break\n\n case actionTypes.UPDATE_TOAST:\n state.value.toasts = state.value.toasts.map(t =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n )\n break\n\n case actionTypes.DISMISS_TOAST: {\n const { toastId } = action\n\n if (toastId) {\n addToRemoveQueue(toastId)\n }\n else {\n state.value.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id)\n })\n }\n\n state.value.toasts = state.value.toasts.map(t =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n )\n break\n }\n\n case actionTypes.REMOVE_TOAST:\n if (action.toastId === undefined)\n state.value.toasts = []\n else\n state.value.toasts = state.value.toasts.filter(t => t.id !== action.toastId)\n\n break\n }\n}\n\nfunction useToast() {\n return {\n toasts: computed(() => state.value.toasts),\n toast,\n dismiss: (toastId?: string) => dispatch({ type: actionTypes.DISMISS_TOAST, toastId }),\n }\n}\n\ntype Toast = Omit\n\nfunction toast(props: Toast) {\n const id = genId()\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: actionTypes.UPDATE_TOAST,\n toast: { ...props, id },\n })\n\n const dismiss = () => dispatch({ type: actionTypes.DISMISS_TOAST, toastId: id })\n\n dispatch({\n type: actionTypes.ADD_TOAST,\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open: boolean) => {\n if (!open)\n dismiss()\n },\n },\n })\n\n return {\n id,\n dismiss,\n update,\n }\n}\n\nexport { toast, useToast }\n", "type": "registry:ui", "target": "" } ] }