@wello-dev/notifications 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["#style-inject:#style-inject","../src/styles.css","../src/core/store.ts","../src/core/toast.ts","../src/core/use-toasts.ts","../src/components/toaster.tsx","../src/lib/colors.ts","../src/lib/labels.ts","../src/lib/utils.ts","../src/components/icons.tsx","../src/components/toast-item.tsx","../src/sound/notification-sound.ts","../src/tab/tab-notifications.ts"],"sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\"@layer theme, base, components, utilities;\\n@layer components {\\n .wello-notifications-toaster {\\n --wello-notifications-bg: rgb(255 255 255 / 0.95);\\n --wello-notifications-fg: #0f172a;\\n --wello-notifications-muted: #64748b;\\n --wello-notifications-border: rgb(226 232 240 / 0.7);\\n --wello-notifications-ring: rgb(0 0 0 / 0.05);\\n --wello-notifications-hover: rgb(0 0 0 / 0.05);\\n --wello-notifications-shadow: 0 8px 24px -12px rgb(0 0 0 / 0.22);\\n --wello-notifications-radius: 16px;\\n --wello-notifications-font: inherit;\\n position: fixed;\\n display: flex;\\n flex-direction: column;\\n box-sizing: border-box;\\n width: var(--wello-notifications-width, 390px);\\n max-width: calc(100vw - 2 * var(--wello-notifications-offset, 16px));\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n pointer-events: none;\\n font-family: var(--wello-notifications-font);\\n color-scheme: light;\\n }\\n .dark .wello-notifications-toaster:not([data-theme=light]),\\n [data-theme=dark] .wello-notifications-toaster:not([data-theme=light]),\\n .wello-notifications-toaster[data-theme=dark] {\\n --wello-notifications-bg: rgb(15 23 42 / 0.92);\\n --wello-notifications-fg: #f1f5f9;\\n --wello-notifications-muted: #94a3b8;\\n --wello-notifications-border: rgb(255 255 255 / 0.1);\\n --wello-notifications-ring: rgb(255 255 255 / 0.06);\\n --wello-notifications-hover: rgb(255 255 255 / 0.1);\\n --wello-notifications-shadow: 0 8px 24px -12px rgb(0 0 0 / 0.45);\\n color-scheme: dark;\\n }\\n .wello-notifications-toaster[data-y=top] {\\n top: calc(var(--wello-notifications-offset, 16px) - var(--wello-notifications-gap, 12px) / 2);\\n }\\n .wello-notifications-toaster[data-y=bottom] {\\n bottom: calc(var(--wello-notifications-offset, 16px) - var(--wello-notifications-gap, 12px) / 2);\\n flex-direction: column-reverse;\\n }\\n .wello-notifications-toaster[data-x=start] {\\n inset-inline-start: var(--wello-notifications-offset, 16px);\\n }\\n .wello-notifications-toaster[data-x=end] {\\n inset-inline-end: var(--wello-notifications-offset, 16px);\\n }\\n .wello-notifications-toaster[data-x=center] {\\n left: 50%;\\n transform: translateX(-50%);\\n }\\n @media (max-width: 480px) {\\n .wello-notifications-toaster {\\n width: auto;\\n max-width: none;\\n inset-inline: var(--wello-notifications-offset, 16px);\\n transform: none;\\n }\\n .wello-notifications-toaster[data-x=center] {\\n left: var(--wello-notifications-offset, 16px);\\n }\\n }\\n .wello-notifications-item {\\n display: grid;\\n grid-template-rows: 1fr;\\n transition: grid-template-rows 200ms ease 110ms;\\n }\\n .wello-notifications-item-inner {\\n min-height: 0;\\n padding-block: calc(var(--wello-notifications-gap, 12px) / 2);\\n }\\n .wello-notifications-item[data-state=closing] {\\n grid-template-rows: 0fr;\\n }\\n .wello-notifications-item[data-state=closing] .wello-notifications-item-inner {\\n overflow: hidden;\\n }\\n .wello-notifications-toast,\\n .wello-notifications-custom {\\n pointer-events: auto;\\n touch-action: pan-y;\\n transform: translateX(var(--wello-notifications-swipe, 0px));\\n transition:\\n transform 200ms ease,\\n opacity 160ms ease,\\n scale 160ms ease;\\n animation: wello-notifications-in 260ms cubic-bezier(0.21, 1.02, 0.73, 1);\\n }\\n .wello-notifications-toaster[data-y=top] .wello-notifications-toast,\\n .wello-notifications-toaster[data-y=top] .wello-notifications-custom {\\n --wello-notifications-enter: -14px;\\n }\\n .wello-notifications-toast[data-swiping],\\n .wello-notifications-custom[data-swiping] {\\n transition: none;\\n user-select: none;\\n }\\n .wello-notifications-item[data-state=closing] .wello-notifications-toast,\\n .wello-notifications-item[data-state=closing] .wello-notifications-custom {\\n opacity: 0;\\n scale: 0.96;\\n }\\n .wello-notifications-item[data-swiped=end] .wello-notifications-toast,\\n .wello-notifications-item[data-swiped=end] .wello-notifications-custom {\\n transform: translateX(calc(100% + 32px));\\n }\\n .wello-notifications-item[data-swiped=start] .wello-notifications-toast,\\n .wello-notifications-item[data-swiped=start] .wello-notifications-custom {\\n transform: translateX(calc(-100% - 32px));\\n }\\n .wello-notifications-toast {\\n position: relative;\\n display: flex;\\n align-items: flex-start;\\n gap: 12px;\\n box-sizing: border-box;\\n width: 100%;\\n padding-block: 14px;\\n padding-inline: 14px 8px;\\n overflow: hidden;\\n border: 1px solid var(--wello-notifications-border);\\n border-radius: var(--wello-notifications-radius);\\n background: var(--wello-notifications-bg);\\n color: var(--wello-notifications-fg);\\n box-shadow: var(--wello-notifications-shadow), 0 0 0 1px var(--wello-notifications-ring);\\n backdrop-filter: blur(24px) saturate(1.5);\\n -webkit-backdrop-filter: blur(24px) saturate(1.5);\\n font-size: 14px;\\n line-height: 1.4;\\n text-align: start;\\n }\\n .wello-notifications-toast::before {\\n content: \\\"\\\";\\n position: absolute;\\n inset-block: 0.55rem;\\n inset-inline-start: 0;\\n width: 3px;\\n border-radius: 999px;\\n background: var(--wello-notifications-tone);\\n }\\n .wello-notifications-icon {\\n display: flex;\\n flex: none;\\n align-items: center;\\n justify-content: center;\\n width: 40px;\\n height: 40px;\\n border-radius: var(--wello-notifications-radius);\\n color: var(--wello-notifications-tone);\\n background: color-mix(in oklab, var(--wello-notifications-tone) 16%, transparent);\\n box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--wello-notifications-tone) 28%, transparent);\\n font-size: 1.15rem;\\n }\\n .wello-notifications-content {\\n display: flex;\\n flex: 1;\\n flex-direction: column;\\n gap: 4px;\\n min-width: 0;\\n padding-block: 2px;\\n padding-inline-end: 8px;\\n overflow-wrap: anywhere;\\n }\\n .wello-notifications-toast > .wello-notifications-content:first-child {\\n padding-inline-start: 2px;\\n }\\n .wello-notifications-title {\\n margin: 0;\\n font-weight: 600;\\n line-height: 1.35;\\n color: var(--wello-notifications-tone);\\n }\\n .wello-notifications-toast[data-type=default] .wello-notifications-title,\\n .wello-notifications-toast[data-type=loading] .wello-notifications-title {\\n color: var(--wello-notifications-fg);\\n }\\n .wello-notifications-description {\\n margin: 0;\\n color: var(--wello-notifications-muted);\\n line-height: 1.55;\\n }\\n .wello-notifications-actions {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 8px;\\n margin-top: 6px;\\n }\\n .wello-notifications-button {\\n display: inline-flex;\\n align-items: center;\\n height: 28px;\\n padding-inline: 10px;\\n border: 1px solid transparent;\\n border-radius: 8px;\\n font: inherit;\\n font-size: 13px;\\n font-weight: 600;\\n cursor: pointer;\\n transition: background-color 120ms ease, filter 120ms ease;\\n }\\n .wello-notifications-action {\\n background: var(--wello-notifications-tone);\\n color: #fff;\\n }\\n .wello-notifications-toast[data-type=default] .wello-notifications-action,\\n .wello-notifications-toast[data-type=loading] .wello-notifications-action {\\n background: var(--wello-notifications-fg);\\n color: var(--wello-notifications-bg);\\n }\\n .wello-notifications-action:hover {\\n filter: brightness(1.08);\\n }\\n .wello-notifications-cancel {\\n background: transparent;\\n border-color: var(--wello-notifications-border);\\n color: var(--wello-notifications-fg);\\n }\\n .wello-notifications-cancel:hover {\\n background: var(--wello-notifications-hover);\\n }\\n .wello-notifications-button:focus-visible,\\n .wello-notifications-close:focus-visible {\\n outline: 2px solid var(--wello-notifications-tone);\\n outline-offset: 2px;\\n }\\n .wello-notifications-close {\\n display: flex;\\n flex: none;\\n align-items: center;\\n justify-content: center;\\n width: 28px;\\n height: 28px;\\n margin: -2px 0;\\n padding: 0;\\n border: 0;\\n border-radius: 10px;\\n background: transparent;\\n color: var(--wello-notifications-muted);\\n font-size: 16px;\\n cursor: pointer;\\n transition: background-color 120ms ease, color 120ms ease;\\n }\\n .wello-notifications-close:hover {\\n background: var(--wello-notifications-hover);\\n color: var(--wello-notifications-fg);\\n }\\n .wello-notifications-progress {\\n position: absolute;\\n inset-inline: 0;\\n bottom: 0;\\n height: 3px;\\n background: var(--wello-notifications-tone);\\n opacity: 0.45;\\n transform-origin: left;\\n animation-name: wello-notifications-progress;\\n animation-timing-function: linear;\\n animation-fill-mode: forwards;\\n }\\n [dir=rtl] .wello-notifications-progress {\\n transform-origin: right;\\n }\\n .wello-notifications-spin {\\n animation: wello-notifications-spin 0.9s linear infinite;\\n }\\n @keyframes wello-notifications-in {\\n from {\\n opacity: 0;\\n translate: 0 var(--wello-notifications-enter, 14px);\\n scale: 0.96;\\n }\\n }\\n @keyframes wello-notifications-progress {\\n from {\\n transform: scaleX(1);\\n }\\n to {\\n transform: scaleX(0);\\n }\\n }\\n @keyframes wello-notifications-spin {\\n to {\\n transform: rotate(360deg);\\n }\\n }\\n @media (prefers-reduced-motion: reduce) {\\n .wello-notifications-toast,\\n .wello-notifications-custom,\\n .wello-notifications-item {\\n animation-duration: 1ms;\\n transition-duration: 1ms;\\n transition-delay: 0ms;\\n }\\n .wello-notifications-spin {\\n animation-duration: 2.5s;\\n }\\n }\\n}\\n\")","import type { ToastId, ToastRecord } from \"./types\";\n\ntype Listener = () => void;\n\nexport interface ToastState {\n /** Newest first; closed toasts stay until their exit animation ends */\n toasts: ToastRecord[];\n /** Set by `toast.pauseAll()` */\n paused: boolean;\n}\n\nlet state: ToastState = { toasts: [], paused: false };\nconst listeners = new Set<Listener>();\nlet counter = 0;\n\nfunction emit(next: ToastState) {\n state = next;\n listeners.forEach((listener) => listener());\n}\n\n/** Shared toast state, readable with `useSyncExternalStore`. */\nexport const toastStore = {\n getState: (): ToastState => state,\n subscribe(listener: Listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n /** `true` when at least one `<Toaster>` is mounted */\n hasToaster: () => listeners.size > 0,\n nextId: (): string => `wello-notifications-${++counter}`,\n\n /** Adds a toast, or replaces the open one with the same id. */\n upsert(record: Omit<ToastRecord, \"version\" | \"createdAt\" | \"open\">): ToastId {\n const existing = state.toasts.find((t) => t.id === record.id);\n if (existing?.open) {\n emit({\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === record.id\n ? { ...record, version: t.version + 1, createdAt: t.createdAt, open: true }\n : t,\n ),\n });\n } else {\n const fresh: ToastRecord = { ...record, version: 0, createdAt: Date.now(), open: true };\n emit({ ...state, toasts: [fresh, ...state.toasts.filter((t) => t.id !== record.id)] });\n }\n return record.id;\n },\n\n /** Merges changes into an open toast. Returns false when there is none with this id. */\n patch(id: ToastId, changes: Partial<ToastRecord>): boolean {\n const existing = state.toasts.find((t) => t.id === id && t.open);\n if (!existing) return false;\n emit({\n ...state,\n toasts: state.toasts.map((t) =>\n t === existing ? { ...t, ...changes, id, version: t.version + 1, open: true } : t,\n ),\n });\n return true;\n },\n\n /** Starts closing one toast, or all of them. */\n dismiss(id?: ToastId, reason: \"close\" | \"auto\" = \"close\") {\n const closing = state.toasts.filter((t) => t.open && (id === undefined || t.id === id));\n if (!closing.length) return;\n // Without a toaster nothing would animate them out, so drop them now.\n const keep = toastStore.hasToaster();\n emit({\n ...state,\n toasts: keep\n ? state.toasts.map((t) => (closing.includes(t) ? { ...t, open: false } : t))\n : state.toasts.filter((t) => !closing.includes(t)),\n });\n for (const t of closing) {\n if (reason === \"auto\") t.onAutoClose?.(t);\n t.onClose?.(t);\n }\n },\n\n /** Removes a toast right away (after its exit animation). */\n remove(id: ToastId) {\n if (!state.toasts.some((t) => t.id === id)) return;\n emit({ ...state, toasts: state.toasts.filter((t) => t.id !== id) });\n },\n\n setPaused(paused: boolean) {\n if (state.paused !== paused) emit({ ...state, paused });\n },\n\n /** Test helper: forget every toast. */\n reset() {\n emit({ toasts: [], paused: false });\n },\n};\n","import type { ReactNode } from \"react\";\nimport { toastStore } from \"./store\";\nimport type { ToastContent, ToastId, ToastOptions, ToastRecord, ToastType } from \"./types\";\n\n/** A promise, or a function that starts one (so it runs only when the toast is shown). */\nexport type PromiseSource<T> = Promise<T> | (() => Promise<T>);\n\nexport interface PromiseMessages<T> {\n loading: ToastContent;\n success: ToastContent | ((data: T) => ToastContent);\n error: ToastContent | ((error: unknown) => ToastContent);\n /** Called after success or error */\n finally?: () => void;\n}\n\nfunction toRecord(\n type: ToastType,\n message: ToastContent,\n options: ToastOptions = {},\n): Omit<ToastRecord, \"version\" | \"createdAt\" | \"open\"> {\n const { id, title, description, autoClose, duration, ...rest } = options;\n // The message is the title; with an explicit title it becomes the description.\n const resolvedTitle = title ?? message;\n const resolvedDescription =\n description ?? (title != null && title !== message ? message : undefined);\n return {\n ...rest,\n id: id ?? toastStore.nextId(),\n type,\n title: resolvedTitle,\n description: resolvedDescription,\n duration: duration ?? autoClose,\n };\n}\n\nfunction show(type: ToastType, message: ToastContent, options?: ToastOptions): ToastId {\n return toastStore.upsert(toRecord(type, message, options));\n}\n\nconst typed =\n (type: ToastType) =>\n (message: ToastContent, options?: ToastOptions): ToastId =>\n show(type, message, options);\n\nfunction promise<T>(\n source: PromiseSource<T>,\n messages: PromiseMessages<T>,\n options?: ToastOptions,\n): Promise<T> {\n const id = show(\"loading\", messages.loading, options);\n const run = typeof source === \"function\" ? source() : source;\n // Only the messages change; the rest of the options carry over.\n const settle = (type: ToastType, content: ToastContent) =>\n toastStore.upsert(toRecord(type, content, { ...options, id }));\n return run.then(\n (data) => {\n settle(\"success\", typeof messages.success === \"function\" ? messages.success(data) : messages.success);\n messages.finally?.();\n return data;\n },\n (error: unknown) => {\n settle(\"error\", typeof messages.error === \"function\" ? messages.error(error) : messages.error);\n messages.finally?.();\n throw error;\n },\n );\n}\n\n/**\n * Changes an open toast. Pass a message to replace its text, options to change anything else\n * (including `type` through `toast.success(…, { id })`). Returns false when it is already gone.\n */\nfunction update(id: ToastId, changes: ToastContent | (ToastOptions & { type?: ToastType })): boolean {\n if (changes !== null && typeof changes === \"object\" && !isReactElement(changes)) {\n const { id: _ignored, autoClose, duration, ...rest } = changes as ToastOptions & { type?: ToastType };\n const patch: Partial<ToastRecord> = { ...rest };\n if (duration !== undefined || autoClose !== undefined) patch.duration = duration ?? autoClose;\n return toastStore.patch(id, patch);\n }\n return toastStore.patch(id, { title: changes as ReactNode });\n}\n\nfunction isReactElement(value: object): boolean {\n return \"$$typeof\" in value;\n}\n\nconst dismiss = (id?: ToastId) => toastStore.dismiss(id);\n\n/**\n * Shows a toast. Needs one `<Toaster />` somewhere in the app.\n *\n * @example\n * toast.success(\"Saved\");\n * toast.error(\"Upload failed\", { description: \"The file is too large\" });\n * const id = toast.loading(\"Sending…\"); toast.success(\"Sent\", { id });\n * await toast.promise(save(), { loading: \"Saving…\", success: \"Saved\", error: \"Could not save\" });\n */\nexport const toast = Object.assign(typed(\"default\"), {\n success: typed(\"success\"),\n error: typed(\"error\"),\n /** Same as `error` */\n danger: typed(\"error\"),\n warning: typed(\"warning\"),\n info: typed(\"info\"),\n loading: typed(\"loading\"),\n /** Same as `toast()` */\n message: typed(\"default\"),\n /** Fully custom content; `render` gets the toast (use `toast.dismiss(t.id)` to close it). */\n custom: (render: (toast: ToastRecord) => ReactNode, options?: ToastOptions): ToastId =>\n toastStore.upsert({ ...toRecord(\"default\", null, options), title: undefined, render }),\n promise,\n update,\n /** Closes one toast, or all of them without an id */\n dismiss,\n /** Same as `dismiss` */\n close: dismiss,\n /** Closes every toast */\n clear: () => toastStore.dismiss(),\n /** Stops every timer, e.g. while a dialog is open */\n pauseAll: () => toastStore.setPaused(true),\n resumeAll: () => toastStore.setPaused(false),\n /** `true` while the toast is open */\n isActive: (id: ToastId) => toastStore.getState().toasts.some((t) => t.id === id && t.open),\n});\n","import { useSyncExternalStore } from \"react\";\nimport { toastStore } from \"./store\";\nimport type { ToastRecord } from \"./types\";\n\nconst NONE: ToastRecord[] = [];\n\n/** Open toasts, newest first; for badges or your own notification UI. */\nexport function useToasts(): ToastRecord[] {\n return useSyncExternalStore(\n toastStore.subscribe,\n () => toastStore.getState().toasts,\n () => NONE,\n ).filter((t) => t.open);\n}\n","import {\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { toastStore, type ToastState } from \"../core/store\";\nimport type {\n ToastClassNames,\n ToastPosition,\n ToastRecord,\n ToastStyles,\n ToastType,\n} from \"../core/types\";\nimport { resolveColor, type ToastColor } from \"../lib/colors\";\nimport { resolveLabels, type ToasterLabels, type ToasterLocale } from \"../lib/labels\";\nimport { cx, toCssSize } from \"../lib/utils\";\nimport { DEFAULT_ICONS } from \"./icons\";\nimport { ToastItem, type ResolvedToast } from \"./toast-item\";\n\nexport type ToasterTheme = \"light\" | \"dark\" | \"system\";\n\nexport interface ToasterProps {\n /** Default: 'bottom-start' (bottom-left in LTR, bottom-right in RTL) */\n position?: ToastPosition;\n /** `'auto'` follows `<html dir>`. Default: 'auto' */\n dir?: \"ltr\" | \"rtl\" | \"auto\";\n /** Toasts shown at once per position; the rest wait their turn. Default: 4 */\n limit?: number;\n /** Default time on screen in ms. Default: 4000 */\n duration?: number;\n /** Per-type time on screen. Default: error 5500, warning 5000, loading until closed */\n durations?: Partial<Record<ToastType, number | false>>;\n /** Per-type accent colors: Tailwind names (`'emerald-600'`) or CSS colors */\n colors?: Partial<Record<ToastType, ToastColor>>;\n /** Per-type icons; `null` hides one */\n icons?: Partial<Record<ToastType, ReactNode>>;\n /** Close button on dismissible toasts. Default: true */\n closeButton?: boolean;\n /** Remaining-time bar on every toast. Default: false */\n progress?: boolean;\n /** Swipe sideways to dismiss. Default: true */\n swipe?: boolean;\n /** Stop timers while hovered or focused. Default: true */\n pauseOnHover?: boolean;\n /** Stop timers while the tab is hidden. Default: true */\n pauseWhenPageHidden?: boolean;\n /** Sound for every toast: `true` for the built-in sound of each type, a built-in name or a URL. Default: false */\n sound?: boolean | string;\n /**\n * Default: light, switching to dark under a `.dark` / `[data-theme=\"dark\"]` ancestor.\n * `'system'` follows the OS setting\n */\n theme?: ToasterTheme;\n /** Toast width. Default: 390 */\n width?: number | string;\n /** Space between toasts. Default: 12 */\n gap?: number;\n /** Distance from the screen edges. Default: 16 */\n offset?: number | string;\n /** Default: 11000 */\n zIndex?: number;\n /** Built-in texts. Default: 'en' */\n locale?: ToasterLocale;\n labels?: Partial<ToasterLabels>;\n /** Classes and styles for the parts of every toast */\n classNames?: ToastClassNames & { toaster?: string };\n styles?: ToastStyles & { toaster?: CSSProperties };\n /** Class on each list of toasts */\n className?: string;\n style?: CSSProperties;\n /** Where to render. Default: document.body */\n container?: Element | null;\n}\n\nconst DEFAULT_COLORS: Record<ToastType, ToastColor> = {\n default: \"slate-500\",\n success: \"emerald-600\",\n error: \"red-600\",\n warning: \"amber-600\",\n info: \"blue-600\",\n loading: \"slate-500\",\n};\n\nconst DEFAULT_DURATIONS: Partial<Record<ToastType, number | false>> = {\n error: 5500,\n warning: 5000,\n loading: false,\n};\n\nconst EMPTY: ToastState = { toasts: [], paused: false };\nconst getServerState = () => EMPTY;\n\nlet nextToasterId = 0;\nlet activeToasterId: number | null = null;\nconst mountedToasters = new Set<number>();\nconst toasterListeners = new Set<() => void>();\n\nfunction subscribeToasters(listener: () => void) {\n toasterListeners.add(listener);\n return () => {\n toasterListeners.delete(listener);\n };\n}\n\nfunction registerToaster(id: number) {\n mountedToasters.add(id);\n if (activeToasterId === null) {\n activeToasterId = id;\n toasterListeners.forEach((listener) => listener());\n }\n return () => {\n mountedToasters.delete(id);\n if (activeToasterId === id) {\n activeToasterId = mountedToasters.values().next().value ?? null;\n toasterListeners.forEach((listener) => listener());\n }\n };\n}\n\nfunction useDocumentDirection(dir: ToasterProps[\"dir\"]): \"ltr\" | \"rtl\" {\n const [documentDir, setDocumentDir] = useState<\"ltr\" | \"rtl\">(\"ltr\");\n useEffect(() => {\n if (dir !== \"auto\" || typeof document === \"undefined\") return;\n const html = document.documentElement;\n const read = () =>\n setDocumentDir(\n (html.getAttribute(\"dir\") || getComputedStyle(html).direction) === \"rtl\" ? \"rtl\" : \"ltr\",\n );\n read();\n // Language switchers usually flip <html dir> at runtime.\n const observer = new MutationObserver(read);\n observer.observe(html, { attributes: true, attributeFilter: [\"dir\"] });\n return () => observer.disconnect();\n }, [dir]);\n return dir === \"ltr\" || dir === \"rtl\" ? dir : documentDir;\n}\n\nfunction usePageHidden(enabled: boolean): boolean {\n const [hidden, setHidden] = useState(false);\n useEffect(() => {\n if (!enabled) return;\n const update = () => setHidden(document.visibilityState === \"hidden\");\n update();\n document.addEventListener(\"visibilitychange\", update);\n return () => document.removeEventListener(\"visibilitychange\", update);\n }, [enabled]);\n return enabled && hidden;\n}\n\nfunction useSystemDark(enabled: boolean): boolean {\n const [dark, setDark] = useState(false);\n useEffect(() => {\n if (!enabled || typeof matchMedia === \"undefined\") return;\n const query = matchMedia(\"(prefers-color-scheme: dark)\");\n const update = () => setDark(query.matches);\n update();\n query.addEventListener(\"change\", update);\n return () => query.removeEventListener(\"change\", update);\n }, [enabled]);\n return dark;\n}\n\n/** Splits `bottom-start` into its parts; physical sides are mapped for the direction. */\nfunction splitPosition(position: ToastPosition, dir: \"ltr\" | \"rtl\") {\n const [y, x] = position.split(\"-\") as [\"top\" | \"bottom\", string];\n const physical = {\n left: dir === \"ltr\" ? \"start\" : \"end\",\n right: dir === \"ltr\" ? \"end\" : \"start\",\n };\n return { y, x: (physical[x as \"left\" | \"right\"] ?? x) as \"start\" | \"center\" | \"end\" };\n}\n\n/**\n * Renders the toasts. Mount it once, near the root of the app.\n *\n * @example\n * <Toaster />\n * <Toaster position=\"top-center\" locale=\"ar\" progress />\n */\nexport function Toaster(props: ToasterProps) {\n const {\n position = \"bottom-start\",\n dir: dirProp = \"auto\",\n limit = 4,\n duration = 4000,\n durations,\n colors,\n icons,\n closeButton = true,\n progress = true,\n swipe = true,\n pauseOnHover = true,\n pauseWhenPageHidden = true,\n sound = false,\n theme,\n width = 390,\n gap = 12,\n offset = 16,\n zIndex = 11000,\n locale,\n labels: labelOverrides,\n classNames = {},\n styles = {},\n className,\n style,\n container,\n } = props;\n\n const state = useSyncExternalStore(toastStore.subscribe, toastStore.getState, getServerState);\n const dir = useDocumentDirection(dirProp);\n const pageHidden = usePageHidden(pauseWhenPageHidden);\n const systemDark = useSystemDark(theme === \"system\");\n const labels = useMemo(() => resolveLabels(locale, labelOverrides), [locale, labelOverrides]);\n const [hovered, setHovered] = useState<string | null>(null);\n const instanceId = useMemo(() => ++nextToasterId, []);\n const isActiveToaster = useSyncExternalStore(\n subscribeToasters,\n () => activeToasterId === instanceId,\n () => false,\n );\n // Portals need the DOM: render nothing on the server and in the first client render.\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n setMounted(true);\n return registerToaster(instanceId);\n }, [instanceId]);\n\n const groups = useMemo(() => {\n const byKey = new Map<\n string,\n { y: \"top\" | \"bottom\"; x: \"start\" | \"center\" | \"end\"; toasts: ToastRecord[] }\n >();\n for (const t of state.toasts) {\n const { y, x } = splitPosition(t.position ?? position, dir);\n const key = `${y}-${x}`;\n if (!byKey.has(key)) byKey.set(key, { y, x, toasts: [] });\n byKey.get(key)!.toasts.push(t);\n }\n // Oldest open toasts get the slots; newer ones queue (closing ones keep theirs until gone).\n for (const group of byKey.values()) {\n const shown = new Set(\n group.toasts\n .filter((t) => t.open)\n .sort((a, b) => a.createdAt - b.createdAt)\n .slice(0, Math.max(1, limit)),\n );\n group.toasts = group.toasts.filter((t) => !t.open || shown.has(t));\n }\n return [...byKey.entries()];\n }, [state.toasts, position, dir, limit]);\n\n // A list that empties under the pointer never gets mouseleave.\n useEffect(() => {\n if (hovered && !groups.some(([key]) => key === hovered)) setHovered(null);\n }, [groups, hovered]);\n\n if (!mounted || !isActiveToaster) return null;\n const target = container ?? document.body;\n\n const resolve = (t: ToastRecord): ResolvedToast => {\n const typeDuration = durations?.[t.type] ?? DEFAULT_DURATIONS[t.type];\n const customIcon = icons && t.type in icons ? icons[t.type] : undefined;\n return {\n duration: t.duration ?? (typeDuration === undefined ? duration : typeDuration),\n color: resolveColor(t.color ?? colors?.[t.type] ?? DEFAULT_COLORS[t.type]),\n icon:\n t.icon === false\n ? null\n : (t.icon ?? (customIcon !== undefined ? customIcon : DEFAULT_ICONS[t.type])),\n dismissible: t.dismissible ?? t.type !== \"loading\",\n closeButton,\n progress: t.progress ?? progress,\n swipe,\n sound: t.sound ?? sound,\n className: t.className,\n style: t.style,\n classNames: { ...classNames, ...t.classNames },\n styles: { ...styles, ...t.styles },\n };\n };\n\n const resolvedTheme = theme === \"system\" ? (systemDark ? \"dark\" : \"light\") : theme;\n\n return createPortal(\n <div role=\"region\" aria-label={labels.region} className=\"wello-notifications-region\" dir={dir}>\n {groups.map(([key, group]) => (\n <ol\n key={key}\n className={cx(\"wello-notifications-toaster\", classNames.toaster, className)}\n data-y={group.y}\n data-x={group.x}\n data-theme={resolvedTheme}\n dir={dir}\n style={\n {\n \"--wello-notifications-width\": toCssSize(width),\n \"--wello-notifications-gap\": `${gap}px`,\n \"--wello-notifications-offset\": toCssSize(offset),\n zIndex,\n ...styles.toaster,\n ...style,\n } as CSSProperties\n }\n onMouseEnter={pauseOnHover ? () => setHovered(key) : undefined}\n onMouseLeave={pauseOnHover ? () => setHovered(null) : undefined}\n onFocus={pauseOnHover ? () => setHovered(key) : undefined}\n onBlur={\n pauseOnHover\n ? (event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null))\n setHovered(null);\n }\n : undefined\n }\n >\n {group.toasts.map((t) => (\n <ToastItem\n key={t.id}\n toast={t}\n settings={resolve(t)}\n paused={state.paused || pageHidden || hovered === key}\n labels={labels}\n />\n ))}\n </ol>\n ))}\n </div>,\n target,\n );\n}\n","/** Tailwind CSS default palette (v3 hex values, MIT); shades 50–950. */\nconst PALETTE: Record<string, readonly string[]> = {\n slate: [\n \"#f8fafc\",\n \"#f1f5f9\",\n \"#e2e8f0\",\n \"#cbd5e1\",\n \"#94a3b8\",\n \"#64748b\",\n \"#475569\",\n \"#334155\",\n \"#1e293b\",\n \"#0f172a\",\n \"#020617\",\n ],\n gray: [\n \"#f9fafb\",\n \"#f3f4f6\",\n \"#e5e7eb\",\n \"#d1d5db\",\n \"#9ca3af\",\n \"#6b7280\",\n \"#4b5563\",\n \"#374151\",\n \"#1f2937\",\n \"#111827\",\n \"#030712\",\n ],\n zinc: [\n \"#fafafa\",\n \"#f4f4f5\",\n \"#e4e4e7\",\n \"#d4d4d8\",\n \"#a1a1aa\",\n \"#71717a\",\n \"#52525b\",\n \"#3f3f46\",\n \"#27272a\",\n \"#18181b\",\n \"#09090b\",\n ],\n neutral: [\n \"#fafafa\",\n \"#f5f5f5\",\n \"#e5e5e5\",\n \"#d4d4d4\",\n \"#a3a3a3\",\n \"#737373\",\n \"#525252\",\n \"#404040\",\n \"#262626\",\n \"#171717\",\n \"#0a0a0a\",\n ],\n stone: [\n \"#fafaf9\",\n \"#f5f5f4\",\n \"#e7e5e4\",\n \"#d6d3d1\",\n \"#a8a29e\",\n \"#78716c\",\n \"#57534e\",\n \"#44403c\",\n \"#292524\",\n \"#1c1917\",\n \"#0c0a09\",\n ],\n red: [\n \"#fef2f2\",\n \"#fee2e2\",\n \"#fecaca\",\n \"#fca5a5\",\n \"#f87171\",\n \"#ef4444\",\n \"#dc2626\",\n \"#b91c1c\",\n \"#991b1b\",\n \"#7f1d1d\",\n \"#450a0a\",\n ],\n orange: [\n \"#fff7ed\",\n \"#ffedd5\",\n \"#fed7aa\",\n \"#fdba74\",\n \"#fb923c\",\n \"#f97316\",\n \"#ea580c\",\n \"#c2410c\",\n \"#9a3412\",\n \"#7c2d12\",\n \"#431407\",\n ],\n amber: [\n \"#fffbeb\",\n \"#fef3c7\",\n \"#fde68a\",\n \"#fcd34d\",\n \"#fbbf24\",\n \"#f59e0b\",\n \"#d97706\",\n \"#b45309\",\n \"#92400e\",\n \"#78350f\",\n \"#451a03\",\n ],\n yellow: [\n \"#fefce8\",\n \"#fef9c3\",\n \"#fef08a\",\n \"#fde047\",\n \"#facc15\",\n \"#eab308\",\n \"#ca8a04\",\n \"#a16207\",\n \"#854d0e\",\n \"#713f12\",\n \"#422006\",\n ],\n lime: [\n \"#f7fee7\",\n \"#ecfccb\",\n \"#d9f99d\",\n \"#bef264\",\n \"#a3e635\",\n \"#84cc16\",\n \"#65a30d\",\n \"#4d7c0f\",\n \"#3f6212\",\n \"#365314\",\n \"#1a2e05\",\n ],\n green: [\n \"#f0fdf4\",\n \"#dcfce7\",\n \"#bbf7d0\",\n \"#86efac\",\n \"#4ade80\",\n \"#22c55e\",\n \"#16a34a\",\n \"#15803d\",\n \"#166534\",\n \"#14532d\",\n \"#052e16\",\n ],\n emerald: [\n \"#ecfdf5\",\n \"#d1fae5\",\n \"#a7f3d0\",\n \"#6ee7b7\",\n \"#34d399\",\n \"#10b981\",\n \"#059669\",\n \"#047857\",\n \"#065f46\",\n \"#064e3b\",\n \"#022c22\",\n ],\n teal: [\n \"#f0fdfa\",\n \"#ccfbf1\",\n \"#99f6e4\",\n \"#5eead4\",\n \"#2dd4bf\",\n \"#14b8a6\",\n \"#0d9488\",\n \"#0f766e\",\n \"#115e59\",\n \"#134e4a\",\n \"#042f2e\",\n ],\n cyan: [\n \"#ecfeff\",\n \"#cffafe\",\n \"#a5f3fc\",\n \"#67e8f9\",\n \"#22d3ee\",\n \"#06b6d4\",\n \"#0891b2\",\n \"#0e7490\",\n \"#155e75\",\n \"#164e63\",\n \"#083344\",\n ],\n sky: [\n \"#f0f9ff\",\n \"#e0f2fe\",\n \"#bae6fd\",\n \"#7dd3fc\",\n \"#38bdf8\",\n \"#0ea5e9\",\n \"#0284c7\",\n \"#0369a1\",\n \"#075985\",\n \"#0c4a6e\",\n \"#082f49\",\n ],\n blue: [\n \"#eff6ff\",\n \"#dbeafe\",\n \"#bfdbfe\",\n \"#93c5fd\",\n \"#60a5fa\",\n \"#3b82f6\",\n \"#2563eb\",\n \"#1d4ed8\",\n \"#1e40af\",\n \"#1e3a8a\",\n \"#172554\",\n ],\n indigo: [\n \"#eef2ff\",\n \"#e0e7ff\",\n \"#c7d2fe\",\n \"#a5b4fc\",\n \"#818cf8\",\n \"#6366f1\",\n \"#4f46e5\",\n \"#4338ca\",\n \"#3730a3\",\n \"#312e81\",\n \"#1e1b4b\",\n ],\n violet: [\n \"#f5f3ff\",\n \"#ede9fe\",\n \"#ddd6fe\",\n \"#c4b5fd\",\n \"#a78bfa\",\n \"#8b5cf6\",\n \"#7c3aed\",\n \"#6d28d9\",\n \"#5b21b6\",\n \"#4c1d95\",\n \"#2e1065\",\n ],\n purple: [\n \"#faf5ff\",\n \"#f3e8ff\",\n \"#e9d5ff\",\n \"#d8b4fe\",\n \"#c084fc\",\n \"#a855f7\",\n \"#9333ea\",\n \"#7e22ce\",\n \"#6b21a8\",\n \"#581c87\",\n \"#3b0764\",\n ],\n fuchsia: [\n \"#fdf4ff\",\n \"#fae8ff\",\n \"#f5d0fe\",\n \"#f0abfc\",\n \"#e879f9\",\n \"#d946ef\",\n \"#c026d3\",\n \"#a21caf\",\n \"#86198f\",\n \"#701a75\",\n \"#4a044e\",\n ],\n pink: [\n \"#fdf2f8\",\n \"#fce7f3\",\n \"#fbcfe8\",\n \"#f9a8d4\",\n \"#f472b6\",\n \"#ec4899\",\n \"#db2777\",\n \"#be185d\",\n \"#9d174d\",\n \"#831843\",\n \"#500724\",\n ],\n rose: [\n \"#fff1f2\",\n \"#ffe4e6\",\n \"#fecdd3\",\n \"#fda4af\",\n \"#fb7185\",\n \"#f43f5e\",\n \"#e11d48\",\n \"#be123c\",\n \"#9f1239\",\n \"#881337\",\n \"#4c0519\",\n ],\n};\nconst SHADES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];\n\n/** `'blue-600'`, `'blue'` (= 500), or any CSS color. */\nexport type ToastColor = string;\n\n/** Resolves a Tailwind name (`'blue-600'`) to its hex value; any other CSS color is returned as is. */\nexport function resolveColor(color: ToastColor): string {\n const match = /^([a-z]+)(?:-(\\d{2,3}))?$/.exec(color);\n const palette = match && PALETTE[match[1]];\n if (!palette) return color;\n const index = SHADES.indexOf(match[2] === undefined ? 500 : Number(match[2]));\n return index === -1 ? color : palette[index];\n}\n\n","export interface ToasterLabels {\n /** Name of the notifications region for screen readers */\n region: string;\n close: string;\n}\n\nexport type ToasterLocale = \"en\" | \"ar\";\n\nconst LABELS: Record<ToasterLocale, ToasterLabels> = {\n en: { region: \"Notifications\", close: \"Close\" },\n ar: { region: \"الإشعارات\", close: \"إغلاق\" },\n};\n\nexport function resolveLabels(locale: ToasterLocale = \"en\", overrides?: Partial<ToasterLabels>): ToasterLabels {\n return { ...(LABELS[locale] ?? LABELS.en), ...overrides };\n}\n","export function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\n/** `16` → `'16px'`; strings pass through. */\nexport const toCssSize = (value: number | string) => (typeof value === \"number\" ? `${value}px` : value);\n","import type { ReactNode, SVGProps } from \"react\";\nimport type { ToastType } from \"../core/types\";\n\nexport type IconProps = SVGProps<SVGSVGElement>;\n\nfunction icon(paths: ReactNode) {\n return function Icon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width=\"1em\"\n height=\"1em\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.25}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n {paths}\n </svg>\n );\n };\n}\n\nexport const SuccessIcon = icon(\n <>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m9 12 2 2 4-4\" />\n </>,\n);\nexport const ErrorIcon = icon(\n <>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m15 9-6 6M9 9l6 6\" />\n </>,\n);\nexport const WarningIcon = icon(\n <>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v4M12 16h.01\" />\n </>,\n);\nexport const InfoIcon = icon(\n <>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4M12 8h.01\" />\n </>,\n);\nexport const LoadingIcon = icon(<path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />);\nexport const CloseIcon = icon(<path d=\"M18 6 6 18M6 6l12 12\" />);\n\n/** Built-in icon per type; plain toasts have none. */\nexport const DEFAULT_ICONS: Partial<Record<ToastType, ReactNode>> = {\n success: <SuccessIcon />,\n error: <ErrorIcon />,\n warning: <WarningIcon />,\n info: <InfoIcon />,\n loading: <LoadingIcon className=\"wello-notifications-spin\" />,\n};\n","import {\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n} from \"react\";\nimport { toastStore } from \"../core/store\";\nimport type {\n ToastAction,\n ToastClassNames,\n ToastRecord,\n ToastStyles,\n ToastStylesNames,\n} from \"../core/types\";\nimport type { ToasterLabels } from \"../lib/labels\";\nimport { cx } from \"../lib/utils\";\nimport { playNotificationSound, type NotificationSoundName } from \"../sound/notification-sound\";\nimport { CloseIcon } from \"./icons\";\n\n/** Exit animation length; keep in sync with styles.css. */\nexport const EXIT_MS = 320;\n/** Horizontal drag that dismisses a toast */\nconst SWIPE_THRESHOLD = 64;\n\nexport interface ResolvedToast {\n duration: number | false;\n color: string;\n icon: ReactNode;\n dismissible: boolean;\n closeButton: boolean;\n progress: boolean;\n swipe: boolean;\n sound: boolean | string;\n className?: string;\n style?: CSSProperties;\n classNames: ToastClassNames;\n styles: ToastStyles;\n}\n\ninterface ToastItemProps {\n toast: ToastRecord;\n settings: ResolvedToast;\n /** Hover, hidden tab or `toast.pauseAll()` */\n paused: boolean;\n labels: ToasterLabels;\n}\n\nconst TYPE_SOUNDS: Partial<Record<ToastRecord[\"type\"], NotificationSoundName>> = {\n success: \"success\",\n error: \"error\",\n warning: \"warning\",\n info: \"info\",\n default: \"pop\",\n};\n\nexport function ToastItem({ toast, settings, paused, labels }: ToastItemProps) {\n const { id, open, version, type } = toast;\n const { duration, classNames, styles } = settings;\n const cardRef = useRef<HTMLDivElement>(null);\n const [swipedOut, setSwipedOut] = useState<\"start\" | \"end\" | null>(null);\n\n const part = (name: ToastStylesNames, base: string) => ({\n className: cx(base, classNames[name]),\n style: styles[name],\n });\n\n // Opened: callback once (the ref survives StrictMode's second effect run).\n const opened = useRef(false);\n useEffect(() => {\n if (opened.current) return;\n opened.current = true;\n toast.onOpen?.(toast);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Sound when it appears, and again when a loading toast settles (toast.promise).\n const soundedType = useRef<ToastRecord[\"type\"] | null>(null);\n useEffect(() => {\n const sound = settings.sound;\n if (!sound || !open || type === \"loading\" || soundedType.current === type) return;\n soundedType.current = type;\n const builtIn = TYPE_SOUNDS[type] ?? \"info\";\n void playNotificationSound(typeof sound === \"string\" ? sound : builtIn, { fallback: builtIn });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [type, open]);\n\n // Auto close. The remaining time survives pauses and restarts on every update.\n const remaining = useRef<number | false>(duration);\n const lastVersion = useRef(version);\n if (lastVersion.current !== version) {\n lastVersion.current = version;\n remaining.current = duration;\n }\n useEffect(() => {\n const left = remaining.current;\n if (!open || paused || left === false || !Number.isFinite(left)) return;\n const startedAt = Date.now();\n const timer = setTimeout(() => toastStore.dismiss(id, \"auto\"), Math.max(0, left));\n return () => {\n clearTimeout(timer);\n // After an update the timer starts over (reset above), so don't keep the old leftover.\n if (lastVersion.current === version) {\n remaining.current = Math.max(0, left - (Date.now() - startedAt));\n }\n };\n }, [id, open, paused, version, duration]);\n\n // Closed: remove after the exit animation.\n useEffect(() => {\n if (open) return;\n const timer = setTimeout(() => toastStore.remove(id), EXIT_MS);\n return () => clearTimeout(timer);\n }, [id, open]);\n\n // Swipe to dismiss (mouse, pen or touch).\n const drag = useRef<{ x: number; y: number; pointer: number; dx: number } | null>(null);\n const canSwipe = settings.swipe && settings.dismissible && open;\n\n function onPointerDown(event: PointerEvent<HTMLDivElement>) {\n if (!canSwipe || event.button !== 0) return;\n if ((event.target as HTMLElement).closest(\"button, a, input, textarea, select\")) return;\n drag.current = { x: event.clientX, y: event.clientY, pointer: event.pointerId, dx: 0 };\n }\n function onPointerMove(event: PointerEvent<HTMLDivElement>) {\n const state = drag.current;\n const card = cardRef.current;\n if (!state || !card || event.pointerId !== state.pointer) return;\n const dx = event.clientX - state.x;\n // Vertical scroll wins until the drag is clearly sideways.\n if (state.dx === 0 && Math.abs(dx) < 6) return;\n if (state.dx === 0 && Math.abs(event.clientY - state.y) > Math.abs(dx)) {\n drag.current = null;\n return;\n }\n if (state.dx === 0) card.setPointerCapture(event.pointerId);\n state.dx = dx;\n card.dataset.swiping = \"\";\n card.style.setProperty(\"--wello-notifications-swipe\", `${dx}px`);\n card.style.opacity = String(Math.max(0.2, 1 - Math.abs(dx) / 220));\n }\n function onPointerUp(event: PointerEvent<HTMLDivElement>) {\n const state = drag.current;\n const card = cardRef.current;\n drag.current = null;\n if (!state || !card || event.pointerId !== state.pointer) return;\n delete card.dataset.swiping;\n if (Math.abs(state.dx) >= SWIPE_THRESHOLD) {\n // Physical side, so the card keeps moving the way it was dragged.\n setSwipedOut(state.dx > 0 ? \"end\" : \"start\");\n toastStore.dismiss(id);\n return;\n }\n card.style.removeProperty(\"--wello-notifications-swipe\");\n card.style.opacity = \"\";\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLLIElement>) {\n if (event.key === \"Escape\" && settings.dismissible) {\n event.stopPropagation();\n toastStore.dismiss(id);\n }\n }\n\n const important = toast.important ?? type === \"error\";\n const tone = { \"--wello-notifications-tone\": settings.color } as CSSProperties;\n\n return (\n <li\n className=\"wello-notifications-item\"\n data-state={open ? \"open\" : \"closing\"}\n data-swiped={swipedOut ?? undefined}\n onKeyDown={onKeyDown}\n >\n <div className=\"wello-notifications-item-inner\">\n {toast.render ? (\n <div\n ref={cardRef}\n className={cx(\"wello-notifications-custom\", settings.className)}\n style={{ ...tone, ...settings.style }}\n role={important ? \"alert\" : \"status\"}\n aria-live={important ? \"assertive\" : \"polite\"}\n aria-atomic=\"true\"\n data-type={type}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n >\n {toast.render(toast)}\n </div>\n ) : (\n <div\n ref={cardRef}\n className={cx(\"wello-notifications-toast\", classNames.toast, settings.className)}\n style={{ ...tone, ...styles.toast, ...settings.style }}\n role={important ? \"alert\" : \"status\"}\n aria-live={important ? \"assertive\" : \"polite\"}\n aria-atomic=\"true\"\n data-type={type}\n data-dismissible={settings.dismissible || undefined}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n >\n {settings.icon != null && settings.icon !== false && (\n <span {...part(\"icon\", \"wello-notifications-icon\")}>{settings.icon}</span>\n )}\n <div {...part(\"content\", \"wello-notifications-content\")}>\n {toast.title != null && toast.title !== false && (\n <div {...part(\"title\", \"wello-notifications-title\")}>{toast.title}</div>\n )}\n {toast.description != null && toast.description !== false && (\n <div {...part(\"description\", \"wello-notifications-description\")}>\n {toast.description}\n </div>\n )}\n {(toast.action || toast.cancel) && (\n <div {...part(\"actions\", \"wello-notifications-actions\")}>\n {toast.cancel && (\n <ActionButton\n action={toast.cancel}\n id={id}\n {...part(\"cancel\", \"wello-notifications-button wello-notifications-cancel\")}\n />\n )}\n {toast.action && (\n <ActionButton\n action={toast.action}\n id={id}\n {...part(\"action\", \"wello-notifications-button wello-notifications-action\")}\n />\n )}\n </div>\n )}\n </div>\n {settings.dismissible && settings.closeButton && (\n <button\n type=\"button\"\n {...part(\"closeButton\", \"wello-notifications-close\")}\n aria-label={labels.close}\n title={labels.close}\n onClick={() => toastStore.dismiss(id)}\n >\n <CloseIcon />\n </button>\n )}\n {settings.progress && duration !== false && (\n <span\n key={version}\n {...part(\"progress\", \"wello-notifications-progress\")}\n style={{\n animationDuration: `${duration}ms`,\n animationPlayState: paused || !open ? \"paused\" : \"running\",\n ...styles.progress,\n }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n )}\n </div>\n </li>\n );\n}\n\nfunction ActionButton({\n action,\n id,\n className,\n style,\n}: {\n action: ToastAction;\n id: ToastRecord[\"id\"];\n className: string;\n style?: CSSProperties;\n}) {\n return (\n <button\n type=\"button\"\n className={className}\n style={style}\n onClick={(event) => {\n action.onClick?.(event);\n if (action.closeOnClick !== false && !event.defaultPrevented) toastStore.dismiss(id);\n }}\n >\n {action.label}\n </button>\n );\n}\n","export type NotificationPriority = \"critical\" | \"high\" | \"normal\" | \"low\";\n\n/** Built-in sounds, synthesized in the browser (no files to host). */\nexport type NotificationSoundName =\n | \"success\"\n | \"error\"\n | \"warning\"\n | \"info\"\n | \"message\"\n | \"critical\"\n | \"pop\";\n\nexport interface PlaySoundOptions {\n /** 0–1. Default: 0.7 */\n volume?: number;\n /**\n * Built-in sound played when there is no URL or it can't play (missing file, autoplay\n * blocked before the first click). `false` for silence. Default: 'info'\n */\n fallback?: NotificationSoundName | NotificationPriority | false;\n}\n\n// ── Synthesis ────────────────────────────────────────────────────────────────\n\n/** One partial of a timbre: frequency ratio, level, and decay relative to the note length. */\ninterface Overtone {\n ratio: number;\n gain: number;\n decay: number;\n type?: OscillatorType;\n}\n\ntype Timbre = \"bell\" | \"marimba\" | \"pluck\" | \"glass\";\n\nconst TIMBRES: Record<Timbre, Overtone[]> = {\n // Warm bell: octave and a slightly inharmonic upper partial for shimmer.\n bell: [\n { ratio: 1, gain: 1, decay: 1 },\n { ratio: 2, gain: 0.28, decay: 0.55 },\n { ratio: 3.01, gain: 0.1, decay: 0.32 },\n { ratio: 5.43, gain: 0.035, decay: 0.16 },\n ],\n // Wooden mallet: strong fundamental, quick bright \"knock\" on top.\n marimba: [\n { ratio: 1, gain: 1, decay: 1 },\n { ratio: 3.98, gain: 0.16, decay: 0.12 },\n { ratio: 9.8, gain: 0.03, decay: 0.05 },\n ],\n // Soft, darker string pluck for errors.\n pluck: [\n { ratio: 1, gain: 1, decay: 1, type: \"triangle\" },\n { ratio: 2, gain: 0.18, decay: 0.4 },\n { ratio: 0.5, gain: 0.22, decay: 0.7 },\n ],\n // Thin and bright, cuts through for urgent alerts.\n glass: [\n { ratio: 1, gain: 1, decay: 1 },\n { ratio: 2.76, gain: 0.22, decay: 0.45 },\n { ratio: 5.4, gain: 0.07, decay: 0.2 },\n ],\n};\n\ninterface Note {\n /** Frequency in Hz */\n f: number;\n /** Start, seconds from the beginning of the sound */\n at: number;\n /** Ring time in seconds */\n dur: number;\n gain?: number;\n timbre: Timbre;\n /** Starts this many times higher and slides down in 40 ms (a \"blip\") */\n glide?: number;\n}\n\n// Equal-tempered pitches used below.\nconst N = {\n G4: 392.0,\n A4: 440.0,\n C5: 523.25,\n D5: 587.33,\n E5: 659.25,\n F5: 698.46,\n G5: 783.99,\n A5: 880.0,\n B5: 987.77,\n C6: 1046.5,\n E6: 1318.51,\n G6: 1567.98,\n};\n\nconst SOUNDS: Record<NotificationSoundName, Note[]> = {\n // Rising major arpeggio: bright and \"done\".\n success: [\n { f: N.C5, at: 0, dur: 0.5, gain: 0.7, timbre: \"marimba\" },\n { f: N.E5, at: 0.075, dur: 0.5, gain: 0.7, timbre: \"marimba\" },\n { f: N.G5, at: 0.15, dur: 0.55, gain: 0.75, timbre: \"marimba\" },\n { f: N.C6, at: 0.225, dur: 0.9, gain: 0.6, timbre: \"bell\" },\n ],\n // Falling minor step, low and soft: noticeable without being harsh.\n error: [\n { f: N.E5, at: 0, dur: 0.35, gain: 0.75, timbre: \"pluck\" },\n { f: N.C5, at: 0.13, dur: 0.6, gain: 0.85, timbre: \"pluck\" },\n ],\n // Two even knocks: \"look here\".\n warning: [\n { f: N.D5, at: 0, dur: 0.32, gain: 0.85, timbre: \"marimba\" },\n { f: N.D5, at: 0.17, dur: 0.45, gain: 0.85, timbre: \"marimba\" },\n ],\n // A single soft bell with its octave.\n info: [\n { f: N.A5, at: 0, dur: 1.1, gain: 0.95, timbre: \"bell\" },\n { f: N.E6, at: 0.03, dur: 0.6, gain: 0.25, timbre: \"bell\" },\n ],\n // Chat-style \"ding-dong\".\n message: [\n { f: N.E6, at: 0, dur: 0.6, gain: 0.55, timbre: \"bell\" },\n { f: N.B5, at: 0.12, dur: 1, gain: 0.65, timbre: \"bell\" },\n ],\n // Three quick rising pairs: urgent, repeats so it isn't missed.\n critical: [0, 0.32, 0.64].flatMap((start) => [\n { f: N.A5, at: start, dur: 0.22, gain: 0.7, timbre: \"glass\" as const },\n { f: N.E6, at: start + 0.1, dur: 0.3, gain: 0.7, timbre: \"glass\" as const },\n ]),\n // Tiny bubble pop for plain toasts.\n pop: [{ f: N.G5, at: 0, dur: 0.3, gain: 2.2, timbre: \"marimba\", glide: 1.6 }],\n};\n\nconst PRIORITY_SOUNDS: Record<NotificationPriority, NotificationSoundName> = {\n critical: \"critical\",\n high: \"message\",\n normal: \"info\",\n low: \"pop\",\n};\n\nconst isSoundName = (value: string): value is NotificationSoundName => value in SOUNDS;\n\nconst toSoundName = (name: string): NotificationSoundName =>\n isSoundName(name) ? name : (PRIORITY_SOUNDS[name as NotificationPriority] ?? \"info\");\n\nconst ATTACK = 0.006;\n\nfunction scheduleNote(ctx: BaseAudioContext, out: AudioNode, note: Note, start: number) {\n const t0 = start + note.at;\n for (const partial of TIMBRES[note.timbre]) {\n const frequency = note.f * partial.ratio;\n // Inaudible or aliasing partials only add noise.\n if (frequency > 16000) continue;\n const peak = (note.gain ?? 1) * partial.gain;\n const end = t0 + ATTACK + Math.max(0.04, note.dur * partial.decay);\n const oscillator = ctx.createOscillator();\n const envelope = ctx.createGain();\n oscillator.type = partial.type ?? \"sine\";\n if (note.glide) {\n oscillator.frequency.setValueAtTime(frequency * note.glide, t0);\n oscillator.frequency.exponentialRampToValueAtTime(frequency, t0 + 0.04);\n } else {\n oscillator.frequency.setValueAtTime(frequency, t0);\n }\n // Fast attack (no click), then a natural exponential ring-out.\n envelope.gain.setValueAtTime(0.0001, t0);\n envelope.gain.exponentialRampToValueAtTime(peak, t0 + ATTACK);\n envelope.gain.exponentialRampToValueAtTime(0.0001, end);\n oscillator.connect(envelope);\n envelope.connect(out);\n oscillator.start(t0);\n oscillator.stop(end + 0.02);\n }\n}\n\n/** Short stereo room, generated once per context: a little space instead of a dry beep. */\nfunction createRoom(ctx: BaseAudioContext): AudioBuffer {\n const seconds = 1.2;\n const length = Math.floor(ctx.sampleRate * seconds);\n const buffer = ctx.createBuffer(2, length, ctx.sampleRate);\n for (let channel = 0; channel < 2; channel++) {\n const data = buffer.getChannelData(channel);\n for (let i = 0; i < length; i++) {\n data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / length, 3.5);\n }\n }\n return buffer;\n}\n\ninterface Bus {\n input: GainNode;\n}\n\nconst buses = new WeakMap<BaseAudioContext, Bus>();\n\n/** input → (dry + reverb) → gentle low-pass → compressor → speakers */\nfunction bus(ctx: BaseAudioContext): Bus {\n const existing = buses.get(ctx);\n if (existing) return existing;\n const input = ctx.createGain();\n const tone = ctx.createBiquadFilter();\n tone.type = \"lowpass\";\n tone.frequency.value = 7500;\n const reverb = ctx.createConvolver();\n reverb.buffer = createRoom(ctx);\n const wet = ctx.createGain();\n wet.gain.value = 0.16;\n const compressor = ctx.createDynamicsCompressor();\n compressor.threshold.value = -16;\n compressor.knee.value = 10;\n compressor.ratio.value = 4;\n compressor.attack.value = 0.002;\n compressor.release.value = 0.2;\n input.connect(tone);\n tone.connect(compressor);\n tone.connect(reverb);\n reverb.connect(wet);\n wet.connect(compressor);\n compressor.connect(ctx.destination);\n const created = { input };\n buses.set(ctx, created);\n return created;\n}\n\n/**\n * Schedules a built-in sound on any audio context (also an `OfflineAudioContext`, to render it).\n * Returns its length in seconds.\n */\nexport function scheduleSound(\n ctx: BaseAudioContext,\n name: NotificationSoundName | NotificationPriority,\n volume = 0.7,\n when = ctx.currentTime + 0.01,\n): number {\n const notes = SOUNDS[toSoundName(name)];\n const level = ctx.createGain();\n // Headroom: several partials and notes overlap.\n level.gain.value = Math.min(1, Math.max(0, volume)) * 0.32;\n level.connect(bus(ctx).input);\n for (const note of notes) scheduleNote(ctx, level, note, when);\n return Math.max(...notes.map((n) => n.at + n.dur)) + 1.2;\n}\n\n// ── Playback ─────────────────────────────────────────────────────────────────\n\nlet context: AudioContext | null = null;\nconst buffers = new Map<string, Promise<AudioBuffer>>();\n\nfunction audioContext(): AudioContext | null {\n if (typeof window === \"undefined\") return null;\n try {\n const Ctor =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctor) return null;\n context ??= new Ctor();\n if (context.state === \"suspended\") void context.resume().catch(() => {});\n return context;\n } catch {\n return null;\n }\n}\n\n/**\n * Plays a built-in sound. Silent where audio isn't available.\n *\n * @example\n * playSound(\"success\");\n * playSound(\"critical\", { volume: 1 });\n */\nexport function playSound(\n name: NotificationSoundName | NotificationPriority = \"info\",\n options: { volume?: number } = {},\n): void {\n const ctx = audioContext();\n if (!ctx) return;\n try {\n scheduleSound(ctx, name, options.volume ?? 0.7);\n } catch {\n // Never let a sound break the app.\n }\n}\n\n/** Plays the built-in sound for a priority (`critical`, `high`, `normal`, `low`) or a sound name. */\nexport function playTone(\n priority: NotificationPriority | NotificationSoundName = \"normal\",\n volume = 0.7,\n): void {\n playSound(priority, { volume });\n}\n\n/** Names of the built-in sounds. */\nexport const NOTIFICATION_SOUNDS = Object.keys(SOUNDS) as NotificationSoundName[];\n\n/**\n * Plays a sound file (decoded once, then cached) or a built-in sound by name, falling back\n * to a built-in sound. Never throws.\n *\n * @example\n * playNotificationSound(\"/sounds/notification.mp3\");\n * playNotificationSound(\"message\");\n * playNotificationSound(undefined, { fallback: \"critical\" }); // built-in only\n */\nexport async function playNotificationSound(\n url?: string,\n options: PlaySoundOptions = {},\n): Promise<void> {\n const { volume = 0.7, fallback = \"info\" } = options;\n if (url && isSoundName(url)) return playSound(url, { volume });\n if (url) {\n const ctx = audioContext();\n if (ctx) {\n try {\n let buffer = buffers.get(url);\n if (!buffer) {\n buffer = fetch(url)\n .then((response) => {\n if (!response.ok) throw new Error(`${response.status}`);\n return response.arrayBuffer();\n })\n .then((data) => ctx.decodeAudioData(data));\n buffers.set(url, buffer);\n // Don't cache failures; the file may appear later.\n buffer.catch(() => buffers.delete(url));\n }\n const source = ctx.createBufferSource();\n const gain = ctx.createGain();\n gain.gain.value = volume;\n source.buffer = await buffer;\n source.connect(gain);\n gain.connect(ctx.destination);\n source.start(0);\n return;\n } catch {\n // Try an <audio> element, then the built-in sound.\n }\n }\n try {\n const audio = new Audio(url);\n audio.volume = volume;\n await audio.play();\n return;\n } catch {\n // Fall back to the built-in sound.\n }\n }\n if (fallback) playSound(fallback, { volume });\n}\n","export interface TabNotificationsOptions {\n /** Title with unread items. Default: `(count) title`, `(99+) title` above 99 */\n formatTitle?: (count: number, title: string) => string;\n /** Color of the favicon dot. Default: red-500 */\n dotColor?: string;\n /** Add the dot to the favicon while there are unread items. Default: true */\n favicon?: boolean;\n}\n\nexport interface FlashTitleOptions {\n /** Milliseconds between swaps. Default: 1500 */\n interval?: number;\n /** Stop when the user comes back to the tab. Default: true */\n stopOnFocus?: boolean;\n}\n\nexport interface TabNotifications {\n /** Shows the count in the title and a dot on the favicon; 0 clears both */\n setUnreadCount(count: number): void;\n getUnreadCount(): number;\n /** Alternates the title with a message until `stopFlashing` (or the tab is focused) */\n flashTitle(message: string, options?: FlashTitleOptions | number): void;\n stopFlashing(): void;\n isFlashing(): boolean;\n /** Restores the original title and favicon */\n reset(): void;\n}\n\nconst defaultFormat = (count: number, title: string) => `(${count > 99 ? \"99+\" : count}) ${title}`;\n\n/**\n * Unread count in the tab title, a dot on the favicon, and a flashing title for urgent alerts.\n * Safe to create on the server; it touches `document` only when used.\n *\n * @example\n * const tab = createTabNotifications();\n * tab.setUnreadCount(5); // \"(5) My app\" + red dot\n * tab.flashTitle(\"🔴 New order\"); // until the user looks at the tab\n */\nexport function createTabNotifications(options: TabNotificationsOptions = {}): TabNotifications {\n const { formatTitle = defaultFormat, dotColor = \"#ef4444\", favicon = true } = options;\n let ready = false;\n let originalTitle = \"\";\n let originalFavicon: string | null = null;\n let unread = 0;\n let flashTimer: ReturnType<typeof setInterval> | null = null;\n let stopListening: (() => void) | null = null;\n let dotted: { source: string; url: string } | null = null;\n let faviconRequest = 0;\n\n const hasDocument = () => typeof document !== \"undefined\";\n\n function init() {\n if (ready || !hasDocument()) return;\n ready = true;\n originalTitle = document.title;\n originalFavicon =\n document.querySelector<HTMLLinkElement>('link[rel~=\"icon\"]')?.href ?? null;\n }\n\n const baseTitle = () => (unread > 0 ? formatTitle(unread, originalTitle) : originalTitle);\n\n function applyFavicon(href: string | null) {\n const links = document.querySelectorAll<HTMLLinkElement>('link[rel~=\"icon\"]');\n if (href === null) {\n // There was no favicon to begin with: remove ours.\n links.forEach((link) => link.dataset.wnFavicon !== undefined && link.remove());\n return;\n }\n let link = links[0];\n if (!link) {\n link = document.createElement(\"link\");\n link.rel = \"icon\";\n link.dataset.wnFavicon = \"\";\n document.head.appendChild(link);\n }\n link.href = href;\n }\n\n function drawDot(base: HTMLImageElement | null): string | null {\n const size = 32;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n if (base) ctx.drawImage(base, 0, 0, size, size);\n const radius = base ? 7 : 10;\n const x = size - radius - 1;\n const y = base ? radius + 1 : size / 2;\n ctx.beginPath();\n ctx.arc(x, y, radius + 2, 0, Math.PI * 2);\n ctx.fillStyle = \"#ffffff\";\n ctx.fill();\n ctx.beginPath();\n ctx.arc(x, y, radius, 0, Math.PI * 2);\n ctx.fillStyle = dotColor;\n ctx.fill();\n try {\n return canvas.toDataURL(\"image/png\");\n } catch {\n return null; // cross-origin favicon taints the canvas\n }\n }\n\n function showDot() {\n if (!favicon) return;\n const source = originalFavicon ?? \"\";\n if (dotted?.source === source) return applyFavicon(dotted.url);\n const request = ++faviconRequest;\n const done = (base: HTMLImageElement | null) => {\n if (request !== faviconRequest || unread === 0) return;\n const url = drawDot(base);\n if (!url) return;\n dotted = { source, url };\n applyFavicon(url);\n };\n if (!source) return done(null);\n const image = new Image();\n image.crossOrigin = \"anonymous\";\n image.onload = () => done(image);\n image.onerror = () => done(null);\n image.src = source;\n }\n\n function hideDot() {\n faviconRequest++;\n if (favicon) applyFavicon(originalFavicon);\n }\n\n const api: TabNotifications = {\n setUnreadCount(count) {\n if (!hasDocument()) return;\n init();\n unread = Math.max(0, Math.floor(count) || 0);\n if (!flashTimer) document.title = baseTitle();\n if (unread > 0) showDot();\n else hideDot();\n },\n getUnreadCount: () => unread,\n flashTitle(message, flashOptions) {\n if (!hasDocument()) return;\n init();\n api.stopFlashing();\n const { interval = 1500, stopOnFocus = true } =\n typeof flashOptions === \"number\" ? { interval: flashOptions } : (flashOptions ?? {});\n let showMessage = false;\n document.title = message;\n flashTimer = setInterval(() => {\n document.title = showMessage ? message : baseTitle();\n showMessage = !showMessage;\n }, interval);\n if (stopOnFocus) {\n const onVisible = () => {\n if (document.visibilityState === \"visible\" && document.hasFocus()) api.stopFlashing();\n };\n // Already looking at the tab: still flash, until they leave and come back.\n document.addEventListener(\"visibilitychange\", onVisible);\n window.addEventListener(\"focus\", onVisible);\n stopListening = () => {\n document.removeEventListener(\"visibilitychange\", onVisible);\n window.removeEventListener(\"focus\", onVisible);\n };\n }\n },\n stopFlashing() {\n if (flashTimer) clearInterval(flashTimer);\n flashTimer = null;\n stopListening?.();\n stopListening = null;\n if (ready) document.title = baseTitle();\n },\n isFlashing: () => flashTimer !== null,\n reset() {\n api.stopFlashing();\n unread = 0;\n if (!ready) return;\n document.title = originalTitle;\n hideDot();\n },\n };\n return api;\n}\n\n/** Shared instance with the default options. */\nexport const tabNotifications: TabNotifications = createTabNotifications();\n"],"mappings":"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CA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AA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","names":["useEffect","useState","useSyncExternalStore","jsx","jsxs","toast","state","jsx","useState","useEffect","update","state","useSyncExternalStore","link"]}
@@ -0,0 +1,338 @@
1
+ /*
2
+ * @wello-dev/notifications
3
+ * In the `components` layer, so Tailwind utilities in `classNames` win without `!`.
4
+ * Theme with the --wello-notifications-* variables on `.wello-notifications-toaster`.
5
+ */
6
+ @layer theme, base, components, utilities;
7
+
8
+ @layer components {
9
+ .wello-notifications-toaster {
10
+ --wello-notifications-bg: rgb(255 255 255 / 0.95);
11
+ --wello-notifications-fg: #0f172a;
12
+ --wello-notifications-muted: #64748b;
13
+ --wello-notifications-border: rgb(226 232 240 / 0.7);
14
+ --wello-notifications-ring: rgb(0 0 0 / 0.05);
15
+ --wello-notifications-hover: rgb(0 0 0 / 0.05);
16
+ --wello-notifications-shadow: 0 8px 24px -12px rgb(0 0 0 / 0.22);
17
+ --wello-notifications-radius: 16px;
18
+ --wello-notifications-font: inherit;
19
+
20
+ position: fixed;
21
+ display: flex;
22
+ flex-direction: column;
23
+ box-sizing: border-box;
24
+ width: var(--wello-notifications-width, 390px);
25
+ max-width: calc(100vw - 2 * var(--wello-notifications-offset, 16px));
26
+ margin: 0;
27
+ padding: 0;
28
+ list-style: none;
29
+ pointer-events: none;
30
+ font-family: var(--wello-notifications-font);
31
+ color-scheme: light;
32
+ }
33
+
34
+ .dark .wello-notifications-toaster:not([data-theme="light"]),
35
+ [data-theme="dark"] .wello-notifications-toaster:not([data-theme="light"]),
36
+ .wello-notifications-toaster[data-theme="dark"] {
37
+ --wello-notifications-bg: rgb(15 23 42 / 0.92);
38
+ --wello-notifications-fg: #f1f5f9;
39
+ --wello-notifications-muted: #94a3b8;
40
+ --wello-notifications-border: rgb(255 255 255 / 0.1);
41
+ --wello-notifications-ring: rgb(255 255 255 / 0.06);
42
+ --wello-notifications-hover: rgb(255 255 255 / 0.1);
43
+ --wello-notifications-shadow: 0 8px 24px -12px rgb(0 0 0 / 0.45);
44
+ color-scheme: dark;
45
+ }
46
+
47
+ /* Positions. Items carry half the gap on each side, so the edges subtract it. */
48
+ .wello-notifications-toaster[data-y="top"] {
49
+ top: calc(var(--wello-notifications-offset, 16px) - var(--wello-notifications-gap, 12px) / 2);
50
+ }
51
+ .wello-notifications-toaster[data-y="bottom"] {
52
+ bottom: calc(
53
+ var(--wello-notifications-offset, 16px) - var(--wello-notifications-gap, 12px) / 2
54
+ );
55
+ /* Newest first in the list, so newest sits at the screen edge. */
56
+ flex-direction: column-reverse;
57
+ }
58
+ .wello-notifications-toaster[data-x="start"] {
59
+ inset-inline-start: var(--wello-notifications-offset, 16px);
60
+ }
61
+ .wello-notifications-toaster[data-x="end"] {
62
+ inset-inline-end: var(--wello-notifications-offset, 16px);
63
+ }
64
+ .wello-notifications-toaster[data-x="center"] {
65
+ left: 50%;
66
+ transform: translateX(-50%);
67
+ }
68
+
69
+ @media (max-width: 480px) {
70
+ .wello-notifications-toaster {
71
+ width: auto;
72
+ max-width: none;
73
+ inset-inline: var(--wello-notifications-offset, 16px);
74
+ transform: none;
75
+ }
76
+ .wello-notifications-toaster[data-x="center"] {
77
+ left: var(--wello-notifications-offset, 16px);
78
+ }
79
+ }
80
+
81
+ /* Each item collapses its own height when it leaves, so the others slide into place. */
82
+ .wello-notifications-item {
83
+ display: grid;
84
+ grid-template-rows: 1fr;
85
+ transition: grid-template-rows 200ms ease 110ms;
86
+ }
87
+ .wello-notifications-item-inner {
88
+ min-height: 0;
89
+ padding-block: calc(var(--wello-notifications-gap, 12px) / 2);
90
+ }
91
+ .wello-notifications-item[data-state="closing"] {
92
+ grid-template-rows: 0fr;
93
+ }
94
+ .wello-notifications-item[data-state="closing"] .wello-notifications-item-inner {
95
+ overflow: hidden;
96
+ }
97
+
98
+ .wello-notifications-toast,
99
+ .wello-notifications-custom {
100
+ pointer-events: auto;
101
+ touch-action: pan-y;
102
+ transform: translateX(var(--wello-notifications-swipe, 0px));
103
+ transition:
104
+ transform 200ms ease,
105
+ opacity 160ms ease,
106
+ scale 160ms ease;
107
+ animation: wello-notifications-in 260ms cubic-bezier(0.21, 1.02, 0.73, 1);
108
+ }
109
+ .wello-notifications-toaster[data-y="top"] .wello-notifications-toast,
110
+ .wello-notifications-toaster[data-y="top"] .wello-notifications-custom {
111
+ --wello-notifications-enter: -14px;
112
+ }
113
+ .wello-notifications-toast[data-swiping],
114
+ .wello-notifications-custom[data-swiping] {
115
+ transition: none;
116
+ user-select: none;
117
+ }
118
+ .wello-notifications-item[data-state="closing"] .wello-notifications-toast,
119
+ .wello-notifications-item[data-state="closing"] .wello-notifications-custom {
120
+ opacity: 0;
121
+ scale: 0.96;
122
+ }
123
+ .wello-notifications-item[data-swiped="end"] .wello-notifications-toast,
124
+ .wello-notifications-item[data-swiped="end"] .wello-notifications-custom {
125
+ transform: translateX(calc(100% + 32px));
126
+ }
127
+ .wello-notifications-item[data-swiped="start"] .wello-notifications-toast,
128
+ .wello-notifications-item[data-swiped="start"] .wello-notifications-custom {
129
+ transform: translateX(calc(-100% - 32px));
130
+ }
131
+
132
+ .wello-notifications-toast {
133
+ position: relative;
134
+ display: flex;
135
+ align-items: flex-start;
136
+ gap: 12px;
137
+ box-sizing: border-box;
138
+ width: 100%;
139
+ padding-block: 14px;
140
+ padding-inline: 14px 8px;
141
+ overflow: hidden;
142
+ border: 1px solid var(--wello-notifications-border);
143
+ border-radius: var(--wello-notifications-radius);
144
+ background: var(--wello-notifications-bg);
145
+ color: var(--wello-notifications-fg);
146
+ box-shadow:
147
+ var(--wello-notifications-shadow),
148
+ 0 0 0 1px var(--wello-notifications-ring);
149
+ backdrop-filter: blur(24px) saturate(1.5);
150
+ -webkit-backdrop-filter: blur(24px) saturate(1.5);
151
+ font-size: 14px;
152
+ line-height: 1.4;
153
+ text-align: start;
154
+ }
155
+
156
+ /* Accent bar on the leading edge */
157
+ .wello-notifications-toast::before {
158
+ content: "";
159
+ position: absolute;
160
+ inset-block: 0.55rem;
161
+ inset-inline-start: 0;
162
+ width: 3px;
163
+ border-radius: 999px;
164
+ background: var(--wello-notifications-tone);
165
+ }
166
+
167
+ .wello-notifications-icon {
168
+ display: flex;
169
+ flex: none;
170
+ align-items: center;
171
+ justify-content: center;
172
+ width: 40px;
173
+ height: 40px;
174
+ border-radius: var(--wello-notifications-radius);
175
+ color: var(--wello-notifications-tone);
176
+ background: color-mix(in oklab, var(--wello-notifications-tone) 16%, transparent);
177
+ box-shadow: inset 0 0 0 1px
178
+ color-mix(in oklab, var(--wello-notifications-tone) 28%, transparent);
179
+ font-size: 1.15rem;
180
+ }
181
+
182
+ .wello-notifications-content {
183
+ display: flex;
184
+ flex: 1;
185
+ flex-direction: column;
186
+ gap: 4px;
187
+ min-width: 0;
188
+ padding-block: 2px;
189
+ padding-inline-end: 8px;
190
+ overflow-wrap: anywhere;
191
+ }
192
+ /* Without an icon, line the text up with the bar. */
193
+ .wello-notifications-toast > .wello-notifications-content:first-child {
194
+ padding-inline-start: 2px;
195
+ }
196
+
197
+ .wello-notifications-title {
198
+ margin: 0;
199
+ font-weight: 600;
200
+ line-height: 1.35;
201
+ color: var(--wello-notifications-tone);
202
+ }
203
+ .wello-notifications-toast[data-type="default"] .wello-notifications-title,
204
+ .wello-notifications-toast[data-type="loading"] .wello-notifications-title {
205
+ color: var(--wello-notifications-fg);
206
+ }
207
+
208
+ .wello-notifications-description {
209
+ margin: 0;
210
+ color: var(--wello-notifications-muted);
211
+ line-height: 1.55;
212
+ }
213
+
214
+ .wello-notifications-actions {
215
+ display: flex;
216
+ flex-wrap: wrap;
217
+ gap: 8px;
218
+ margin-top: 6px;
219
+ }
220
+ .wello-notifications-button {
221
+ display: inline-flex;
222
+ align-items: center;
223
+ height: 28px;
224
+ padding-inline: 10px;
225
+ border: 1px solid transparent;
226
+ border-radius: 8px;
227
+ font: inherit;
228
+ font-size: 13px;
229
+ font-weight: 600;
230
+ cursor: pointer;
231
+ transition:
232
+ background-color 120ms ease,
233
+ filter 120ms ease;
234
+ }
235
+ .wello-notifications-action {
236
+ background: var(--wello-notifications-tone);
237
+ color: #fff;
238
+ }
239
+ .wello-notifications-toast[data-type="default"] .wello-notifications-action,
240
+ .wello-notifications-toast[data-type="loading"] .wello-notifications-action {
241
+ background: var(--wello-notifications-fg);
242
+ color: var(--wello-notifications-bg);
243
+ }
244
+ .wello-notifications-action:hover {
245
+ filter: brightness(1.08);
246
+ }
247
+ .wello-notifications-cancel {
248
+ background: transparent;
249
+ border-color: var(--wello-notifications-border);
250
+ color: var(--wello-notifications-fg);
251
+ }
252
+ .wello-notifications-cancel:hover {
253
+ background: var(--wello-notifications-hover);
254
+ }
255
+ .wello-notifications-button:focus-visible,
256
+ .wello-notifications-close:focus-visible {
257
+ outline: 2px solid var(--wello-notifications-tone);
258
+ outline-offset: 2px;
259
+ }
260
+
261
+ .wello-notifications-close {
262
+ display: flex;
263
+ flex: none;
264
+ align-items: center;
265
+ justify-content: center;
266
+ width: 28px;
267
+ height: 28px;
268
+ margin: -2px 0;
269
+ padding: 0;
270
+ border: 0;
271
+ border-radius: 10px;
272
+ background: transparent;
273
+ color: var(--wello-notifications-muted);
274
+ font-size: 16px;
275
+ cursor: pointer;
276
+ transition:
277
+ background-color 120ms ease,
278
+ color 120ms ease;
279
+ }
280
+ .wello-notifications-close:hover {
281
+ background: var(--wello-notifications-hover);
282
+ color: var(--wello-notifications-fg);
283
+ }
284
+
285
+ .wello-notifications-progress {
286
+ position: absolute;
287
+ inset-inline: 0;
288
+ bottom: 0;
289
+ height: 3px;
290
+ background: var(--wello-notifications-tone);
291
+ opacity: 0.45;
292
+ transform-origin: left;
293
+ animation-name: wello-notifications-progress;
294
+ animation-timing-function: linear;
295
+ animation-fill-mode: forwards;
296
+ }
297
+ [dir="rtl"] .wello-notifications-progress {
298
+ transform-origin: right;
299
+ }
300
+
301
+ .wello-notifications-spin {
302
+ animation: wello-notifications-spin 0.9s linear infinite;
303
+ }
304
+
305
+ @keyframes wello-notifications-in {
306
+ from {
307
+ opacity: 0;
308
+ translate: 0 var(--wello-notifications-enter, 14px);
309
+ scale: 0.96;
310
+ }
311
+ }
312
+ @keyframes wello-notifications-progress {
313
+ from {
314
+ transform: scaleX(1);
315
+ }
316
+ to {
317
+ transform: scaleX(0);
318
+ }
319
+ }
320
+ @keyframes wello-notifications-spin {
321
+ to {
322
+ transform: rotate(360deg);
323
+ }
324
+ }
325
+
326
+ @media (prefers-reduced-motion: reduce) {
327
+ .wello-notifications-toast,
328
+ .wello-notifications-custom,
329
+ .wello-notifications-item {
330
+ animation-duration: 1ms;
331
+ transition-duration: 1ms;
332
+ transition-delay: 0ms;
333
+ }
334
+ .wello-notifications-spin {
335
+ animation-duration: 2.5s;
336
+ }
337
+ }
338
+ }
package/package.json CHANGED
@@ -1,6 +1,73 @@
1
- {
2
- "name": "@wello-dev/notifications",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "@wello-dev/notifications",
3
+ "version": "1.0.0",
4
+ "description": "Toasts with a sonner-style API, tab title / favicon badges and notification sounds for React",
5
+ "homepage": "https://wello-dev.vercel.app/",
6
+ "author": "Mohamed Wael <mohamedwael4553@gmail.com>",
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "sideEffects": [
10
+ "**/*.css",
11
+ "./dist/index.js",
12
+ "./dist/index.cjs"
13
+ ],
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "import": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "require": {
24
+ "types": "./dist/index.d.cts",
25
+ "default": "./dist/index.cjs"
26
+ }
27
+ },
28
+ "./package.json": "./package.json",
29
+ "./styles.css": "./dist/styles.css"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsup && node -e \"require('fs').copyFileSync('src/styles.css','dist/styles.css')\"",
37
+ "dev": "tsup --watch",
38
+ "typecheck": "tsc --noEmit",
39
+ "test": "vitest run",
40
+ "test:watch": "vitest",
41
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
42
+ },
43
+ "keywords": [
44
+ "wello-dev",
45
+ "notifications",
46
+ "toast",
47
+ "toaster",
48
+ "sonner",
49
+ "react",
50
+ "rtl"
51
+ ],
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "repository": {
56
+ "url": "https://github.com/MohamedWael257/wello-dev",
57
+ "type": "git",
58
+ "directory": "packages/notifications"
59
+ },
60
+ "peerDependencies": {
61
+ "react": ">=18",
62
+ "react-dom": ">=18"
63
+ },
64
+ "devDependencies": {
65
+ "@testing-library/react": "^16.3.3",
66
+ "@types/react": "^19.3.0",
67
+ "@types/react-dom": "^19.3.0",
68
+ "happy-dom": "^21.0.4",
69
+ "react": "^19.3.1",
70
+ "react-dom": "^19.3.1",
71
+ "vitest": "^5.0.5"
72
+ }
73
+ }