@refraction-ui/react 0.19.2 → 0.20.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.
Files changed (59) hide show
  1. package/dist/{chunk-UJ6BBWQM.js → chunk-TOZBR4GL.js} +3 -3
  2. package/dist/{chunk-UJ6BBWQM.js.map → chunk-TOZBR4GL.js.map} +1 -1
  3. package/dist/chunk-WSPJTQAV.js +59 -0
  4. package/dist/chunk-WSPJTQAV.js.map +7 -0
  5. package/dist/form.cjs.map +1 -1
  6. package/dist/form.js.map +1 -1
  7. package/dist/index.cjs +2584 -33423
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +1 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +1 -0
  12. package/dist/internal/react-badge/index.d.cts +5 -0
  13. package/dist/internal/react-badge/index.d.ts +5 -0
  14. package/dist/internal/react-callout/index.d.cts +4 -0
  15. package/dist/internal/react-callout/index.d.ts +4 -0
  16. package/dist/internal/react-card/index.d.cts +8 -1
  17. package/dist/internal/react-card/index.d.ts +8 -1
  18. package/dist/internal/react-form/index.d.cts +2 -21
  19. package/dist/internal/react-form/index.d.ts +2 -21
  20. package/dist/internal/react-link-card/index.d.cts +8 -2
  21. package/dist/internal/react-link-card/index.d.ts +8 -2
  22. package/dist/internal/react-slot/index.d.cts +23 -0
  23. package/dist/internal/react-slot/index.d.ts +23 -0
  24. package/dist/react-analytics.js +6 -6
  25. package/dist/react-analytics.js.map +3 -3
  26. package/dist/react-avatar-group.js +4 -4
  27. package/dist/react-avatar-group.js.map +1 -1
  28. package/dist/react-badge.js +17 -1
  29. package/dist/react-badge.js.map +2 -2
  30. package/dist/react-callout.js +19 -3
  31. package/dist/react-callout.js.map +2 -2
  32. package/dist/react-card.js +18 -2
  33. package/dist/react-card.js.map +2 -2
  34. package/dist/react-empty-state.js +2 -2
  35. package/dist/react-empty-state.js.map +1 -1
  36. package/dist/react-input.js +1 -1
  37. package/dist/react-link-card.js +15 -1
  38. package/dist/react-link-card.js.map +2 -2
  39. package/dist/react-password-input.js +1 -1
  40. package/dist/react-presence-indicator.js +4 -4
  41. package/dist/react-presence-indicator.js.map +1 -1
  42. package/dist/react-progress-display.js +2 -2
  43. package/dist/react-progress-display.js.map +1 -1
  44. package/dist/react-slot.js +7 -0
  45. package/dist/react-slot.js.map +7 -0
  46. package/dist/react-status-indicator.js +8 -8
  47. package/dist/react-status-indicator.js.map +1 -1
  48. package/dist/react-toast.js +3 -3
  49. package/dist/react-toast.js.map +2 -2
  50. package/dist/styles.css +7 -0
  51. package/package.json +2 -1
  52. package/dist/applicationinsights-web-H7OBLIVJ.js +0 -23393
  53. package/dist/applicationinsights-web-H7OBLIVJ.js.map +0 -1
  54. package/dist/chunk-GFXGXZDB.js +0 -23543
  55. package/dist/chunk-GFXGXZDB.js.map +0 -7
  56. package/dist/chunk-O4R4W2KY.js +0 -6460
  57. package/dist/chunk-O4R4W2KY.js.map +0 -7
  58. package/dist/module-X3HTTRQK.js +0 -6438
  59. package/dist/module-X3HTTRQK.js.map +0 -1
@@ -129,9 +129,9 @@ var toastVariants = cva({
129
129
  variants: {
130
130
  variant: {
131
131
  default: "border bg-background text-foreground",
132
- success: "border-l-4 border-green-500/50 bg-green-50 text-green-900 dark:bg-green-950 dark:text-green-100",
133
- error: "border-l-4 border-red-500/50 bg-red-50 text-red-900 dark:bg-red-950 dark:text-red-100",
134
- warning: "border-l-4 border-amber-500/50 bg-amber-50 text-amber-900 dark:bg-amber-950 dark:text-amber-100"
132
+ success: "border-l-4 border-success/50 bg-success/10 text-success",
133
+ error: "border-l-4 border-destructive/50 bg-destructive/10 text-destructive",
134
+ warning: "border-l-4 border-warning/50 bg-warning/10 text-warning"
135
135
  }
136
136
  },
137
137
  defaultVariants: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../toast/src/toast.ts", "../../toast/src/toast.styles.ts", "../../react-toast/src/toast.tsx"],
4
- "sourcesContent": ["import type { AccessibilityProps } from '@refraction-ui/shared'\nimport { generateId } from '@refraction-ui/shared'\n\nexport type ToastVariant = 'default' | 'success' | 'error' | 'warning'\n\n/** Icon name for each toast variant — non-color indicator for colorblind safety */\nconst TOAST_ICONS: Record<ToastVariant, string> = {\n default: 'info-circle',\n success: 'check-circle',\n error: 'x-circle',\n warning: 'alert-triangle',\n}\n\n/** Get the icon name for a toast variant (colorblind-safe: meaning not conveyed by color alone) */\nexport function getToastIcon(variant: ToastVariant): string {\n return TOAST_ICONS[variant]\n}\n\nexport interface ToastProps {\n /** Visual variant */\n variant?: ToastVariant\n /** Auto-dismiss duration in ms (default: 3000). Set to 0 to disable. */\n duration?: number\n /** Whether the toast is open (controlled) */\n open?: boolean\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void\n /** Elapsed-time clock for timer pause/resume math (ms). Default: ambient `Date.now()` — inject for deterministic tests. */\n now?: () => number\n}\n\nexport interface ToastState {\n open: boolean\n variant: ToastVariant\n}\n\nexport interface ToastAPI {\n /** Current toast state */\n state: ToastState\n /** ARIA attributes for the toast element */\n ariaProps: Partial<AccessibilityProps>\n /** Dismiss the toast */\n dismiss(): void\n /** Start the auto-dismiss timer */\n startTimer(): void\n /** Pause the auto-dismiss timer (e.g. on hover) */\n pauseTimer(): void\n /** Resume the auto-dismiss timer */\n resumeTimer(): void\n}\n\nexport function createToast(props: ToastProps = {}): ToastAPI {\n const {\n variant = 'default',\n duration = 3000,\n open: controlledOpen,\n onOpenChange,\n } = props\n\n // Injection boundary: ambient time is the default; inject `now` for deterministic timer math.\n const now = props.now ?? (() => Date.now())\n let isOpen = controlledOpen ?? true\n let timerId: ReturnType<typeof setTimeout> | null = null\n let remaining = duration\n let startedAt = 0\n\n function dismiss(): void {\n clearTimer()\n isOpen = false\n onOpenChange?.(false)\n }\n\n function clearTimer(): void {\n if (timerId !== null) {\n clearTimeout(timerId)\n timerId = null\n }\n }\n\n function startTimer(): void {\n if (duration <= 0) return\n clearTimer()\n remaining = duration\n startedAt = now()\n timerId = setTimeout(dismiss, remaining)\n }\n\n function pauseTimer(): void {\n if (timerId === null) return\n clearTimer()\n remaining = remaining - (now() - startedAt)\n if (remaining < 0) remaining = 0\n }\n\n function resumeTimer(): void {\n if (duration <= 0 || remaining <= 0) return\n clearTimer()\n startedAt = now()\n timerId = setTimeout(dismiss, remaining)\n }\n\n const ariaProps: Partial<AccessibilityProps> = {\n role: 'alert',\n 'aria-live': 'assertive',\n 'aria-atomic': true,\n }\n\n return {\n state: {\n get open() {\n return controlledOpen !== undefined ? controlledOpen : isOpen\n },\n variant,\n },\n ariaProps,\n dismiss,\n startTimer,\n pauseTimer,\n resumeTimer,\n }\n}\n\n/** Entry in the toast manager */\nexport interface ToastEntry {\n id: string\n message: string\n variant: ToastVariant\n duration: number\n createdAt: number\n}\n\nexport interface ToastManagerAPI {\n /** Add a new toast. Returns the toast id. */\n toast(message: string, opts?: { variant?: ToastVariant; duration?: number }): string\n /** Dismiss a toast by id */\n dismiss(id: string): void\n /** Current toast list (read-only) */\n readonly toasts: ReadonlyArray<ToastEntry>\n /** Subscribe to toast list changes. Returns unsubscribe function. */\n subscribe(fn: (toasts: ReadonlyArray<ToastEntry>) => void): () => void\n}\n\nexport interface ToastManagerConfig {\n /** Clock for entry `createdAt` stamps (ms). Default: ambient `Date.now()` — inject for deterministic tests. */\n now?: () => number\n}\n\nexport function createToastManager(config: ToastManagerConfig = {}): ToastManagerAPI {\n // Injection boundary: ambient time is the default; inject `now` for deterministic createdAt.\n const now = config.now ?? (() => Date.now())\n let toasts: ToastEntry[] = []\n const listeners = new Set<(toasts: ReadonlyArray<ToastEntry>) => void>()\n const timers = new Map<string, ReturnType<typeof setTimeout>>()\n\n function notify(): void {\n const snapshot = [...toasts]\n for (const fn of listeners) {\n fn(snapshot)\n }\n }\n\n function dismiss(id: string): void {\n const timer = timers.get(id)\n if (timer) {\n clearTimeout(timer)\n timers.delete(id)\n }\n toasts = toasts.filter((t) => t.id !== id)\n notify()\n }\n\n function toast(\n message: string,\n opts?: { variant?: ToastVariant; duration?: number },\n ): string {\n const id = generateId('rfr-toast')\n const variant = opts?.variant ?? 'default'\n const duration = opts?.duration ?? 3000\n\n const entry: ToastEntry = {\n id,\n message,\n variant,\n duration,\n createdAt: now(),\n }\n\n toasts = [...toasts, entry]\n notify()\n\n if (duration > 0) {\n const timer = setTimeout(() => dismiss(id), duration)\n timers.set(id, timer)\n }\n\n return id\n }\n\n function subscribe(fn: (toasts: ReadonlyArray<ToastEntry>) => void): () => void {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n }\n\n return {\n toast,\n dismiss,\n get toasts() {\n return toasts\n },\n subscribe,\n }\n}\n", "import { cva } from '@refraction-ui/shared'\n\nexport const toastVariants = cva({\n base: 'pointer-events-auto relative flex w-full items-center justify-between gap-2 overflow-hidden rounded-lg border p-4 shadow-lg transition-all',\n variants: {\n variant: {\n default: 'border bg-background text-foreground',\n success:\n 'border-l-4 border-green-500/50 bg-green-50 text-green-900 dark:bg-green-950 dark:text-green-100',\n error:\n 'border-l-4 border-red-500/50 bg-red-50 text-red-900 dark:bg-red-950 dark:text-red-100',\n warning:\n 'border-l-4 border-amber-500/50 bg-amber-50 text-amber-900 dark:bg-amber-950 dark:text-amber-100',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n})\n", "import * as React from 'react'\nimport {\n createToast,\n createToastManager,\n toastVariants,\n type ToastVariant,\n type ToastEntry,\n type ToastManagerAPI,\n} from '@refraction-ui/toast'\nimport { cn, devWarn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface ToastContextValue {\n manager: ToastManagerAPI\n}\n\nconst ToastContext = React.createContext<ToastContextValue | null>(null)\n\nfunction useToastContext(): ToastContextValue {\n const ctx = React.useContext(ToastContext)\n if (!ctx) {\n devWarn(\n 'react-toast/use-toast-outside-provider',\n 'useToast() was called outside a <ToastProvider>. Wrap your app (or the consuming subtree) in <ToastProvider> so the toast context is available.',\n )\n throw new Error('useToast must be used within a <ToastProvider>')\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// ToastProvider\n// ---------------------------------------------------------------------------\n\nexport interface ToastProviderProps {\n children?: React.ReactNode\n}\n\nexport function ToastProvider({ children }: ToastProviderProps) {\n const managerRef = React.useRef<ToastManagerAPI | null>(null)\n if (managerRef.current === null) {\n managerRef.current = createToastManager()\n }\n\n const ctx = React.useMemo<ToastContextValue>(\n () => ({ manager: managerRef.current! }),\n [],\n )\n\n return React.createElement(ToastContext.Provider, { value: ctx }, children)\n}\n\n// ---------------------------------------------------------------------------\n// useToast hook\n// ---------------------------------------------------------------------------\n\nexport interface UseToastReturn {\n /** Show a new toast */\n toast: (message: string, opts?: { variant?: ToastVariant; duration?: number }) => string\n /** Dismiss a toast by id */\n dismiss: (id: string) => void\n /** Current toast entries */\n toasts: ReadonlyArray<ToastEntry>\n}\n\nexport function useToast(): UseToastReturn {\n const { manager } = useToastContext()\n const [toasts, setToasts] = React.useState<ReadonlyArray<ToastEntry>>(manager.toasts)\n\n React.useEffect(() => {\n // Sync initial state\n setToasts(manager.toasts)\n const unsub = manager.subscribe(setToasts)\n return unsub\n }, [manager])\n\n return {\n toast: manager.toast,\n dismiss: manager.dismiss,\n toasts,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Toast (individual toast component)\n// ---------------------------------------------------------------------------\n\nexport interface ToastProps extends React.HTMLAttributes<HTMLDivElement> {\n entry: ToastEntry\n onDismiss?: (id: string) => void\n}\n\nexport const Toast = React.forwardRef<HTMLDivElement, ToastProps>(\n function Toast({ entry, onDismiss, className, children, onMouseEnter, onMouseLeave, ...props }, ref) {\n const api = React.useMemo(\n () => createToast({ variant: entry.variant, duration: entry.duration }),\n [entry.variant, entry.duration],\n )\n\n // Start auto-dismiss timer on mount\n React.useEffect(() => {\n api.startTimer()\n return () => api.pauseTimer()\n }, [api])\n\n const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {\n api.pauseTimer()\n onMouseEnter?.(e)\n }\n\n const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {\n api.resumeTimer()\n onMouseLeave?.(e)\n }\n\n return React.createElement(\n 'div',\n {\n ref,\n className: cn(toastVariants({ variant: entry.variant }), className),\n ...api.ariaProps,\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n ...props,\n },\n React.createElement('div', { className: 'flex-1' }, entry.message),\n children,\n onDismiss &&\n React.createElement(\n 'button',\n {\n type: 'button',\n className: 'shrink-0',\n onClick: () => onDismiss(entry.id),\n 'aria-label': 'Dismiss',\n },\n '\\u00d7',\n ),\n )\n },\n)\n\n// ---------------------------------------------------------------------------\n// Toaster (container that renders all active toasts)\n// ---------------------------------------------------------------------------\n\nexport interface ToasterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const Toaster = React.forwardRef<HTMLDivElement, ToasterProps>(\n function Toaster({ className, ...props }, ref) {\n const { toasts, dismiss } = useToast()\n\n return React.createElement(\n 'div',\n {\n ref,\n className: cn(\n 'fixed bottom-4 right-4 z-50 flex flex-col gap-2 w-full max-w-sm pointer-events-none',\n className,\n ),\n ...props,\n },\n toasts.map((entry) =>\n React.createElement(Toast, {\n key: entry.id,\n entry,\n onDismiss: dismiss,\n }),\n ),\n )\n },\n)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { AccessibilityProps } from '@refraction-ui/shared'\nimport { generateId } from '@refraction-ui/shared'\n\nexport type ToastVariant = 'default' | 'success' | 'error' | 'warning'\n\n/** Icon name for each toast variant — non-color indicator for colorblind safety */\nconst TOAST_ICONS: Record<ToastVariant, string> = {\n default: 'info-circle',\n success: 'check-circle',\n error: 'x-circle',\n warning: 'alert-triangle',\n}\n\n/** Get the icon name for a toast variant (colorblind-safe: meaning not conveyed by color alone) */\nexport function getToastIcon(variant: ToastVariant): string {\n return TOAST_ICONS[variant]\n}\n\nexport interface ToastProps {\n /** Visual variant */\n variant?: ToastVariant\n /** Auto-dismiss duration in ms (default: 3000). Set to 0 to disable. */\n duration?: number\n /** Whether the toast is open (controlled) */\n open?: boolean\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void\n /** Elapsed-time clock for timer pause/resume math (ms). Default: ambient `Date.now()` — inject for deterministic tests. */\n now?: () => number\n}\n\nexport interface ToastState {\n open: boolean\n variant: ToastVariant\n}\n\nexport interface ToastAPI {\n /** Current toast state */\n state: ToastState\n /** ARIA attributes for the toast element */\n ariaProps: Partial<AccessibilityProps>\n /** Dismiss the toast */\n dismiss(): void\n /** Start the auto-dismiss timer */\n startTimer(): void\n /** Pause the auto-dismiss timer (e.g. on hover) */\n pauseTimer(): void\n /** Resume the auto-dismiss timer */\n resumeTimer(): void\n}\n\nexport function createToast(props: ToastProps = {}): ToastAPI {\n const {\n variant = 'default',\n duration = 3000,\n open: controlledOpen,\n onOpenChange,\n } = props\n\n // Injection boundary: ambient time is the default; inject `now` for deterministic timer math.\n const now = props.now ?? (() => Date.now())\n let isOpen = controlledOpen ?? true\n let timerId: ReturnType<typeof setTimeout> | null = null\n let remaining = duration\n let startedAt = 0\n\n function dismiss(): void {\n clearTimer()\n isOpen = false\n onOpenChange?.(false)\n }\n\n function clearTimer(): void {\n if (timerId !== null) {\n clearTimeout(timerId)\n timerId = null\n }\n }\n\n function startTimer(): void {\n if (duration <= 0) return\n clearTimer()\n remaining = duration\n startedAt = now()\n timerId = setTimeout(dismiss, remaining)\n }\n\n function pauseTimer(): void {\n if (timerId === null) return\n clearTimer()\n remaining = remaining - (now() - startedAt)\n if (remaining < 0) remaining = 0\n }\n\n function resumeTimer(): void {\n if (duration <= 0 || remaining <= 0) return\n clearTimer()\n startedAt = now()\n timerId = setTimeout(dismiss, remaining)\n }\n\n const ariaProps: Partial<AccessibilityProps> = {\n role: 'alert',\n 'aria-live': 'assertive',\n 'aria-atomic': true,\n }\n\n return {\n state: {\n get open() {\n return controlledOpen !== undefined ? controlledOpen : isOpen\n },\n variant,\n },\n ariaProps,\n dismiss,\n startTimer,\n pauseTimer,\n resumeTimer,\n }\n}\n\n/** Entry in the toast manager */\nexport interface ToastEntry {\n id: string\n message: string\n variant: ToastVariant\n duration: number\n createdAt: number\n}\n\nexport interface ToastManagerAPI {\n /** Add a new toast. Returns the toast id. */\n toast(message: string, opts?: { variant?: ToastVariant; duration?: number }): string\n /** Dismiss a toast by id */\n dismiss(id: string): void\n /** Current toast list (read-only) */\n readonly toasts: ReadonlyArray<ToastEntry>\n /** Subscribe to toast list changes. Returns unsubscribe function. */\n subscribe(fn: (toasts: ReadonlyArray<ToastEntry>) => void): () => void\n}\n\nexport interface ToastManagerConfig {\n /** Clock for entry `createdAt` stamps (ms). Default: ambient `Date.now()` — inject for deterministic tests. */\n now?: () => number\n}\n\nexport function createToastManager(config: ToastManagerConfig = {}): ToastManagerAPI {\n // Injection boundary: ambient time is the default; inject `now` for deterministic createdAt.\n const now = config.now ?? (() => Date.now())\n let toasts: ToastEntry[] = []\n const listeners = new Set<(toasts: ReadonlyArray<ToastEntry>) => void>()\n const timers = new Map<string, ReturnType<typeof setTimeout>>()\n\n function notify(): void {\n const snapshot = [...toasts]\n for (const fn of listeners) {\n fn(snapshot)\n }\n }\n\n function dismiss(id: string): void {\n const timer = timers.get(id)\n if (timer) {\n clearTimeout(timer)\n timers.delete(id)\n }\n toasts = toasts.filter((t) => t.id !== id)\n notify()\n }\n\n function toast(\n message: string,\n opts?: { variant?: ToastVariant; duration?: number },\n ): string {\n const id = generateId('rfr-toast')\n const variant = opts?.variant ?? 'default'\n const duration = opts?.duration ?? 3000\n\n const entry: ToastEntry = {\n id,\n message,\n variant,\n duration,\n createdAt: now(),\n }\n\n toasts = [...toasts, entry]\n notify()\n\n if (duration > 0) {\n const timer = setTimeout(() => dismiss(id), duration)\n timers.set(id, timer)\n }\n\n return id\n }\n\n function subscribe(fn: (toasts: ReadonlyArray<ToastEntry>) => void): () => void {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n }\n\n return {\n toast,\n dismiss,\n get toasts() {\n return toasts\n },\n subscribe,\n }\n}\n", "import { cva } from '@refraction-ui/shared'\n\nexport const toastVariants = cva({\n base: 'pointer-events-auto relative flex w-full items-center justify-between gap-2 overflow-hidden rounded-lg border p-4 shadow-lg transition-all',\n variants: {\n variant: {\n default: 'border bg-background text-foreground',\n success: 'border-l-4 border-success/50 bg-success/10 text-success',\n error: 'border-l-4 border-destructive/50 bg-destructive/10 text-destructive',\n warning: 'border-l-4 border-warning/50 bg-warning/10 text-warning',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n})\n", "import * as React from 'react'\nimport {\n createToast,\n createToastManager,\n toastVariants,\n type ToastVariant,\n type ToastEntry,\n type ToastManagerAPI,\n} from '@refraction-ui/toast'\nimport { cn, devWarn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface ToastContextValue {\n manager: ToastManagerAPI\n}\n\nconst ToastContext = React.createContext<ToastContextValue | null>(null)\n\nfunction useToastContext(): ToastContextValue {\n const ctx = React.useContext(ToastContext)\n if (!ctx) {\n devWarn(\n 'react-toast/use-toast-outside-provider',\n 'useToast() was called outside a <ToastProvider>. Wrap your app (or the consuming subtree) in <ToastProvider> so the toast context is available.',\n )\n throw new Error('useToast must be used within a <ToastProvider>')\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// ToastProvider\n// ---------------------------------------------------------------------------\n\nexport interface ToastProviderProps {\n children?: React.ReactNode\n}\n\nexport function ToastProvider({ children }: ToastProviderProps) {\n const managerRef = React.useRef<ToastManagerAPI | null>(null)\n if (managerRef.current === null) {\n managerRef.current = createToastManager()\n }\n\n const ctx = React.useMemo<ToastContextValue>(\n () => ({ manager: managerRef.current! }),\n [],\n )\n\n return React.createElement(ToastContext.Provider, { value: ctx }, children)\n}\n\n// ---------------------------------------------------------------------------\n// useToast hook\n// ---------------------------------------------------------------------------\n\nexport interface UseToastReturn {\n /** Show a new toast */\n toast: (message: string, opts?: { variant?: ToastVariant; duration?: number }) => string\n /** Dismiss a toast by id */\n dismiss: (id: string) => void\n /** Current toast entries */\n toasts: ReadonlyArray<ToastEntry>\n}\n\nexport function useToast(): UseToastReturn {\n const { manager } = useToastContext()\n const [toasts, setToasts] = React.useState<ReadonlyArray<ToastEntry>>(manager.toasts)\n\n React.useEffect(() => {\n // Sync initial state\n setToasts(manager.toasts)\n const unsub = manager.subscribe(setToasts)\n return unsub\n }, [manager])\n\n return {\n toast: manager.toast,\n dismiss: manager.dismiss,\n toasts,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Toast (individual toast component)\n// ---------------------------------------------------------------------------\n\nexport interface ToastProps extends React.HTMLAttributes<HTMLDivElement> {\n entry: ToastEntry\n onDismiss?: (id: string) => void\n}\n\nexport const Toast = React.forwardRef<HTMLDivElement, ToastProps>(\n function Toast({ entry, onDismiss, className, children, onMouseEnter, onMouseLeave, ...props }, ref) {\n const api = React.useMemo(\n () => createToast({ variant: entry.variant, duration: entry.duration }),\n [entry.variant, entry.duration],\n )\n\n // Start auto-dismiss timer on mount\n React.useEffect(() => {\n api.startTimer()\n return () => api.pauseTimer()\n }, [api])\n\n const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {\n api.pauseTimer()\n onMouseEnter?.(e)\n }\n\n const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {\n api.resumeTimer()\n onMouseLeave?.(e)\n }\n\n return React.createElement(\n 'div',\n {\n ref,\n className: cn(toastVariants({ variant: entry.variant }), className),\n ...api.ariaProps,\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n ...props,\n },\n React.createElement('div', { className: 'flex-1' }, entry.message),\n children,\n onDismiss &&\n React.createElement(\n 'button',\n {\n type: 'button',\n className: 'shrink-0',\n onClick: () => onDismiss(entry.id),\n 'aria-label': 'Dismiss',\n },\n '\\u00d7',\n ),\n )\n },\n)\n\n// ---------------------------------------------------------------------------\n// Toaster (container that renders all active toasts)\n// ---------------------------------------------------------------------------\n\nexport interface ToasterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const Toaster = React.forwardRef<HTMLDivElement, ToasterProps>(\n function Toaster({ className, ...props }, ref) {\n const { toasts, dismiss } = useToast()\n\n return React.createElement(\n 'div',\n {\n ref,\n className: cn(\n 'fixed bottom-4 right-4 z-50 flex flex-col gap-2 w-full max-w-sm pointer-events-none',\n className,\n ),\n ...props,\n },\n toasts.map((entry) =>\n React.createElement(Toast, {\n key: entry.id,\n entry,\n onDismiss: dismiss,\n }),\n ),\n )\n },\n)\n"],
5
+ "mappings": "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",
6
6
  "names": ["Toast", "Toaster"]
7
7
  }
package/dist/styles.css CHANGED
@@ -61,6 +61,10 @@
61
61
  --success-foreground: 0 0% 100%;
62
62
  --warning: 38 92% 50%;
63
63
  --warning-foreground: 240 10% 10%;
64
+ /* #3B82F6 (Tailwind blue-500). The Flutter package's info token is #2196F3
65
+ (Material blue) — a deliberate small cross-framework delta. */
66
+ --info: 217 91% 60%;
67
+ --info-foreground: 0 0% 100%;
64
68
 
65
69
  --border: 240 6% 92%;
66
70
  --input: 240 6% 92%;
@@ -269,6 +273,9 @@
269
273
  --success-foreground: 0 0% 98%;
270
274
  --warning: 38 92% 50%;
271
275
  --warning-foreground: 240 10% 4%;
276
+ /* Lightened from 60% (light) to 65% lightness for contrast on dark surfaces */
277
+ --info: 217 91% 65%;
278
+ --info-foreground: 0 0% 98%;
272
279
 
273
280
  --border: 240 5% 16%;
274
281
  --input: 240 5% 16%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@refraction-ui/react",
3
- "version": "0.19.2",
3
+ "version": "0.20.0",
4
4
  "description": "All Refraction UI React components in one package — headless, accessible, zero-dependency",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -151,6 +151,7 @@
151
151
  "@refraction-ui/react-skip-to-content": "workspace:*",
152
152
  "@refraction-ui/react-slide-viewer": "workspace:*",
153
153
  "@refraction-ui/react-slider": "workspace:*",
154
+ "@refraction-ui/react-slot": "workspace:*",
154
155
  "@refraction-ui/react-slot-picker": "workspace:*",
155
156
  "@refraction-ui/react-social-auth-button": "workspace:*",
156
157
  "@refraction-ui/react-sortable-list": "workspace:*",