@karakuri-ui/react 0.3.2 → 0.3.4
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.
- package/README.md +27 -4
- package/dist/components/ui/accordion.js +27 -24
- package/dist/components/ui/accordion.js.map +1 -1
- package/dist/components/ui/accordion.mjs +27 -24
- package/dist/components/ui/accordion.mjs.map +1 -1
- package/dist/components/ui/alert.js +45 -27
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/alert.mjs +45 -27
- package/dist/components/ui/alert.mjs.map +1 -1
- package/dist/components/ui/avatar.js +41 -32
- package/dist/components/ui/avatar.js.map +1 -1
- package/dist/components/ui/avatar.mjs +41 -32
- package/dist/components/ui/avatar.mjs.map +1 -1
- package/dist/components/ui/badge.js +46 -43
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/badge.mjs +46 -43
- package/dist/components/ui/badge.mjs.map +1 -1
- package/dist/components/ui/breadcrumb.js +30 -25
- package/dist/components/ui/breadcrumb.js.map +1 -1
- package/dist/components/ui/breadcrumb.mjs +30 -25
- package/dist/components/ui/breadcrumb.mjs.map +1 -1
- package/dist/components/ui/button-group.js +6 -5
- package/dist/components/ui/button-group.js.map +1 -1
- package/dist/components/ui/button-group.mjs +6 -5
- package/dist/components/ui/button-group.mjs.map +1 -1
- package/dist/components/ui/button.js +24 -14
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/button.mjs +24 -14
- package/dist/components/ui/button.mjs.map +1 -1
- package/dist/components/ui/card.js +53 -39
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/card.mjs +53 -39
- package/dist/components/ui/card.mjs.map +1 -1
- package/dist/components/ui/chart.d.mts +1 -1
- package/dist/components/ui/chart.d.ts +1 -1
- package/dist/components/ui/chart.js +154 -130
- package/dist/components/ui/chart.js.map +1 -1
- package/dist/components/ui/chart.mjs +154 -130
- package/dist/components/ui/chart.mjs.map +1 -1
- package/dist/components/ui/checkbox.js +47 -40
- package/dist/components/ui/checkbox.js.map +1 -1
- package/dist/components/ui/checkbox.mjs +47 -40
- package/dist/components/ui/checkbox.mjs.map +1 -1
- package/dist/components/ui/divider.js +16 -13
- package/dist/components/ui/divider.js.map +1 -1
- package/dist/components/ui/divider.mjs +16 -13
- package/dist/components/ui/divider.mjs.map +1 -1
- package/dist/components/ui/drawer.js +44 -35
- package/dist/components/ui/drawer.js.map +1 -1
- package/dist/components/ui/drawer.mjs +44 -35
- package/dist/components/ui/drawer.mjs.map +1 -1
- package/dist/components/ui/dropdown.js +31 -24
- package/dist/components/ui/dropdown.js.map +1 -1
- package/dist/components/ui/dropdown.mjs +31 -24
- package/dist/components/ui/dropdown.mjs.map +1 -1
- package/dist/components/ui/field.js +18 -15
- package/dist/components/ui/field.js.map +1 -1
- package/dist/components/ui/field.mjs +18 -15
- package/dist/components/ui/field.mjs.map +1 -1
- package/dist/components/ui/icon-button.js +17 -14
- package/dist/components/ui/icon-button.js.map +1 -1
- package/dist/components/ui/icon-button.mjs +17 -14
- package/dist/components/ui/icon-button.mjs.map +1 -1
- package/dist/components/ui/input.js +34 -29
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/input.mjs +34 -29
- package/dist/components/ui/input.mjs.map +1 -1
- package/dist/components/ui/metric-card.js +24 -21
- package/dist/components/ui/metric-card.js.map +1 -1
- package/dist/components/ui/metric-card.mjs +24 -21
- package/dist/components/ui/metric-card.mjs.map +1 -1
- package/dist/components/ui/modal.js +91 -74
- package/dist/components/ui/modal.js.map +1 -1
- package/dist/components/ui/modal.mjs +91 -74
- package/dist/components/ui/modal.mjs.map +1 -1
- package/dist/components/ui/navigation-menu.js +114 -93
- package/dist/components/ui/navigation-menu.js.map +1 -1
- package/dist/components/ui/navigation-menu.mjs +114 -93
- package/dist/components/ui/navigation-menu.mjs.map +1 -1
- package/dist/components/ui/pagination.js +66 -55
- package/dist/components/ui/pagination.js.map +1 -1
- package/dist/components/ui/pagination.mjs +66 -55
- package/dist/components/ui/pagination.mjs.map +1 -1
- package/dist/components/ui/popover.js +39 -36
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/popover.mjs +39 -36
- package/dist/components/ui/popover.mjs.map +1 -1
- package/dist/components/ui/progress.js +73 -64
- package/dist/components/ui/progress.js.map +1 -1
- package/dist/components/ui/progress.mjs +73 -64
- package/dist/components/ui/progress.mjs.map +1 -1
- package/dist/components/ui/radio-group.js +23 -19
- package/dist/components/ui/radio-group.js.map +1 -1
- package/dist/components/ui/radio-group.mjs +23 -19
- package/dist/components/ui/radio-group.mjs.map +1 -1
- package/dist/components/ui/segmented.js +7 -6
- package/dist/components/ui/segmented.js.map +1 -1
- package/dist/components/ui/segmented.mjs +7 -6
- package/dist/components/ui/segmented.mjs.map +1 -1
- package/dist/components/ui/select.js +55 -48
- package/dist/components/ui/select.js.map +1 -1
- package/dist/components/ui/select.mjs +55 -48
- package/dist/components/ui/select.mjs.map +1 -1
- package/dist/components/ui/skeleton.js +20 -19
- package/dist/components/ui/skeleton.js.map +1 -1
- package/dist/components/ui/skeleton.mjs +20 -19
- package/dist/components/ui/skeleton.mjs.map +1 -1
- package/dist/components/ui/slider.js +68 -58
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/slider.mjs +68 -58
- package/dist/components/ui/slider.mjs.map +1 -1
- package/dist/components/ui/spinner.js +185 -176
- package/dist/components/ui/spinner.js.map +1 -1
- package/dist/components/ui/spinner.mjs +185 -176
- package/dist/components/ui/spinner.mjs.map +1 -1
- package/dist/components/ui/switch.js +39 -28
- package/dist/components/ui/switch.js.map +1 -1
- package/dist/components/ui/switch.mjs +39 -28
- package/dist/components/ui/switch.mjs.map +1 -1
- package/dist/components/ui/table.js +26 -23
- package/dist/components/ui/table.js.map +1 -1
- package/dist/components/ui/table.mjs +26 -23
- package/dist/components/ui/table.mjs.map +1 -1
- package/dist/components/ui/tabs.js +25 -9
- package/dist/components/ui/tabs.js.map +1 -1
- package/dist/components/ui/tabs.mjs +25 -9
- package/dist/components/ui/tabs.mjs.map +1 -1
- package/dist/components/ui/textarea.js +2 -1
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/components/ui/textarea.mjs +2 -1
- package/dist/components/ui/textarea.mjs.map +1 -1
- package/dist/components/ui/toast.js +104 -80
- package/dist/components/ui/toast.js.map +1 -1
- package/dist/components/ui/toast.mjs +104 -80
- package/dist/components/ui/toast.mjs.map +1 -1
- package/dist/components/ui/toggle-group.js +9 -8
- package/dist/components/ui/toggle-group.js.map +1 -1
- package/dist/components/ui/toggle-group.mjs +9 -8
- package/dist/components/ui/toggle-group.mjs.map +1 -1
- package/dist/components/ui/toggle.js +3 -2
- package/dist/components/ui/toggle.js.map +1 -1
- package/dist/components/ui/toggle.mjs +3 -2
- package/dist/components/ui/toggle.mjs.map +1 -1
- package/dist/components/ui/tooltip.js +18 -15
- package/dist/components/ui/tooltip.js.map +1 -1
- package/dist/components/ui/tooltip.mjs +18 -15
- package/dist/components/ui/tooltip.mjs.map +1 -1
- package/package.json +27 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\nconst textareaVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border-form hover:border-border-form-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n compact: 'px-3 py-2 text-md', // 12px padding / 14px font - compact spaces\n default: 'px-4 py-3 text-base', // 16px padding / 16px font - standard\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-3xl', // rounded-full looks unnatural on textarea, using 3xl instead\n },\n resize: {\n none: 'resize-none',\n vertical: 'resize-y',\n horizontal: 'resize-x',\n both: 'resize',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-form-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n resize: 'vertical',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface TextareaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n VariantProps<typeof textareaVariants> {\n error?: boolean\n focusRing?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, variant, size, radius, resize, state, error, focusRing, id, rows = 4, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const textareaId = id ?? fieldContext?.id\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLTextAreaElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n return (\n <textarea\n id={textareaId}\n rows={rows}\n className={cn(\n textareaVariants({ variant, size, radius, resize, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n onPointerDown={handlePointerDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = 'Textarea'\n\nexport { Textarea, textareaVariants }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\nconst textareaVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border-form hover:border-border-form-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n compact: 'px-3 py-2 text-md', // 12px padding / 14px font - compact spaces\n default: 'px-4 py-3 text-base', // 16px padding / 16px font - standard\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-3xl', // rounded-full looks unnatural on textarea, using 3xl instead\n },\n resize: {\n none: 'resize-none',\n vertical: 'resize-y',\n horizontal: 'resize-x',\n both: 'resize',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-form-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n resize: 'vertical',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface TextareaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n VariantProps<typeof textareaVariants> {\n error?: boolean\n focusRing?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, variant, size, radius, resize, state, error, focusRing, id, rows = 4, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const textareaId = id ?? fieldContext?.id\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLTextAreaElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n return (\n <textarea\n id={textareaId}\n rows={rows}\n className={cn(\n textareaVariants({ variant, size, radius, resize, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n onPointerDown={handlePointerDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = 'Textarea'\n\nexport { Textarea, textareaVariants }\n"],"mappings":"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","names":["onBlur","onFocus"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { cva } from "class-variance-authority";
|
|
4
5
|
import { cn } from "../../lib/utils";
|
|
@@ -116,7 +117,7 @@ const Textarea = React.forwardRef(
|
|
|
116
117
|
const ariaDescribedBy = fieldContext ? [
|
|
117
118
|
resolvedError ? `${fieldContext.id}-error` : null
|
|
118
119
|
].filter(Boolean).join(" ") || void 0 : void 0;
|
|
119
|
-
return /* @__PURE__ */
|
|
120
|
+
return /* @__PURE__ */ jsx(
|
|
120
121
|
"textarea",
|
|
121
122
|
{
|
|
122
123
|
id: textareaId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\nconst textareaVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border-form hover:border-border-form-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n compact: 'px-3 py-2 text-md', // 12px padding / 14px font - compact spaces\n default: 'px-4 py-3 text-base', // 16px padding / 16px font - standard\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-3xl', // rounded-full looks unnatural on textarea, using 3xl instead\n },\n resize: {\n none: 'resize-none',\n vertical: 'resize-y',\n horizontal: 'resize-x',\n both: 'resize',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-form-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n resize: 'vertical',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface TextareaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n VariantProps<typeof textareaVariants> {\n error?: boolean\n focusRing?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, variant, size, radius, resize, state, error, focusRing, id, rows = 4, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const textareaId = id ?? fieldContext?.id\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLTextAreaElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n return (\n <textarea\n id={textareaId}\n rows={rows}\n className={cn(\n textareaVariants({ variant, size, radius, resize, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n onPointerDown={handlePointerDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = 'Textarea'\n\nexport { Textarea, textareaVariants }\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\nconst textareaVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border-form hover:border-border-form-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n compact: 'px-3 py-2 text-md', // 12px padding / 14px font - compact spaces\n default: 'px-4 py-3 text-base', // 16px padding / 16px font - standard\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-3xl', // rounded-full looks unnatural on textarea, using 3xl instead\n },\n resize: {\n none: 'resize-none',\n vertical: 'resize-y',\n horizontal: 'resize-x',\n both: 'resize',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-form-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n resize: 'vertical',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface TextareaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n VariantProps<typeof textareaVariants> {\n error?: boolean\n focusRing?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, variant, size, radius, resize, state, error, focusRing, id, rows = 4, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const textareaId = id ?? fieldContext?.id\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLTextAreaElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n return (\n <textarea\n id={textareaId}\n rows={rows}\n className={cn(\n textareaVariants({ variant, size, radius, resize, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n onPointerDown={handlePointerDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = 'Textarea'\n\nexport { Textarea, textareaVariants }\n"],"mappings":"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","names":["onBlur","onFocus"]}
|
|
@@ -34,15 +34,31 @@ __export(toast_exports, {
|
|
|
34
34
|
toastVariants: () => toastVariants
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(toast_exports);
|
|
37
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
37
38
|
var React = __toESM(require("react"));
|
|
38
39
|
var import_class_variance_authority = require("class-variance-authority");
|
|
39
40
|
var import_utils = require("../../lib/utils");
|
|
40
|
-
const InfoIcon = ({ className }) => /* @__PURE__ */
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
41
|
+
const InfoIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
43
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 16v-4" }),
|
|
44
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 8h.01" })
|
|
45
|
+
] });
|
|
46
|
+
const SuccessIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9 12 2 2 4-4" })
|
|
49
|
+
] });
|
|
50
|
+
const WarningIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
51
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
|
|
52
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 9v4" }),
|
|
53
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 17h.01" })
|
|
54
|
+
] });
|
|
55
|
+
const ErrorIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
56
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
57
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 8v5" }),
|
|
58
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 16h.01" })
|
|
59
|
+
] });
|
|
60
|
+
const DefaultCloseIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) });
|
|
61
|
+
const LoadingIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className: (0, import_utils.cn)("animate-spin", className), viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) });
|
|
46
62
|
const STATUS_ICONS = {
|
|
47
63
|
default: InfoIcon,
|
|
48
64
|
success: SuccessIcon,
|
|
@@ -289,7 +305,7 @@ const ToastItem = React.memo(function ToastItem2({
|
|
|
289
305
|
}
|
|
290
306
|
}
|
|
291
307
|
}, [data._promiseState, data.duration, defaultDuration, handleAutoClose]);
|
|
292
|
-
return /* @__PURE__ */
|
|
308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
293
309
|
"div",
|
|
294
310
|
{
|
|
295
311
|
role,
|
|
@@ -303,43 +319,51 @@ const ToastItem = React.memo(function ToastItem2({
|
|
|
303
319
|
data.className
|
|
304
320
|
),
|
|
305
321
|
onMouseEnter: handleMouseEnter,
|
|
306
|
-
onMouseLeave: handleMouseLeave
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
322
|
+
onMouseLeave: handleMouseLeave,
|
|
323
|
+
children: [
|
|
324
|
+
data.icon !== void 0 ? data.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "shrink-0", children: data.icon }) : data.type !== "default" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, { className: "icon-sm" }) }),
|
|
325
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "font-semibold", children: data.message }),
|
|
327
|
+
data.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_utils.cn)("mt-1 opacity-80", size === "sm" ? "text-xs" : "text-sm"), children: data.description })
|
|
328
|
+
] }),
|
|
329
|
+
(data.action || data.cancel) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5 shrink-0", children: [
|
|
330
|
+
data.cancel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
331
|
+
"button",
|
|
332
|
+
{
|
|
333
|
+
type: "button",
|
|
334
|
+
className: "px-2.5 py-1.5 text-xs font-semibold rounded-md opacity-70 hover:opacity-100 transition-opacity",
|
|
335
|
+
onClick: () => {
|
|
336
|
+
data.cancel.onClick();
|
|
337
|
+
handleDismiss();
|
|
338
|
+
},
|
|
339
|
+
children: data.cancel.label
|
|
340
|
+
}
|
|
341
|
+
),
|
|
342
|
+
data.action && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
343
|
+
"button",
|
|
344
|
+
{
|
|
345
|
+
type: "button",
|
|
346
|
+
className: "px-2.5 py-1.5 text-xs font-semibold rounded-md bg-foreground/5 hover:bg-foreground/15 transition-colors",
|
|
347
|
+
onClick: () => {
|
|
348
|
+
data.action.onClick();
|
|
349
|
+
handleDismiss();
|
|
350
|
+
},
|
|
351
|
+
children: data.action.label
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
] }),
|
|
355
|
+
showClose && dismissible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
356
|
+
"button",
|
|
357
|
+
{
|
|
358
|
+
type: "button",
|
|
359
|
+
className: "shrink-0 rounded-md p-1 opacity-70 hover:opacity-100 transition-opacity focus-visible:focus-ring",
|
|
360
|
+
onClick: handleDismiss,
|
|
361
|
+
"aria-label": "Close",
|
|
362
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultCloseIcon, { className: "icon-sm" })
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
]
|
|
366
|
+
}
|
|
343
367
|
);
|
|
344
368
|
});
|
|
345
369
|
function Toaster({
|
|
@@ -369,7 +393,7 @@ function Toaster({
|
|
|
369
393
|
isTop ? "top-0" : "bottom-0",
|
|
370
394
|
isCenter ? "left-1/2 -translate-x-1/2" : isRight ? "right-0" : "left-0"
|
|
371
395
|
);
|
|
372
|
-
return /* @__PURE__ */
|
|
396
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
373
397
|
"section",
|
|
374
398
|
{
|
|
375
399
|
"aria-label": "Notifications",
|
|
@@ -381,42 +405,42 @@ function Toaster({
|
|
|
381
405
|
maxWidth: isCenter ? `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)` : void 0
|
|
382
406
|
},
|
|
383
407
|
onMouseEnter: () => setExpanded(true),
|
|
384
|
-
onMouseLeave: () => setExpanded(false)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"div",
|
|
390
|
-
{
|
|
391
|
-
key: t.id,
|
|
392
|
-
className: "transition-[transform,opacity] duration-normal ease-out",
|
|
393
|
-
style: {
|
|
394
|
-
width: TOAST_WIDTH,
|
|
395
|
-
maxWidth: `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)`,
|
|
396
|
-
...isStacked ? {
|
|
397
|
-
position: "absolute",
|
|
398
|
-
...isTop ? { top: offset + index * TOAST_STACK_OFFSET } : { bottom: offset + index * TOAST_STACK_OFFSET },
|
|
399
|
-
...isCenter ? { left: "50%", transform: `translateX(-50%) scale(${1 - index * TOAST_STACK_SCALE_STEP})` } : isRight ? { right: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` } : { left: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` },
|
|
400
|
-
opacity: index < TOAST_STACK_VISIBLE_LAYERS ? 1 - index * TOAST_STACK_OPACITY_STEP : 0,
|
|
401
|
-
zIndex: visibleToasts - index,
|
|
402
|
-
pointerEvents: "none"
|
|
403
|
-
} : { zIndex: visibleToasts - index }
|
|
404
|
-
}
|
|
405
|
-
},
|
|
406
|
-
/* @__PURE__ */ React.createElement(
|
|
407
|
-
ToastItem,
|
|
408
|
+
onMouseLeave: () => setExpanded(false),
|
|
409
|
+
children: visible.map((t, index) => {
|
|
410
|
+
const isStacked = !expand && !expanded && index > 0;
|
|
411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
412
|
+
"div",
|
|
408
413
|
{
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
414
|
+
className: "transition-[transform,opacity] duration-normal ease-out",
|
|
415
|
+
style: {
|
|
416
|
+
width: TOAST_WIDTH,
|
|
417
|
+
maxWidth: `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)`,
|
|
418
|
+
...isStacked ? {
|
|
419
|
+
position: "absolute",
|
|
420
|
+
...isTop ? { top: offset + index * TOAST_STACK_OFFSET } : { bottom: offset + index * TOAST_STACK_OFFSET },
|
|
421
|
+
...isCenter ? { left: "50%", transform: `translateX(-50%) scale(${1 - index * TOAST_STACK_SCALE_STEP})` } : isRight ? { right: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` } : { left: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` },
|
|
422
|
+
opacity: index < TOAST_STACK_VISIBLE_LAYERS ? 1 - index * TOAST_STACK_OPACITY_STEP : 0,
|
|
423
|
+
zIndex: visibleToasts - index,
|
|
424
|
+
pointerEvents: "none"
|
|
425
|
+
} : { zIndex: visibleToasts - index }
|
|
426
|
+
},
|
|
427
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
428
|
+
ToastItem,
|
|
429
|
+
{
|
|
430
|
+
data: t,
|
|
431
|
+
position,
|
|
432
|
+
size,
|
|
433
|
+
closeButton,
|
|
434
|
+
richColors,
|
|
435
|
+
defaultDuration: duration,
|
|
436
|
+
onRemove: handleRemove
|
|
437
|
+
}
|
|
438
|
+
)
|
|
439
|
+
},
|
|
440
|
+
t.id
|
|
441
|
+
);
|
|
442
|
+
})
|
|
443
|
+
}
|
|
420
444
|
);
|
|
421
445
|
}
|
|
422
446
|
Toaster.displayName = "Toaster";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/toast.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ─── Built-in status icons (shared with Alert — no external dependency) ──────\n// All icons: Lucide-compatible 24×24 viewBox, strokeWidth=2, rounded caps/joins\nconst InfoIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n)\n\nconst SuccessIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m9 12 2 2 4-4\" />\n </svg>\n)\n\nconst WarningIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n)\n\nconst ErrorIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v5\" />\n <path d=\"M12 16h.01\" />\n </svg>\n)\n\nconst DefaultCloseIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n)\n\nconst LoadingIcon = ({ className }: { className?: string }) => (\n <svg className={cn('animate-spin', className)} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" strokeLinecap=\"round\" />\n </svg>\n)\n\n// ─── Status icon mapping ─────────────────────────────────────────\nconst STATUS_ICONS: Record<ToastType, React.FC<{ className?: string }>> = {\n default: InfoIcon,\n success: SuccessIcon,\n warning: WarningIcon,\n error: ErrorIcon,\n info: InfoIcon,\n loading: LoadingIcon,\n}\n\n// ─── Color × Type class mapping ─────────────────────────────────\nconst colorMap: Record<ToastType, string> = {\n default: 'bg-background-paper text-foreground border-border shadow-lg',\n success: 'bg-success-tint text-text-success border-success/20 shadow-lg',\n error: 'bg-error-tint text-text-error border-error/20 shadow-lg',\n warning: 'bg-warning-tint text-text-warning border-warning/20 shadow-lg',\n info: 'bg-info-tint text-text-info border-info/20 shadow-lg',\n loading: 'bg-background-paper text-foreground border-border shadow-lg',\n}\n\nconst richColorMap: Record<ToastType, string> = {\n default: 'bg-foreground text-background border-transparent shadow-lg',\n success: 'bg-success text-success-foreground border-transparent shadow-lg',\n error: 'bg-error text-error-foreground border-transparent shadow-lg',\n warning: 'bg-warning text-warning-foreground border-transparent shadow-lg',\n info: 'bg-info text-info-foreground border-transparent shadow-lg',\n loading: 'bg-foreground text-background border-transparent shadow-lg',\n}\n\n// ─── Constants (JS cannot read CSS variables at runtime) ─────────\nconst TOAST_EXIT_DURATION = 200 // --duration-normal (200ms)\nconst TOAST_MIN_RESUME_MS = 500 // --duration-slowest (500ms) — minimum time after hover resume\nconst TOAST_WIDTH = 360 // fixed toast width — smallest mobile viewport baseline\nconst TOAST_VIEWPORT_MARGIN = 48 // 2 × offset default (24px) — viewport safe area\nconst TOAST_STACK_OFFSET = 8 // --spacing-2 (8px) — vertical gap between stacked toasts\nconst TOAST_STACK_SCALE_STEP = 0.05 // scale reduction per stack level (0.95, 0.90, ...)\nconst TOAST_STACK_OPACITY_STEP = 0.15 // opacity reduction per stack level (0.85, 0.70, ...)\nconst TOAST_STACK_VISIBLE_LAYERS = 3 // max visible stacked layers before hidden\n\n// ─── Toast variants (CVA) ────────────────────────────────────────\nconst toastVariants = cva(\n 'group pointer-events-auto relative flex items-center gap-2.5 border w-full overflow-hidden transition-all',\n {\n variants: {\n size: {\n sm: 'p-3 text-sm rounded-md',\n default: 'p-4 text-md rounded-lg',\n lg: 'p-5 text-md rounded-lg',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\n// ─── Types ───────────────────────────────────────────────────────\nexport type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading'\nexport type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\nexport type ToastSize = 'sm' | 'default' | 'lg'\n\nexport interface ToastAction {\n label: string\n onClick: () => void\n}\n\nexport interface ToastData {\n id: string\n type: ToastType\n message: React.ReactNode\n description?: React.ReactNode\n duration?: number\n dismissible?: boolean\n closeButton?: boolean\n icon?: React.ReactNode\n action?: ToastAction\n cancel?: ToastAction\n onDismiss?: (toast: ToastData) => void\n onAutoClose?: (toast: ToastData) => void\n className?: string\n /** Promise state — managed internally */\n _promiseState?: 'loading' | 'success' | 'error'\n}\n\n// ─── Global toast store ──────────────────────────────────────────\ntype ToastListener = () => void\n\ninterface ToastStore {\n toasts: ToastData[]\n listeners: Set<ToastListener>\n addToast: (toast: ToastData) => void\n removeToast: (id: string) => void\n updateToast: (id: string, updates: Partial<ToastData>) => void\n removeAll: () => void\n subscribe: (listener: ToastListener) => () => void\n}\n\nfunction createToastStore(): ToastStore {\n const store: ToastStore = {\n toasts: [],\n listeners: new Set(),\n addToast(toast) {\n store.toasts = [toast, ...store.toasts]\n store.listeners.forEach((l) => l())\n },\n removeToast(id) {\n store.toasts = store.toasts.filter((t) => t.id !== id)\n store.listeners.forEach((l) => l())\n },\n updateToast(id, updates) {\n store.toasts = store.toasts.map((t) => (t.id === id ? { ...t, ...updates } : t))\n store.listeners.forEach((l) => l())\n },\n removeAll() {\n store.toasts = []\n store.listeners.forEach((l) => l())\n },\n subscribe(listener) {\n store.listeners.add(listener)\n return () => { store.listeners.delete(listener) }\n },\n }\n return store\n}\n\nconst globalStore = createToastStore()\n\nfunction useToastStore() {\n const [, forceUpdate] = React.useState(0)\n React.useEffect(() => {\n return globalStore.subscribe(() => forceUpdate((n) => n + 1))\n }, [])\n return globalStore.toasts\n}\n\n// ─── Toast ID generator ─────────────────────────────────────────\nlet toastCounter = 0\nfunction genId() {\n toastCounter += 1\n return `toast-${toastCounter}-${Date.now()}`\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// Imperative API: toast()\n// ═══════════════════════════════════════════════════════════════════\n\ninterface ToastOptions {\n id?: string\n description?: React.ReactNode\n duration?: number\n dismissible?: boolean\n closeButton?: boolean\n icon?: React.ReactNode\n action?: ToastAction\n cancel?: ToastAction\n onDismiss?: (toast: ToastData) => void\n onAutoClose?: (toast: ToastData) => void\n className?: string\n}\n\ninterface PromiseOptions<T> {\n loading: React.ReactNode\n success: React.ReactNode | ((data: T) => React.ReactNode)\n error: React.ReactNode | ((err: unknown) => React.ReactNode)\n finally?: () => void\n description?: {\n loading?: React.ReactNode\n success?: React.ReactNode | ((data: T) => React.ReactNode)\n error?: React.ReactNode | ((err: unknown) => React.ReactNode)\n }\n}\n\nfunction createToast(message: React.ReactNode, type: ToastType, opts?: ToastOptions): string {\n const id = opts?.id ?? genId()\n\n // If updating existing toast, just update\n const existing = globalStore.toasts.find((t) => t.id === id)\n if (existing) {\n globalStore.updateToast(id, { message, type, ...opts })\n return id\n }\n\n globalStore.addToast({\n id,\n type,\n message,\n description: opts?.description,\n duration: opts?.duration,\n dismissible: opts?.dismissible,\n closeButton: opts?.closeButton,\n icon: opts?.icon,\n action: opts?.action,\n cancel: opts?.cancel,\n onDismiss: opts?.onDismiss,\n onAutoClose: opts?.onAutoClose,\n className: opts?.className,\n })\n return id\n}\n\nfunction toast(message: React.ReactNode, opts?: ToastOptions): string {\n return createToast(message, 'default', opts)\n}\n\ntoast.success = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'success', opts)\n\ntoast.error = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'error', opts)\n\ntoast.warning = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'warning', opts)\n\ntoast.info = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'info', opts)\n\ntoast.loading = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'loading', { ...opts, duration: 0 })\n\ntoast.promise = <T,>(\n promise: Promise<T>,\n opts: PromiseOptions<T>,\n toastOpts?: ToastOptions\n): Promise<T> => {\n const id = createToast(opts.loading, 'loading', {\n ...toastOpts,\n duration: 0,\n })\n\n promise\n .then((data) => {\n const msg = typeof opts.success === 'function' ? opts.success(data) : opts.success\n const desc = typeof opts.description?.success === 'function'\n ? opts.description.success(data)\n : opts.description?.success\n globalStore.updateToast(id, {\n type: 'success',\n message: msg,\n description: desc,\n duration: toastOpts?.duration,\n _promiseState: 'success',\n })\n })\n .catch((err) => {\n const msg = typeof opts.error === 'function' ? opts.error(err) : opts.error\n const desc = typeof opts.description?.error === 'function'\n ? opts.description.error(err)\n : opts.description?.error\n globalStore.updateToast(id, {\n type: 'error',\n message: msg,\n description: desc,\n duration: toastOpts?.duration,\n _promiseState: 'error',\n })\n })\n .finally(() => {\n opts.finally?.()\n })\n\n return promise\n}\n\ntoast.dismiss = (id?: string) => {\n if (id) {\n globalStore.removeToast(id)\n } else {\n globalStore.removeAll()\n }\n}\n\ntoast.custom = (render: (t: ToastData) => React.ReactNode, opts?: ToastOptions): string => {\n const id = opts?.id ?? genId()\n globalStore.addToast({\n id,\n type: 'default',\n message: render as unknown as React.ReactNode,\n duration: opts?.duration,\n dismissible: opts?.dismissible,\n className: opts?.className,\n onDismiss: opts?.onDismiss,\n onAutoClose: opts?.onAutoClose,\n _promiseState: undefined,\n })\n return id\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// ToastItem — individual toast renderer\n// ═══════════════════════════════════════════════════════════════════\n\ninterface ToastItemProps {\n data: ToastData\n position: ToastPosition\n size: ToastSize\n closeButton: boolean\n richColors: boolean\n defaultDuration: number\n onRemove: (id: string) => void\n}\n\nconst ToastItem = React.memo(function ToastItem({\n data,\n position,\n size,\n closeButton: globalCloseButton,\n richColors,\n defaultDuration,\n onRemove,\n}: ToastItemProps) {\n const [isExiting, setIsExiting] = React.useState(false)\n const [isEntered, setIsEntered] = React.useState(false)\n const [isPaused, setIsPaused] = React.useState(false)\n const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n const remainingRef = React.useRef<number>(0)\n const startTimeRef = React.useRef<number>(0)\n\n // Enter animation — play once on mount, then remove class\n React.useEffect(() => {\n const timer = setTimeout(() => setIsEntered(true), TOAST_EXIT_DURATION)\n return () => clearTimeout(timer)\n }, [])\n\n const showClose = data.closeButton ?? globalCloseButton\n const dismissible = data.dismissible !== false\n const duration = data.type === 'loading' ? 0 : (data.duration ?? defaultDuration)\n\n // ARIA — error/warning use assertive, others polite\n const role = data.type === 'error' || data.type === 'warning' ? 'alert' : 'status'\n const ariaLive = data.type === 'error' || data.type === 'warning' ? 'assertive' : 'polite'\n\n const colors = richColors ? richColorMap[data.type] : colorMap[data.type]\n const StatusIcon = STATUS_ICONS[data.type]\n\n // Animation classes based on position\n const enterAnim = position.includes('right')\n ? 'animate-toast-slide-in-right'\n : position.includes('left')\n ? 'animate-toast-slide-in-left'\n : position.includes('top')\n ? 'animate-toast-slide-in-top'\n : 'animate-toast-slide-in-bottom'\n\n const exitAnim = position.includes('right')\n ? 'animate-toast-slide-out-right'\n : position.includes('left')\n ? 'animate-toast-slide-out-left'\n : position.includes('top')\n ? 'animate-toast-slide-out-top'\n : 'animate-toast-slide-out-bottom'\n\n const handleDismiss = React.useCallback(() => {\n if (!dismissible) return\n setIsExiting(true)\n data.onDismiss?.(data)\n // Wait for exit animation then remove\n setTimeout(() => onRemove(data.id), TOAST_EXIT_DURATION)\n }, [data, dismissible, onRemove])\n\n const handleAutoClose = React.useCallback(() => {\n setIsExiting(true)\n data.onAutoClose?.(data)\n setTimeout(() => onRemove(data.id), TOAST_EXIT_DURATION)\n }, [data, onRemove])\n\n // Auto-dismiss timer with pause support\n React.useEffect(() => {\n if (duration <= 0) return\n\n remainingRef.current = duration\n startTimeRef.current = Date.now()\n\n timerRef.current = setTimeout(handleAutoClose, duration)\n\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current)\n }\n }, [duration, handleAutoClose])\n\n // Pause/resume on hover\n const handleMouseEnter = React.useCallback(() => {\n if (duration <= 0) return\n setIsPaused(true)\n if (timerRef.current) {\n clearTimeout(timerRef.current)\n remainingRef.current -= Date.now() - startTimeRef.current\n }\n }, [duration])\n\n const handleMouseLeave = React.useCallback(() => {\n if (duration <= 0) return\n setIsPaused(false)\n startTimeRef.current = Date.now()\n timerRef.current = setTimeout(handleAutoClose, Math.max(remainingRef.current, TOAST_MIN_RESUME_MS))\n }, [duration, handleAutoClose])\n\n // Reset timer when toast updates (promise resolve)\n React.useEffect(() => {\n if (data._promiseState === 'success' || data._promiseState === 'error') {\n const newDuration = data.duration ?? defaultDuration\n if (newDuration > 0) {\n if (timerRef.current) clearTimeout(timerRef.current)\n remainingRef.current = newDuration\n startTimeRef.current = Date.now()\n timerRef.current = setTimeout(handleAutoClose, newDuration)\n }\n }\n }, [data._promiseState, data.duration, defaultDuration, handleAutoClose])\n\n return (\n <div\n role={role}\n aria-live={ariaLive}\n aria-atomic=\"true\"\n className={cn(\n toastVariants({ size }),\n colors,\n isExiting ? exitAnim : !isEntered ? enterAnim : undefined,\n isExiting && 'pointer-events-none',\n data.className,\n )}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n {/* Icon */}\n {data.icon !== undefined ? (\n data.icon && <span className=\"shrink-0\">{data.icon}</span>\n ) : (\n data.type !== 'default' && (\n <span className=\"shrink-0\">\n <StatusIcon className=\"icon-sm\" />\n </span>\n )\n )}\n\n {/* Content */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-semibold\">{data.message}</div>\n {data.description && (\n <div className={cn('mt-1 opacity-80', size === 'sm' ? 'text-xs' : 'text-sm')}>\n {data.description}\n </div>\n )}\n </div>\n\n {/* Actions */}\n {(data.action || data.cancel) && (\n <div className=\"flex items-center gap-1.5 shrink-0\">\n {data.cancel && (\n <button\n type=\"button\"\n className=\"px-2.5 py-1.5 text-xs font-semibold rounded-md opacity-70 hover:opacity-100 transition-opacity\"\n onClick={() => {\n data.cancel!.onClick()\n handleDismiss()\n }}\n >\n {data.cancel.label}\n </button>\n )}\n {data.action && (\n <button\n type=\"button\"\n className=\"px-2.5 py-1.5 text-xs font-semibold rounded-md bg-foreground/5 hover:bg-foreground/15 transition-colors\"\n onClick={() => {\n data.action!.onClick()\n handleDismiss()\n }}\n >\n {data.action.label}\n </button>\n )}\n </div>\n )}\n\n {/* Close button */}\n {showClose && dismissible && (\n <button\n type=\"button\"\n className=\"shrink-0 rounded-md p-1 opacity-70 hover:opacity-100 transition-opacity focus-visible:focus-ring\"\n onClick={handleDismiss}\n aria-label=\"Close\"\n >\n <DefaultCloseIcon className=\"icon-sm\" />\n </button>\n )}\n\n </div>\n )\n})\n\n// ═══════════════════════════════════════════════════════════════════\n// Toaster — renders all toasts\n// ═══════════════════════════════════════════════════════════════════\n\nexport interface ToasterProps {\n /** Position on screen */\n position?: ToastPosition\n /** Default auto-dismiss duration in ms (0 = persistent) */\n duration?: number\n /** Max visible toasts */\n visibleToasts?: number\n /** Show close button on all toasts */\n closeButton?: boolean\n /** Use rich (filled) colors for status toasts — default: true */\n richColors?: boolean\n /** Expand all toasts (no stacking) */\n expand?: boolean\n /** Offset from screen edge in px */\n offset?: number\n /** Gap between toasts in px */\n gap?: number\n /** Toast size */\n size?: ToastSize\n /** Additional className for container */\n className?: string\n}\n\nfunction Toaster({\n position = 'bottom-right',\n duration = 4000,\n visibleToasts = 5,\n closeButton = false,\n richColors = true,\n expand = false,\n offset = 24,\n gap = 8,\n size = 'default',\n className,\n}: ToasterProps) {\n const toasts = useToastStore()\n const [expanded, setExpanded] = React.useState(false)\n\n const handleRemove = React.useCallback((id: string) => {\n globalStore.removeToast(id)\n }, [])\n\n const visible = toasts.slice(0, visibleToasts)\n\n const isTop = position.startsWith('top')\n const isCenter = position.includes('center')\n const isRight = position.includes('right')\n const isLeft = position.includes('left')\n\n // Position styles\n const positionClasses = cn(\n 'fixed z-toast flex flex-col pointer-events-none',\n isTop ? 'top-0' : 'bottom-0',\n isCenter ? 'left-1/2 -translate-x-1/2' : isRight ? 'right-0' : 'left-0',\n )\n\n return (\n <section\n aria-label=\"Notifications\"\n className={cn(positionClasses, className)}\n style={{\n padding: offset,\n gap,\n width: isCenter ? 'auto' : undefined,\n maxWidth: isCenter ? `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)` : undefined,\n }}\n onMouseEnter={() => setExpanded(true)}\n onMouseLeave={() => setExpanded(false)}\n >\n {visible.map((t, index) => {\n const isStacked = !expand && !expanded && index > 0\n return (\n <div\n key={t.id}\n className=\"transition-[transform,opacity] duration-normal ease-out\"\n style={{\n width: TOAST_WIDTH,\n maxWidth: `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)`,\n ...(isStacked\n ? {\n position: 'absolute' as const,\n ...(isTop ? { top: offset + index * TOAST_STACK_OFFSET } : { bottom: offset + index * TOAST_STACK_OFFSET }),\n ...(isCenter\n ? { left: '50%', transform: `translateX(-50%) scale(${1 - index * TOAST_STACK_SCALE_STEP})` }\n : isRight\n ? { right: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` }\n : { left: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` }),\n opacity: index < TOAST_STACK_VISIBLE_LAYERS ? 1 - index * TOAST_STACK_OPACITY_STEP : 0,\n zIndex: visibleToasts - index,\n pointerEvents: 'none' as const,\n }\n : { zIndex: visibleToasts - index }),\n }}\n >\n <ToastItem\n data={t}\n position={position}\n size={size}\n closeButton={closeButton}\n richColors={richColors}\n defaultDuration={duration}\n onRemove={handleRemove}\n />\n </div>\n )\n })}\n </section>\n )\n}\nToaster.displayName = 'Toaster'\n\n// ─── Exports ─────────────────────────────────────────────────────\nexport {\n toast,\n Toaster,\n toastVariants,\n}\n\nexport type {\n ToastOptions,\n PromiseOptions,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,YAAuB;AACvB,sCAAuC;AACvC,mBAAmB;AAInB,MAAM,WAAW,CAAC,EAAE,UAAU,MAC5B,oCAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,eAAc,SAAQ,gBAAe,SAAQ,eAAY,UACxJ,oCAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,GAC/B,oCAAC,UAAK,GAAE,aAAY,GACpB,oCAAC,UAAK,GAAE,aAAY,CACtB;AAGF,MAAM,cAAc,CAAC,EAAE,UAAU,MAC/B,oCAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,eAAc,SAAQ,gBAAe,SAAQ,eAAY,UACxJ,oCAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,GAC/B,oCAAC,UAAK,GAAE,iBAAgB,CAC1B;AAGF,MAAM,cAAc,CAAC,EAAE,UAAU,MAC/B,oCAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,eAAc,SAAQ,gBAAe,SAAQ,eAAY,UACxJ,oCAAC,UAAK,GAAE,4EAA2E,GACnF,oCAAC,UAAK,GAAE,WAAU,GAClB,oCAAC,UAAK,GAAE,cAAa,CACvB;AAGF,MAAM,YAAY,CAAC,EAAE,UAAU,MAC7B,oCAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,eAAc,SAAQ,gBAAe,SAAQ,eAAY,UACxJ,oCAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,GAC/B,oCAAC,UAAK,GAAE,WAAU,GAClB,oCAAC,UAAK,GAAE,cAAa,CACvB;AAGF,MAAM,mBAAmB,CAAC,EAAE,UAAU,MACpC,oCAAC,SAAI,WAAsB,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAAG,eAAY,UAC3G,oCAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,wBAAuB,CAC9E;AAGF,MAAM,cAAc,CAAC,EAAE,UAAU,MAC/B,oCAAC,SAAI,eAAW,iBAAG,gBAAgB,SAAS,GAAG,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,eAAY,UAC/H,oCAAC,UAAK,GAAE,+BAA8B,eAAc,SAAQ,CAC9D;AAIF,MAAM,eAAoE;AAAA,EACxE,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AACX;AAGA,MAAM,WAAsC;AAAA,EAC1C,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX;AAEA,MAAM,eAA0C;AAAA,EAC9C,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX;AAGA,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,cAAc;AACpB,MAAM,wBAAwB;AAC9B,MAAM,qBAAqB;AAC3B,MAAM,yBAAyB;AAC/B,MAAM,2BAA2B;AACjC,MAAM,6BAA6B;AAGnC,MAAM,oBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,MACN;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,MAAM;AAAA,IACR;AAAA,EACF;AACF;AA2CA,SAAS,mBAA+B;AACtC,QAAM,QAAoB;AAAA,IACxB,QAAQ,CAAC;AAAA,IACT,WAAW,oBAAI,IAAI;AAAA,IACnB,SAASA,QAAO;AACd,YAAM,SAAS,CAACA,QAAO,GAAG,MAAM,MAAM;AACtC,YAAM,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,IACpC;AAAA,IACA,YAAY,IAAI;AACd,YAAM,SAAS,MAAM,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AACrD,YAAM,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,IACpC;AAAA,IACA,YAAY,IAAI,SAAS;AACvB,YAAM,SAAS,MAAM,OAAO,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,EAAE,GAAG,GAAG,GAAG,QAAQ,IAAI,CAAE;AAC/E,YAAM,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,IACpC;AAAA,IACA,YAAY;AACV,YAAM,SAAS,CAAC;AAChB,YAAM,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,IACpC;AAAA,IACA,UAAU,UAAU;AAClB,YAAM,UAAU,IAAI,QAAQ;AAC5B,aAAO,MAAM;AAAE,cAAM,UAAU,OAAO,QAAQ;AAAA,MAAE;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,cAAc,iBAAiB;AAErC,SAAS,gBAAgB;AACvB,QAAM,CAAC,EAAE,WAAW,IAAI,MAAM,SAAS,CAAC;AACxC,QAAM,UAAU,MAAM;AACpB,WAAO,YAAY,UAAU,MAAM,YAAY,CAAC,MAAM,IAAI,CAAC,CAAC;AAAA,EAC9D,GAAG,CAAC,CAAC;AACL,SAAO,YAAY;AACrB;AAGA,IAAI,eAAe;AACnB,SAAS,QAAQ;AACf,kBAAgB;AAChB,SAAO,SAAS,YAAY,IAAI,KAAK,IAAI,CAAC;AAC5C;AAgCA,SAAS,YAAY,SAA0B,MAAiB,MAA6B;AAC3F,QAAM,KAAK,MAAM,MAAM,MAAM;AAG7B,QAAM,WAAW,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3D,MAAI,UAAU;AACZ,gBAAY,YAAY,IAAI,EAAE,SAAS,MAAM,GAAG,KAAK,CAAC;AACtD,WAAO;AAAA,EACT;AAEA,cAAY,SAAS;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,MAAM;AAAA,IACnB,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB,MAAM,MAAM;AAAA,IACZ,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM;AAAA,IACd,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,EACnB,CAAC;AACD,SAAO;AACT;AAEA,SAAS,MAAM,SAA0B,MAA6B;AACpE,SAAO,YAAY,SAAS,WAAW,IAAI;AAC7C;AAEA,MAAM,UAAU,CAAC,SAA0B,SACzC,YAAY,SAAS,WAAW,IAAI;AAEtC,MAAM,QAAQ,CAAC,SAA0B,SACvC,YAAY,SAAS,SAAS,IAAI;AAEpC,MAAM,UAAU,CAAC,SAA0B,SACzC,YAAY,SAAS,WAAW,IAAI;AAEtC,MAAM,OAAO,CAAC,SAA0B,SACtC,YAAY,SAAS,QAAQ,IAAI;AAEnC,MAAM,UAAU,CAAC,SAA0B,SACzC,YAAY,SAAS,WAAW,EAAE,GAAG,MAAM,UAAU,EAAE,CAAC;AAE1D,MAAM,UAAU,CACd,SACA,MACA,cACe;AACf,QAAM,KAAK,YAAY,KAAK,SAAS,WAAW;AAAA,IAC9C,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,UACG,KAAK,CAAC,SAAS;AACd,UAAM,MAAM,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,IAAI,IAAI,KAAK;AAC3E,UAAM,OAAO,OAAO,KAAK,aAAa,YAAY,aAC9C,KAAK,YAAY,QAAQ,IAAI,IAC7B,KAAK,aAAa;AACtB,gBAAY,YAAY,IAAI;AAAA,MAC1B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,MACb,UAAU,WAAW;AAAA,MACrB,eAAe;AAAA,IACjB,CAAC;AAAA,EACH,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,UAAM,MAAM,OAAO,KAAK,UAAU,aAAa,KAAK,MAAM,GAAG,IAAI,KAAK;AACtE,UAAM,OAAO,OAAO,KAAK,aAAa,UAAU,aAC5C,KAAK,YAAY,MAAM,GAAG,IAC1B,KAAK,aAAa;AACtB,gBAAY,YAAY,IAAI;AAAA,MAC1B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,MACb,UAAU,WAAW;AAAA,MACrB,eAAe;AAAA,IACjB,CAAC;AAAA,EACH,CAAC,EACA,QAAQ,MAAM;AACb,SAAK,UAAU;AAAA,EACjB,CAAC;AAEH,SAAO;AACT;AAEA,MAAM,UAAU,CAAC,OAAgB;AAC/B,MAAI,IAAI;AACN,gBAAY,YAAY,EAAE;AAAA,EAC5B,OAAO;AACL,gBAAY,UAAU;AAAA,EACxB;AACF;AAEA,MAAM,SAAS,CAAC,QAA2C,SAAgC;AACzF,QAAM,KAAK,MAAM,MAAM,MAAM;AAC7B,cAAY,SAAS;AAAA,IACnB;AAAA,IACA,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM;AAAA,IACjB,aAAa,MAAM;AAAA,IACnB,eAAe;AAAA,EACjB,CAAC;AACD,SAAO;AACT;AAgBA,MAAM,YAAY,MAAM,KAAK,SAASC,WAAU;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,KAAK;AACpD,QAAM,WAAW,MAAM,OAA6C,IAAI;AACxE,QAAM,eAAe,MAAM,OAAe,CAAC;AAC3C,QAAM,eAAe,MAAM,OAAe,CAAC;AAG3C,QAAM,UAAU,MAAM;AACpB,UAAM,QAAQ,WAAW,MAAM,aAAa,IAAI,GAAG,mBAAmB;AACtE,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,YAAY,KAAK,eAAe;AACtC,QAAM,cAAc,KAAK,gBAAgB;AACzC,QAAM,WAAW,KAAK,SAAS,YAAY,IAAK,KAAK,YAAY;AAGjE,QAAM,OAAO,KAAK,SAAS,WAAW,KAAK,SAAS,YAAY,UAAU;AAC1E,QAAM,WAAW,KAAK,SAAS,WAAW,KAAK,SAAS,YAAY,cAAc;AAElF,QAAM,SAAS,aAAa,aAAa,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI;AACxE,QAAM,aAAa,aAAa,KAAK,IAAI;AAGzC,QAAM,YAAY,SAAS,SAAS,OAAO,IACvC,iCACA,SAAS,SAAS,MAAM,IACtB,gCACA,SAAS,SAAS,KAAK,IACrB,+BACA;AAER,QAAM,WAAW,SAAS,SAAS,OAAO,IACtC,kCACA,SAAS,SAAS,MAAM,IACtB,iCACA,SAAS,SAAS,KAAK,IACrB,gCACA;AAER,QAAM,gBAAgB,MAAM,YAAY,MAAM;AAC5C,QAAI,CAAC,YAAa;AAClB,iBAAa,IAAI;AACjB,SAAK,YAAY,IAAI;AAErB,eAAW,MAAM,SAAS,KAAK,EAAE,GAAG,mBAAmB;AAAA,EACzD,GAAG,CAAC,MAAM,aAAa,QAAQ,CAAC;AAEhC,QAAM,kBAAkB,MAAM,YAAY,MAAM;AAC9C,iBAAa,IAAI;AACjB,SAAK,cAAc,IAAI;AACvB,eAAW,MAAM,SAAS,KAAK,EAAE,GAAG,mBAAmB;AAAA,EACzD,GAAG,CAAC,MAAM,QAAQ,CAAC;AAGnB,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY,EAAG;AAEnB,iBAAa,UAAU;AACvB,iBAAa,UAAU,KAAK,IAAI;AAEhC,aAAS,UAAU,WAAW,iBAAiB,QAAQ;AAEvD,WAAO,MAAM;AACX,UAAI,SAAS,QAAS,cAAa,SAAS,OAAO;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,UAAU,eAAe,CAAC;AAG9B,QAAM,mBAAmB,MAAM,YAAY,MAAM;AAC/C,QAAI,YAAY,EAAG;AACnB,gBAAY,IAAI;AAChB,QAAI,SAAS,SAAS;AACpB,mBAAa,SAAS,OAAO;AAC7B,mBAAa,WAAW,KAAK,IAAI,IAAI,aAAa;AAAA,IACpD;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,mBAAmB,MAAM,YAAY,MAAM;AAC/C,QAAI,YAAY,EAAG;AACnB,gBAAY,KAAK;AACjB,iBAAa,UAAU,KAAK,IAAI;AAChC,aAAS,UAAU,WAAW,iBAAiB,KAAK,IAAI,aAAa,SAAS,mBAAmB,CAAC;AAAA,EACpG,GAAG,CAAC,UAAU,eAAe,CAAC;AAG9B,QAAM,UAAU,MAAM;AACpB,QAAI,KAAK,kBAAkB,aAAa,KAAK,kBAAkB,SAAS;AACtE,YAAM,cAAc,KAAK,YAAY;AACrC,UAAI,cAAc,GAAG;AACnB,YAAI,SAAS,QAAS,cAAa,SAAS,OAAO;AACnD,qBAAa,UAAU;AACvB,qBAAa,UAAU,KAAK,IAAI;AAChC,iBAAS,UAAU,WAAW,iBAAiB,WAAW;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,KAAK,eAAe,KAAK,UAAU,iBAAiB,eAAe,CAAC;AAExE,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAW;AAAA,MACX,eAAY;AAAA,MACZ,eAAW;AAAA,QACT,cAAc,EAAE,KAAK,CAAC;AAAA,QACtB;AAAA,QACA,YAAY,WAAW,CAAC,YAAY,YAAY;AAAA,QAChD,aAAa;AAAA,QACb,KAAK;AAAA,MACP;AAAA,MACA,cAAc;AAAA,MACd,cAAc;AAAA;AAAA,IAGb,KAAK,SAAS,SACb,KAAK,QAAQ,oCAAC,UAAK,WAAU,cAAY,KAAK,IAAK,IAEnD,KAAK,SAAS,aACZ,oCAAC,UAAK,WAAU,cACd,oCAAC,cAAW,WAAU,WAAU,CAClC;AAAA,IAKJ,oCAAC,SAAI,WAAU,oBACb,oCAAC,SAAI,WAAU,mBAAiB,KAAK,OAAQ,GAC5C,KAAK,eACJ,oCAAC,SAAI,eAAW,iBAAG,mBAAmB,SAAS,OAAO,YAAY,SAAS,KACxE,KAAK,WACR,CAEJ;AAAA,KAGE,KAAK,UAAU,KAAK,WACpB,oCAAC,SAAI,WAAU,wCACZ,KAAK,UACJ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM;AACb,eAAK,OAAQ,QAAQ;AACrB,wBAAc;AAAA,QAChB;AAAA;AAAA,MAEC,KAAK,OAAO;AAAA,IACf,GAED,KAAK,UACJ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM;AACb,eAAK,OAAQ,QAAQ;AACrB,wBAAc;AAAA,QAChB;AAAA;AAAA,MAEC,KAAK,OAAO;AAAA,IACf,CAEJ;AAAA,IAID,aAAa,eACZ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS;AAAA,QACT,cAAW;AAAA;AAAA,MAEX,oCAAC,oBAAiB,WAAU,WAAU;AAAA,IACxC;AAAA,EAGJ;AAEJ,CAAC;AA6BD,SAAS,QAAQ;AAAA,EACf,WAAW;AAAA,EACX,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP;AACF,GAAiB;AACf,QAAM,SAAS,cAAc;AAC7B,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,KAAK;AAEpD,QAAM,eAAe,MAAM,YAAY,CAAC,OAAe;AACrD,gBAAY,YAAY,EAAE;AAAA,EAC5B,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,OAAO,MAAM,GAAG,aAAa;AAE7C,QAAM,QAAQ,SAAS,WAAW,KAAK;AACvC,QAAM,WAAW,SAAS,SAAS,QAAQ;AAC3C,QAAM,UAAU,SAAS,SAAS,OAAO;AACzC,QAAM,SAAS,SAAS,SAAS,MAAM;AAGvC,QAAM,sBAAkB;AAAA,IACtB;AAAA,IACA,QAAQ,UAAU;AAAA,IAClB,WAAW,8BAA8B,UAAU,YAAY;AAAA,EACjE;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAW;AAAA,MACX,eAAW,iBAAG,iBAAiB,SAAS;AAAA,MACxC,OAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,OAAO,WAAW,SAAS;AAAA,QAC3B,UAAU,WAAW,gBAAgB,qBAAqB,QAAQ;AAAA,MACpE;AAAA,MACA,cAAc,MAAM,YAAY,IAAI;AAAA,MACpC,cAAc,MAAM,YAAY,KAAK;AAAA;AAAA,IAEpC,QAAQ,IAAI,CAAC,GAAG,UAAU;AACzB,YAAM,YAAY,CAAC,UAAU,CAAC,YAAY,QAAQ;AAClD,aACE;AAAA,QAAC;AAAA;AAAA,UACC,KAAK,EAAE;AAAA,UACP,WAAU;AAAA,UACV,OAAO;AAAA,YACL,OAAO;AAAA,YACP,UAAU,gBAAgB,qBAAqB;AAAA,YAC/C,GAAI,YACA;AAAA,cACE,UAAU;AAAA,cACV,GAAI,QAAQ,EAAE,KAAK,SAAS,QAAQ,mBAAmB,IAAI,EAAE,QAAQ,SAAS,QAAQ,mBAAmB;AAAA,cACzG,GAAI,WACA,EAAE,MAAM,OAAO,WAAW,0BAA0B,IAAI,QAAQ,sBAAsB,IAAI,IAC1F,UACE,EAAE,OAAO,QAAQ,WAAW,SAAS,IAAI,QAAQ,sBAAsB,IAAI,IAC3E,EAAE,MAAM,QAAQ,WAAW,SAAS,IAAI,QAAQ,sBAAsB,IAAI;AAAA,cAChF,SAAS,QAAQ,6BAA6B,IAAI,QAAQ,2BAA2B;AAAA,cACrF,QAAQ,gBAAgB;AAAA,cACxB,eAAe;AAAA,YACjB,IACA,EAAE,QAAQ,gBAAgB,MAAM;AAAA,UACtC;AAAA;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,iBAAiB;AAAA,YACjB,UAAU;AAAA;AAAA,QACZ;AAAA,MACF;AAAA,IAEJ,CAAC;AAAA,EACH;AAEJ;AACA,QAAQ,cAAc;","names":["toast","ToastItem"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/toast.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ─── Built-in status icons (shared with Alert — no external dependency) ──────\n// All icons: Lucide-compatible 24×24 viewBox, strokeWidth=2, rounded caps/joins\nconst InfoIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n)\n\nconst SuccessIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m9 12 2 2 4-4\" />\n </svg>\n)\n\nconst WarningIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n)\n\nconst ErrorIcon = ({ className }: { className?: string }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v5\" />\n <path d=\"M12 16h.01\" />\n </svg>\n)\n\nconst DefaultCloseIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n)\n\nconst LoadingIcon = ({ className }: { className?: string }) => (\n <svg className={cn('animate-spin', className)} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" strokeLinecap=\"round\" />\n </svg>\n)\n\n// ─── Status icon mapping ─────────────────────────────────────────\nconst STATUS_ICONS: Record<ToastType, React.FC<{ className?: string }>> = {\n default: InfoIcon,\n success: SuccessIcon,\n warning: WarningIcon,\n error: ErrorIcon,\n info: InfoIcon,\n loading: LoadingIcon,\n}\n\n// ─── Color × Type class mapping ─────────────────────────────────\nconst colorMap: Record<ToastType, string> = {\n default: 'bg-background-paper text-foreground border-border shadow-lg',\n success: 'bg-success-tint text-text-success border-success/20 shadow-lg',\n error: 'bg-error-tint text-text-error border-error/20 shadow-lg',\n warning: 'bg-warning-tint text-text-warning border-warning/20 shadow-lg',\n info: 'bg-info-tint text-text-info border-info/20 shadow-lg',\n loading: 'bg-background-paper text-foreground border-border shadow-lg',\n}\n\nconst richColorMap: Record<ToastType, string> = {\n default: 'bg-foreground text-background border-transparent shadow-lg',\n success: 'bg-success text-success-foreground border-transparent shadow-lg',\n error: 'bg-error text-error-foreground border-transparent shadow-lg',\n warning: 'bg-warning text-warning-foreground border-transparent shadow-lg',\n info: 'bg-info text-info-foreground border-transparent shadow-lg',\n loading: 'bg-foreground text-background border-transparent shadow-lg',\n}\n\n// ─── Constants (JS cannot read CSS variables at runtime) ─────────\nconst TOAST_EXIT_DURATION = 200 // --duration-normal (200ms)\nconst TOAST_MIN_RESUME_MS = 500 // --duration-slowest (500ms) — minimum time after hover resume\nconst TOAST_WIDTH = 360 // fixed toast width — smallest mobile viewport baseline\nconst TOAST_VIEWPORT_MARGIN = 48 // 2 × offset default (24px) — viewport safe area\nconst TOAST_STACK_OFFSET = 8 // --spacing-2 (8px) — vertical gap between stacked toasts\nconst TOAST_STACK_SCALE_STEP = 0.05 // scale reduction per stack level (0.95, 0.90, ...)\nconst TOAST_STACK_OPACITY_STEP = 0.15 // opacity reduction per stack level (0.85, 0.70, ...)\nconst TOAST_STACK_VISIBLE_LAYERS = 3 // max visible stacked layers before hidden\n\n// ─── Toast variants (CVA) ────────────────────────────────────────\nconst toastVariants = cva(\n 'group pointer-events-auto relative flex items-center gap-2.5 border w-full overflow-hidden transition-all',\n {\n variants: {\n size: {\n sm: 'p-3 text-sm rounded-md',\n default: 'p-4 text-md rounded-lg',\n lg: 'p-5 text-md rounded-lg',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\n// ─── Types ───────────────────────────────────────────────────────\nexport type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading'\nexport type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\nexport type ToastSize = 'sm' | 'default' | 'lg'\n\nexport interface ToastAction {\n label: string\n onClick: () => void\n}\n\nexport interface ToastData {\n id: string\n type: ToastType\n message: React.ReactNode\n description?: React.ReactNode\n duration?: number\n dismissible?: boolean\n closeButton?: boolean\n icon?: React.ReactNode\n action?: ToastAction\n cancel?: ToastAction\n onDismiss?: (toast: ToastData) => void\n onAutoClose?: (toast: ToastData) => void\n className?: string\n /** Promise state — managed internally */\n _promiseState?: 'loading' | 'success' | 'error'\n}\n\n// ─── Global toast store ──────────────────────────────────────────\ntype ToastListener = () => void\n\ninterface ToastStore {\n toasts: ToastData[]\n listeners: Set<ToastListener>\n addToast: (toast: ToastData) => void\n removeToast: (id: string) => void\n updateToast: (id: string, updates: Partial<ToastData>) => void\n removeAll: () => void\n subscribe: (listener: ToastListener) => () => void\n}\n\nfunction createToastStore(): ToastStore {\n const store: ToastStore = {\n toasts: [],\n listeners: new Set(),\n addToast(toast) {\n store.toasts = [toast, ...store.toasts]\n store.listeners.forEach((l) => l())\n },\n removeToast(id) {\n store.toasts = store.toasts.filter((t) => t.id !== id)\n store.listeners.forEach((l) => l())\n },\n updateToast(id, updates) {\n store.toasts = store.toasts.map((t) => (t.id === id ? { ...t, ...updates } : t))\n store.listeners.forEach((l) => l())\n },\n removeAll() {\n store.toasts = []\n store.listeners.forEach((l) => l())\n },\n subscribe(listener) {\n store.listeners.add(listener)\n return () => { store.listeners.delete(listener) }\n },\n }\n return store\n}\n\nconst globalStore = createToastStore()\n\nfunction useToastStore() {\n const [, forceUpdate] = React.useState(0)\n React.useEffect(() => {\n return globalStore.subscribe(() => forceUpdate((n) => n + 1))\n }, [])\n return globalStore.toasts\n}\n\n// ─── Toast ID generator ─────────────────────────────────────────\nlet toastCounter = 0\nfunction genId() {\n toastCounter += 1\n return `toast-${toastCounter}-${Date.now()}`\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// Imperative API: toast()\n// ═══════════════════════════════════════════════════════════════════\n\ninterface ToastOptions {\n id?: string\n description?: React.ReactNode\n duration?: number\n dismissible?: boolean\n closeButton?: boolean\n icon?: React.ReactNode\n action?: ToastAction\n cancel?: ToastAction\n onDismiss?: (toast: ToastData) => void\n onAutoClose?: (toast: ToastData) => void\n className?: string\n}\n\ninterface PromiseOptions<T> {\n loading: React.ReactNode\n success: React.ReactNode | ((data: T) => React.ReactNode)\n error: React.ReactNode | ((err: unknown) => React.ReactNode)\n finally?: () => void\n description?: {\n loading?: React.ReactNode\n success?: React.ReactNode | ((data: T) => React.ReactNode)\n error?: React.ReactNode | ((err: unknown) => React.ReactNode)\n }\n}\n\nfunction createToast(message: React.ReactNode, type: ToastType, opts?: ToastOptions): string {\n const id = opts?.id ?? genId()\n\n // If updating existing toast, just update\n const existing = globalStore.toasts.find((t) => t.id === id)\n if (existing) {\n globalStore.updateToast(id, { message, type, ...opts })\n return id\n }\n\n globalStore.addToast({\n id,\n type,\n message,\n description: opts?.description,\n duration: opts?.duration,\n dismissible: opts?.dismissible,\n closeButton: opts?.closeButton,\n icon: opts?.icon,\n action: opts?.action,\n cancel: opts?.cancel,\n onDismiss: opts?.onDismiss,\n onAutoClose: opts?.onAutoClose,\n className: opts?.className,\n })\n return id\n}\n\nfunction toast(message: React.ReactNode, opts?: ToastOptions): string {\n return createToast(message, 'default', opts)\n}\n\ntoast.success = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'success', opts)\n\ntoast.error = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'error', opts)\n\ntoast.warning = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'warning', opts)\n\ntoast.info = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'info', opts)\n\ntoast.loading = (message: React.ReactNode, opts?: ToastOptions) =>\n createToast(message, 'loading', { ...opts, duration: 0 })\n\ntoast.promise = <T,>(\n promise: Promise<T>,\n opts: PromiseOptions<T>,\n toastOpts?: ToastOptions\n): Promise<T> => {\n const id = createToast(opts.loading, 'loading', {\n ...toastOpts,\n duration: 0,\n })\n\n promise\n .then((data) => {\n const msg = typeof opts.success === 'function' ? opts.success(data) : opts.success\n const desc = typeof opts.description?.success === 'function'\n ? opts.description.success(data)\n : opts.description?.success\n globalStore.updateToast(id, {\n type: 'success',\n message: msg,\n description: desc,\n duration: toastOpts?.duration,\n _promiseState: 'success',\n })\n })\n .catch((err) => {\n const msg = typeof opts.error === 'function' ? opts.error(err) : opts.error\n const desc = typeof opts.description?.error === 'function'\n ? opts.description.error(err)\n : opts.description?.error\n globalStore.updateToast(id, {\n type: 'error',\n message: msg,\n description: desc,\n duration: toastOpts?.duration,\n _promiseState: 'error',\n })\n })\n .finally(() => {\n opts.finally?.()\n })\n\n return promise\n}\n\ntoast.dismiss = (id?: string) => {\n if (id) {\n globalStore.removeToast(id)\n } else {\n globalStore.removeAll()\n }\n}\n\ntoast.custom = (render: (t: ToastData) => React.ReactNode, opts?: ToastOptions): string => {\n const id = opts?.id ?? genId()\n globalStore.addToast({\n id,\n type: 'default',\n message: render as unknown as React.ReactNode,\n duration: opts?.duration,\n dismissible: opts?.dismissible,\n className: opts?.className,\n onDismiss: opts?.onDismiss,\n onAutoClose: opts?.onAutoClose,\n _promiseState: undefined,\n })\n return id\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// ToastItem — individual toast renderer\n// ═══════════════════════════════════════════════════════════════════\n\ninterface ToastItemProps {\n data: ToastData\n position: ToastPosition\n size: ToastSize\n closeButton: boolean\n richColors: boolean\n defaultDuration: number\n onRemove: (id: string) => void\n}\n\nconst ToastItem = React.memo(function ToastItem({\n data,\n position,\n size,\n closeButton: globalCloseButton,\n richColors,\n defaultDuration,\n onRemove,\n}: ToastItemProps) {\n const [isExiting, setIsExiting] = React.useState(false)\n const [isEntered, setIsEntered] = React.useState(false)\n const [isPaused, setIsPaused] = React.useState(false)\n const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n const remainingRef = React.useRef<number>(0)\n const startTimeRef = React.useRef<number>(0)\n\n // Enter animation — play once on mount, then remove class\n React.useEffect(() => {\n const timer = setTimeout(() => setIsEntered(true), TOAST_EXIT_DURATION)\n return () => clearTimeout(timer)\n }, [])\n\n const showClose = data.closeButton ?? globalCloseButton\n const dismissible = data.dismissible !== false\n const duration = data.type === 'loading' ? 0 : (data.duration ?? defaultDuration)\n\n // ARIA — error/warning use assertive, others polite\n const role = data.type === 'error' || data.type === 'warning' ? 'alert' : 'status'\n const ariaLive = data.type === 'error' || data.type === 'warning' ? 'assertive' : 'polite'\n\n const colors = richColors ? richColorMap[data.type] : colorMap[data.type]\n const StatusIcon = STATUS_ICONS[data.type]\n\n // Animation classes based on position\n const enterAnim = position.includes('right')\n ? 'animate-toast-slide-in-right'\n : position.includes('left')\n ? 'animate-toast-slide-in-left'\n : position.includes('top')\n ? 'animate-toast-slide-in-top'\n : 'animate-toast-slide-in-bottom'\n\n const exitAnim = position.includes('right')\n ? 'animate-toast-slide-out-right'\n : position.includes('left')\n ? 'animate-toast-slide-out-left'\n : position.includes('top')\n ? 'animate-toast-slide-out-top'\n : 'animate-toast-slide-out-bottom'\n\n const handleDismiss = React.useCallback(() => {\n if (!dismissible) return\n setIsExiting(true)\n data.onDismiss?.(data)\n // Wait for exit animation then remove\n setTimeout(() => onRemove(data.id), TOAST_EXIT_DURATION)\n }, [data, dismissible, onRemove])\n\n const handleAutoClose = React.useCallback(() => {\n setIsExiting(true)\n data.onAutoClose?.(data)\n setTimeout(() => onRemove(data.id), TOAST_EXIT_DURATION)\n }, [data, onRemove])\n\n // Auto-dismiss timer with pause support\n React.useEffect(() => {\n if (duration <= 0) return\n\n remainingRef.current = duration\n startTimeRef.current = Date.now()\n\n timerRef.current = setTimeout(handleAutoClose, duration)\n\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current)\n }\n }, [duration, handleAutoClose])\n\n // Pause/resume on hover\n const handleMouseEnter = React.useCallback(() => {\n if (duration <= 0) return\n setIsPaused(true)\n if (timerRef.current) {\n clearTimeout(timerRef.current)\n remainingRef.current -= Date.now() - startTimeRef.current\n }\n }, [duration])\n\n const handleMouseLeave = React.useCallback(() => {\n if (duration <= 0) return\n setIsPaused(false)\n startTimeRef.current = Date.now()\n timerRef.current = setTimeout(handleAutoClose, Math.max(remainingRef.current, TOAST_MIN_RESUME_MS))\n }, [duration, handleAutoClose])\n\n // Reset timer when toast updates (promise resolve)\n React.useEffect(() => {\n if (data._promiseState === 'success' || data._promiseState === 'error') {\n const newDuration = data.duration ?? defaultDuration\n if (newDuration > 0) {\n if (timerRef.current) clearTimeout(timerRef.current)\n remainingRef.current = newDuration\n startTimeRef.current = Date.now()\n timerRef.current = setTimeout(handleAutoClose, newDuration)\n }\n }\n }, [data._promiseState, data.duration, defaultDuration, handleAutoClose])\n\n return (\n <div\n role={role}\n aria-live={ariaLive}\n aria-atomic=\"true\"\n className={cn(\n toastVariants({ size }),\n colors,\n isExiting ? exitAnim : !isEntered ? enterAnim : undefined,\n isExiting && 'pointer-events-none',\n data.className,\n )}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n {/* Icon */}\n {data.icon !== undefined ? (\n data.icon && <span className=\"shrink-0\">{data.icon}</span>\n ) : (\n data.type !== 'default' && (\n <span className=\"shrink-0\">\n <StatusIcon className=\"icon-sm\" />\n </span>\n )\n )}\n\n {/* Content */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-semibold\">{data.message}</div>\n {data.description && (\n <div className={cn('mt-1 opacity-80', size === 'sm' ? 'text-xs' : 'text-sm')}>\n {data.description}\n </div>\n )}\n </div>\n\n {/* Actions */}\n {(data.action || data.cancel) && (\n <div className=\"flex items-center gap-1.5 shrink-0\">\n {data.cancel && (\n <button\n type=\"button\"\n className=\"px-2.5 py-1.5 text-xs font-semibold rounded-md opacity-70 hover:opacity-100 transition-opacity\"\n onClick={() => {\n data.cancel!.onClick()\n handleDismiss()\n }}\n >\n {data.cancel.label}\n </button>\n )}\n {data.action && (\n <button\n type=\"button\"\n className=\"px-2.5 py-1.5 text-xs font-semibold rounded-md bg-foreground/5 hover:bg-foreground/15 transition-colors\"\n onClick={() => {\n data.action!.onClick()\n handleDismiss()\n }}\n >\n {data.action.label}\n </button>\n )}\n </div>\n )}\n\n {/* Close button */}\n {showClose && dismissible && (\n <button\n type=\"button\"\n className=\"shrink-0 rounded-md p-1 opacity-70 hover:opacity-100 transition-opacity focus-visible:focus-ring\"\n onClick={handleDismiss}\n aria-label=\"Close\"\n >\n <DefaultCloseIcon className=\"icon-sm\" />\n </button>\n )}\n\n </div>\n )\n})\n\n// ═══════════════════════════════════════════════════════════════════\n// Toaster — renders all toasts\n// ═══════════════════════════════════════════════════════════════════\n\nexport interface ToasterProps {\n /** Position on screen */\n position?: ToastPosition\n /** Default auto-dismiss duration in ms (0 = persistent) */\n duration?: number\n /** Max visible toasts */\n visibleToasts?: number\n /** Show close button on all toasts */\n closeButton?: boolean\n /** Use rich (filled) colors for status toasts — default: true */\n richColors?: boolean\n /** Expand all toasts (no stacking) */\n expand?: boolean\n /** Offset from screen edge in px */\n offset?: number\n /** Gap between toasts in px */\n gap?: number\n /** Toast size */\n size?: ToastSize\n /** Additional className for container */\n className?: string\n}\n\nfunction Toaster({\n position = 'bottom-right',\n duration = 4000,\n visibleToasts = 5,\n closeButton = false,\n richColors = true,\n expand = false,\n offset = 24,\n gap = 8,\n size = 'default',\n className,\n}: ToasterProps) {\n const toasts = useToastStore()\n const [expanded, setExpanded] = React.useState(false)\n\n const handleRemove = React.useCallback((id: string) => {\n globalStore.removeToast(id)\n }, [])\n\n const visible = toasts.slice(0, visibleToasts)\n\n const isTop = position.startsWith('top')\n const isCenter = position.includes('center')\n const isRight = position.includes('right')\n const isLeft = position.includes('left')\n\n // Position styles\n const positionClasses = cn(\n 'fixed z-toast flex flex-col pointer-events-none',\n isTop ? 'top-0' : 'bottom-0',\n isCenter ? 'left-1/2 -translate-x-1/2' : isRight ? 'right-0' : 'left-0',\n )\n\n return (\n <section\n aria-label=\"Notifications\"\n className={cn(positionClasses, className)}\n style={{\n padding: offset,\n gap,\n width: isCenter ? 'auto' : undefined,\n maxWidth: isCenter ? `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)` : undefined,\n }}\n onMouseEnter={() => setExpanded(true)}\n onMouseLeave={() => setExpanded(false)}\n >\n {visible.map((t, index) => {\n const isStacked = !expand && !expanded && index > 0\n return (\n <div\n key={t.id}\n className=\"transition-[transform,opacity] duration-normal ease-out\"\n style={{\n width: TOAST_WIDTH,\n maxWidth: `calc(100vw - ${TOAST_VIEWPORT_MARGIN}px)`,\n ...(isStacked\n ? {\n position: 'absolute' as const,\n ...(isTop ? { top: offset + index * TOAST_STACK_OFFSET } : { bottom: offset + index * TOAST_STACK_OFFSET }),\n ...(isCenter\n ? { left: '50%', transform: `translateX(-50%) scale(${1 - index * TOAST_STACK_SCALE_STEP})` }\n : isRight\n ? { right: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` }\n : { left: offset, transform: `scale(${1 - index * TOAST_STACK_SCALE_STEP})` }),\n opacity: index < TOAST_STACK_VISIBLE_LAYERS ? 1 - index * TOAST_STACK_OPACITY_STEP : 0,\n zIndex: visibleToasts - index,\n pointerEvents: 'none' as const,\n }\n : { zIndex: visibleToasts - index }),\n }}\n >\n <ToastItem\n data={t}\n position={position}\n size={size}\n closeButton={closeButton}\n richColors={richColors}\n defaultDuration={duration}\n onRemove={handleRemove}\n />\n </div>\n )\n })}\n </section>\n )\n}\nToaster.displayName = 'Toaster'\n\n// ─── Exports ─────────────────────────────────────────────────────\nexport {\n toast,\n Toaster,\n toastVariants,\n}\n\nexport type {\n ToastOptions,\n PromiseOptions,\n}\n"],"mappings":"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","names":["toast","ToastItem"]}
|