@mihcm/ui 0.15.1 → 0.16.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.
package/dist/Toast.d.ts CHANGED
@@ -1,29 +1,113 @@
1
1
  /**
2
2
  * Toast (web variant — React DOM).
3
3
  *
4
+ * Built on top of [sonner](https://sonner.emilkowal.ski/) so MiHCM apps get
5
+ * every feature the upstream library ships — promise toasts, loading state,
6
+ * action + cancel buttons, swipe-to-dismiss, hover-to-expand stacks, rich
7
+ * colours per type, theme switching, full a11y wiring — without forking.
8
+ *
9
+ * Surface is themed with MiHCM tokens (`bg-card`, `border-border`,
10
+ * `text-foreground`, `text-success-foreground`, etc.) via sonner's
11
+ * `toastOptions.classNames` so the toasts read as part of the rest of the
12
+ * design system regardless of light/dark mode or custom `colorScheme`s.
13
+ *
4
14
  * Two-part API:
5
- * 1. `<ToastProvider>` wraps your app, manages the queue, renders toasts
6
- * in a fixed container at bottom-right.
7
- * 2. `toast()` imperative function — call from anywhere to show a toast.
15
+ * 1. `<Toaster />` mount once near the app root. It renders the queue
16
+ * in a portal at the chosen `position`. Pass `richColors`, `expand`,
17
+ * `closeButton`, `visibleToasts`, `theme`, etc. to tune behaviour.
18
+ * 2. `toast()` — call from anywhere to enqueue. Sub-APIs:
8
19
  *
9
- * Sub-components (`Toast`, `ToastTitle`, `ToastDescription`, `ToastAction`,
10
- * `ToastClose`) are used internally by the provider but exported for
11
- * advanced composition.
20
+ * toast('Title')
21
+ * toast.success('Saved')
22
+ * toast.error('Failed', { description: '...' })
23
+ * toast.warning('Heads up')
24
+ * toast.info('Just so you know')
25
+ * toast.message('Plain')
26
+ * toast.loading('Working…')
27
+ * toast.promise(myPromise, {
28
+ * loading: 'Saving…',
29
+ * success: (data) => `Saved ${data.name}`,
30
+ * error: (err) => `Failed: ${err.message}`,
31
+ * })
32
+ * toast.custom((id) => <MyJSX onDismiss={() => toast.dismiss(id)} />)
33
+ * toast.dismiss() // dismiss all
34
+ * toast.dismiss(id) // dismiss one
12
35
  *
13
- * Variants: default, success, error, warning.
14
- * Auto-dismiss after configurable duration (default 5 000 ms).
15
- * Pause timer on hover; resume on mouse leave.
36
+ * Backward-compat shims for the previous imperative MiHCM API are below —
37
+ * `ToastProvider` is a deprecated alias for `Toaster`; the legacy
38
+ * `Toast`/`ToastTitle`/`ToastDescription`/`ToastAction`/`ToastClose`
39
+ * sub-components remain so any pre-sonner consumer keeps rendering.
16
40
  *
17
41
  * Wiki: docs/components/Toast.md
18
42
  */
19
- import { type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from 'react';
43
+ import { type ButtonHTMLAttributes, type ComponentProps, type HTMLAttributes } from 'react';
44
+ import { Toaster as SonnerToaster, toast as sonnerToast } from 'sonner';
20
45
  import { type VariantProps } from 'class-variance-authority';
46
+ /**
47
+ * Imperative toast API. Backed by sonner.
48
+ *
49
+ * @example
50
+ * toast('Saved');
51
+ * toast.success('Profile updated');
52
+ * toast.error('Network error', { description: 'Retrying in 5s…' });
53
+ * toast.loading('Compiling…');
54
+ * toast.promise(savePost(), {
55
+ * loading: 'Saving…',
56
+ * success: 'Saved!',
57
+ * error: 'Save failed',
58
+ * });
59
+ * toast.dismiss(id);
60
+ */
61
+ export declare const toast: typeof sonnerToast;
62
+ export type { ExternalToast, ToastT, ToasterProps } from 'sonner';
63
+ export interface MihcmToasterProps extends ComponentProps<typeof SonnerToaster> {
64
+ /** Default visual treatment for toasts without an explicit appearance. */
65
+ appearance?: 'soft' | 'solid' | 'outline' | 'minimal';
66
+ }
67
+ /**
68
+ * Mount `<Toaster />` once near the root of your app (e.g. in `layout.tsx`).
69
+ * Forwards every prop to sonner's `<Toaster />`; the only addition is the
70
+ * MiHCM token styling applied via `toastOptions.classNames`.
71
+ *
72
+ * @example
73
+ * // app/layout.tsx
74
+ * import { Toaster } from '@mihcm/ui/Toast';
75
+ * <Toaster richColors closeButton position="bottom-right" />
76
+ */
77
+ export declare function Toaster({ position, expand, richColors, closeButton, visibleToasts, duration, theme, toastOptions, className, appearance, ...rest }: MihcmToasterProps): import("react/jsx-runtime").JSX.Element;
78
+ /**
79
+ * @deprecated Use `<Toaster />` instead. Kept as a wrapping component for
80
+ * pre-sonner consumers — renders children, then mounts the Toaster portal.
81
+ */
82
+ export declare function ToastProvider({ children, ...rest }: MihcmToasterProps & {
83
+ children?: React.ReactNode;
84
+ }): import("react/jsx-runtime").JSX.Element;
85
+ export type ToastProviderProps = MihcmToasterProps & {
86
+ children?: React.ReactNode;
87
+ };
21
88
  export declare const toastVariants: (props?: ({
22
89
  variant?: "accent" | "default" | "success" | "warning" | "error" | null | undefined;
23
90
  appearance?: "outline" | "solid" | "soft" | "minimal" | null | undefined;
24
91
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
25
92
  export type ToastVariant = NonNullable<VariantProps<typeof toastVariants>['variant']>;
26
93
  export type ToastAppearance = NonNullable<VariantProps<typeof toastVariants>['appearance']>;
94
+ export interface ToastProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof toastVariants> {
95
+ className?: string;
96
+ }
97
+ /** @deprecated Sonner renders rows internally. Kept for stand-alone use. */
98
+ export declare const Toast: import("react").ForwardRefExoticComponent<ToastProps & import("react").RefAttributes<HTMLDivElement>>;
99
+ /** @deprecated Use sonner's title slot in `toast()` instead. */
100
+ export declare const ToastTitle: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
101
+ /** @deprecated Use sonner's `description` option in `toast()` instead. */
102
+ export declare const ToastDescription: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
103
+ /** @deprecated Use sonner's `action` option in `toast()` instead. */
104
+ export declare const ToastAction: import("react").ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & import("react").RefAttributes<HTMLButtonElement>>;
105
+ /** @deprecated `closeButton` prop on `<Toaster />` renders this automatically. */
106
+ export declare const ToastClose: import("react").ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & import("react").RefAttributes<HTMLButtonElement>>;
107
+ /**
108
+ * Legacy `ToastData` shape kept for typing in any pre-sonner consumer.
109
+ * @deprecated Sonner uses its own `ExternalToast` shape; prefer that.
110
+ */
27
111
  export interface ToastData {
28
112
  id: string;
29
113
  title: string;
@@ -35,38 +119,14 @@ export interface ToastData {
35
119
  label: string;
36
120
  onClick: () => void;
37
121
  };
38
- icon?: ReactNode;
39
- }
40
- export interface ToastProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof toastVariants> {
41
- className?: string;
122
+ icon?: React.ReactNode;
42
123
  }
43
124
  export interface ToastTitleProps extends HTMLAttributes<HTMLDivElement> {
44
- className?: string;
45
125
  }
46
126
  export interface ToastDescriptionProps extends HTMLAttributes<HTMLDivElement> {
47
- className?: string;
48
127
  }
49
128
  export interface ToastActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
50
- className?: string;
51
129
  }
52
130
  export interface ToastCloseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
53
- className?: string;
54
131
  }
55
- export interface ToastProviderProps {
56
- children: ReactNode;
57
- /** Maximum number of visible toasts. @default 5 */
58
- max?: number;
59
- /** Screen corner for the toast stack. */
60
- position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
61
- /** Default visual treatment for toasts without an explicit appearance. */
62
- appearance?: ToastAppearance;
63
- }
64
- /** Imperative API — call from anywhere to show a toast. */
65
- export declare function toast(data: Omit<ToastData, 'id'>): string;
66
- export declare const Toast: import("react").ForwardRefExoticComponent<ToastProps & import("react").RefAttributes<HTMLDivElement>>;
67
- export declare const ToastTitle: import("react").ForwardRefExoticComponent<ToastTitleProps & import("react").RefAttributes<HTMLDivElement>>;
68
- export declare const ToastDescription: import("react").ForwardRefExoticComponent<ToastDescriptionProps & import("react").RefAttributes<HTMLDivElement>>;
69
- export declare const ToastAction: import("react").ForwardRefExoticComponent<ToastActionProps & import("react").RefAttributes<HTMLButtonElement>>;
70
- export declare const ToastClose: import("react").ForwardRefExoticComponent<ToastCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
71
- export declare function ToastProvider({ children, max, position, appearance }: ToastProviderProps): import("react/jsx-runtime").JSX.Element;
72
132
  //# sourceMappingURL=Toast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../src/Toast.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAOL,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAOlE,eAAO,MAAM,aAAa;;;8EAiCzB,CAAC;AAMF,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACtF,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAE5F,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,UAAW,SAAQ,cAAc,CAAC,cAAc,CAAC,EAAE,YAAY,CAAC,OAAO,aAAa,CAAC;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,CAAC;IACpB,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;IACrE,0EAA0E;IAC1E,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAgDD,2DAA2D;AAC3D,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,MAAM,CAOzD;AAoBD,eAAO,MAAM,KAAK,uGAahB,CAAC;AAEH,eAAO,MAAM,UAAU,4GAKrB,CAAC;AAEH,eAAO,MAAM,gBAAgB,kHAI5B,CAAC;AAEF,eAAO,MAAM,WAAW,gHAiBtB,CAAC;AAEH,eAAO,MAAM,UAAU,+GAiCrB,CAAC;AAmGH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAO,EAAE,QAAyB,EAAE,UAAmB,EAAE,EAAE,kBAAkB,2CAiCtH"}
1
+ {"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../src/Toast.tsx"],"names":[],"mappings":"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"}
package/dist/Toast.js CHANGED
@@ -1,31 +1,157 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  /**
4
4
  * Toast (web variant — React DOM).
5
5
  *
6
+ * Built on top of [sonner](https://sonner.emilkowal.ski/) so MiHCM apps get
7
+ * every feature the upstream library ships — promise toasts, loading state,
8
+ * action + cancel buttons, swipe-to-dismiss, hover-to-expand stacks, rich
9
+ * colours per type, theme switching, full a11y wiring — without forking.
10
+ *
11
+ * Surface is themed with MiHCM tokens (`bg-card`, `border-border`,
12
+ * `text-foreground`, `text-success-foreground`, etc.) via sonner's
13
+ * `toastOptions.classNames` so the toasts read as part of the rest of the
14
+ * design system regardless of light/dark mode or custom `colorScheme`s.
15
+ *
6
16
  * Two-part API:
7
- * 1. `<ToastProvider>` wraps your app, manages the queue, renders toasts
8
- * in a fixed container at bottom-right.
9
- * 2. `toast()` imperative function — call from anywhere to show a toast.
17
+ * 1. `<Toaster />` mount once near the app root. It renders the queue
18
+ * in a portal at the chosen `position`. Pass `richColors`, `expand`,
19
+ * `closeButton`, `visibleToasts`, `theme`, etc. to tune behaviour.
20
+ * 2. `toast()` — call from anywhere to enqueue. Sub-APIs:
10
21
  *
11
- * Sub-components (`Toast`, `ToastTitle`, `ToastDescription`, `ToastAction`,
12
- * `ToastClose`) are used internally by the provider but exported for
13
- * advanced composition.
22
+ * toast('Title')
23
+ * toast.success('Saved')
24
+ * toast.error('Failed', { description: '...' })
25
+ * toast.warning('Heads up')
26
+ * toast.info('Just so you know')
27
+ * toast.message('Plain')
28
+ * toast.loading('Working…')
29
+ * toast.promise(myPromise, {
30
+ * loading: 'Saving…',
31
+ * success: (data) => `Saved ${data.name}`,
32
+ * error: (err) => `Failed: ${err.message}`,
33
+ * })
34
+ * toast.custom((id) => <MyJSX onDismiss={() => toast.dismiss(id)} />)
35
+ * toast.dismiss() // dismiss all
36
+ * toast.dismiss(id) // dismiss one
14
37
  *
15
- * Variants: default, success, error, warning.
16
- * Auto-dismiss after configurable duration (default 5 000 ms).
17
- * Pause timer on hover; resume on mouse leave.
38
+ * Backward-compat shims for the previous imperative MiHCM API are below —
39
+ * `ToastProvider` is a deprecated alias for `Toaster`; the legacy
40
+ * `Toast`/`ToastTitle`/`ToastDescription`/`ToastAction`/`ToastClose`
41
+ * sub-components remain so any pre-sonner consumer keeps rendering.
18
42
  *
19
43
  * Wiki: docs/components/Toast.md
20
44
  */
21
- import { forwardRef, useCallback, useEffect, useRef, useState, useSyncExternalStore, } from 'react';
45
+ import { forwardRef, } from 'react';
46
+ import { Toaster as SonnerToaster, toast as sonnerToast } from 'sonner';
22
47
  import { cva } from 'class-variance-authority';
23
48
  import { cn } from './internal/cn.js';
24
49
  /* -------------------------------------------------------------------------- */
25
- /* CVA variants */
50
+ /* Re-exports — the canonical sonner API */
51
+ /* -------------------------------------------------------------------------- */
52
+ /**
53
+ * Imperative toast API. Backed by sonner.
54
+ *
55
+ * @example
56
+ * toast('Saved');
57
+ * toast.success('Profile updated');
58
+ * toast.error('Network error', { description: 'Retrying in 5s…' });
59
+ * toast.loading('Compiling…');
60
+ * toast.promise(savePost(), {
61
+ * loading: 'Saving…',
62
+ * success: 'Saved!',
63
+ * error: 'Save failed',
64
+ * });
65
+ * toast.dismiss(id);
66
+ */
67
+ export const toast = sonnerToast;
68
+ /**
69
+ * Mount `<Toaster />` once near the root of your app (e.g. in `layout.tsx`).
70
+ * Forwards every prop to sonner's `<Toaster />`; the only addition is the
71
+ * MiHCM token styling applied via `toastOptions.classNames`.
72
+ *
73
+ * @example
74
+ * // app/layout.tsx
75
+ * import { Toaster } from '@mihcm/ui/Toast';
76
+ * <Toaster richColors closeButton position="bottom-right" />
77
+ */
78
+ export function Toaster({ position = 'bottom-right', expand = false, richColors = false, closeButton = false, visibleToasts = 3, duration = 5000, theme = 'system', toastOptions, className, appearance, ...rest }) {
79
+ void appearance; /* reserved — sonner already handles visual variants via richColors */
80
+ /*
81
+ * Sonner injects its own CSS that uses these variables to colour each
82
+ * row. By mapping them to MiHCM design-system tokens here, the surface,
83
+ * border, and type tints inherit the brand palette AND light/dark mode
84
+ * flips automatically — no need to fight specificity with Tailwind.
85
+ */
86
+ const sonnerCssVars = {
87
+ '--normal-bg': 'var(--color-card)',
88
+ '--normal-text': 'var(--color-card-foreground)',
89
+ '--normal-border': 'var(--color-border)',
90
+ '--success-bg': 'var(--color-success-50, color-mix(in oklab, var(--color-success) 12%, var(--color-card)))',
91
+ '--success-text': 'var(--color-success-700, var(--color-success))',
92
+ '--success-border': 'var(--color-success)',
93
+ '--error-bg': 'var(--color-destructive-50, color-mix(in oklab, var(--color-destructive) 12%, var(--color-card)))',
94
+ '--error-text': 'var(--color-destructive-700, var(--color-destructive))',
95
+ '--error-border': 'var(--color-destructive)',
96
+ '--warning-bg': 'var(--color-warning-50, color-mix(in oklab, var(--color-warning) 12%, var(--color-card)))',
97
+ '--warning-text': 'var(--color-warning-700, var(--color-warning))',
98
+ '--warning-border': 'var(--color-warning)',
99
+ '--info-bg': 'var(--color-primary-50, color-mix(in oklab, var(--color-primary) 12%, var(--color-card)))',
100
+ '--info-text': 'var(--color-primary-700, var(--color-primary))',
101
+ '--info-border': 'var(--color-primary)',
102
+ };
103
+ return (_jsx(SonnerToaster, { position: position, expand: expand, richColors: richColors, closeButton: closeButton, visibleToasts: visibleToasts, duration: duration, theme: theme, className: cn('mihcm-toaster', className), style: { ...sonnerCssVars, ...(rest.style ?? {}) }, toastOptions: {
104
+ ...toastOptions,
105
+ classNames: {
106
+ /*
107
+ * Surface — the toast row itself. Polished default look:
108
+ * - bg-card / text-card-foreground (theme-aware)
109
+ * - shadow-mi-modal for a soft floating elevation
110
+ * - rounded-xl + slightly bigger padding for a modern feel
111
+ * - ring-1 ring-border for crisp edge separation in light mode
112
+ * (the border-border on its own can look washed out)
113
+ * - max-width capped so long messages don't sprawl
114
+ */
115
+ toast: cn('group toast pointer-events-auto flex w-full items-start gap-3 rounded-xl border border-border bg-card p-4 pr-12', 'text-card-foreground shadow-mi-modal ring-1 ring-border/40', toastOptions?.classNames?.toast),
116
+ title: cn('text-sm font-semibold leading-snug text-foreground', toastOptions?.classNames?.title),
117
+ description: cn('text-sm text-muted-foreground leading-snug', toastOptions?.classNames?.description),
118
+ actionButton: cn('inline-flex shrink-0 items-center rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', toastOptions?.classNames?.actionButton),
119
+ cancelButton: cn('inline-flex shrink-0 items-center rounded-md border border-border bg-transparent px-3 py-1 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', toastOptions?.classNames?.cancelButton),
120
+ closeButton: cn('absolute right-2 top-2 grid size-6 place-items-center rounded-md border border-transparent bg-transparent text-foreground/60 transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', toastOptions?.classNames?.closeButton),
121
+ icon: cn('mt-0.5 shrink-0 [&_svg]:size-5', toastOptions?.classNames?.icon),
122
+ /*
123
+ * Per-type styling — sonner adds `data-type="success|error|…"`
124
+ * to the toast root. Use richColors-like surface treatment so
125
+ * tone is unmistakeable even without sonner's own richColors
126
+ * (which forces hard-coded colours).
127
+ */
128
+ default: cn('border-border bg-card text-card-foreground', toastOptions?.classNames?.default),
129
+ success: cn('border-success/30 bg-success/10 text-foreground [&_[data-icon]]:text-success', toastOptions?.classNames?.success),
130
+ error: cn('border-destructive/30 bg-destructive/10 text-foreground [&_[data-icon]]:text-destructive', toastOptions?.classNames?.error),
131
+ warning: cn('border-warning/30 bg-warning/10 text-foreground [&_[data-icon]]:text-warning', toastOptions?.classNames?.warning),
132
+ info: cn('border-primary/30 bg-primary/10 text-foreground [&_[data-icon]]:text-primary', toastOptions?.classNames?.info),
133
+ loading: cn('border-border bg-card text-foreground', toastOptions?.classNames?.loading),
134
+ },
135
+ }, ...rest }));
136
+ }
137
+ /* -------------------------------------------------------------------------- */
138
+ /* Backward-compat layer */
139
+ /* */
140
+ /* The previous MiHCM Toast API exported `ToastProvider`, `Toast`, */
141
+ /* `ToastTitle`, `ToastDescription`, `ToastAction`, `ToastClose`. Keep them */
142
+ /* as thin shims so existing call sites stay green. New code should import */
143
+ /* `Toaster` + `toast` only. */
26
144
  /* -------------------------------------------------------------------------- */
27
- export const toastVariants = cva('pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-lg border p-4 shadow-lg ' +
28
- 'transition-all duration-300 ease-out', {
145
+ /**
146
+ * @deprecated Use `<Toaster />` instead. Kept as a wrapping component for
147
+ * pre-sonner consumers — renders children, then mounts the Toaster portal.
148
+ */
149
+ export function ToastProvider({ children, ...rest }) {
150
+ return (_jsxs(_Fragment, { children: [children, _jsx(Toaster, { ...rest })] }));
151
+ }
152
+ /* The original `toastVariants` CVA — kept for any consumer that referenced
153
+ * its variant union types or used it to style a stand-alone Toast row. */
154
+ export const toastVariants = cva('pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-lg border p-4 shadow-lg transition-all duration-300 ease-out', {
29
155
  variants: {
30
156
  variant: {
31
157
  default: 'border-border bg-card text-foreground',
@@ -55,140 +181,24 @@ export const toastVariants = cva('pointer-events-auto relative flex w-full items
55
181
  ],
56
182
  defaultVariants: { variant: 'default', appearance: 'soft' },
57
183
  });
58
- const STORE_KEY = '__mihcm_toast_store__';
59
- function getStore() {
60
- const g = globalThis;
61
- if (!g[STORE_KEY]) {
62
- g[STORE_KEY] = { toasts: [], listeners: new Set(), viewports: new Set(), counter: 0, viewportCounter: 0 };
63
- }
64
- return g[STORE_KEY];
65
- }
66
- function notify() {
67
- for (const l of getStore().listeners)
68
- l();
69
- }
70
- function getSnapshot() {
71
- return getStore().toasts;
72
- }
73
- function getViewportSnapshot() {
74
- return Array.from(getStore().viewports).at(-1);
75
- }
76
- function subscribe(listener) {
77
- const store = getStore();
78
- store.listeners.add(listener);
79
- return () => store.listeners.delete(listener);
80
- }
81
- /** Imperative API — call from anywhere to show a toast. */
82
- export function toast(data) {
83
- const store = getStore();
84
- const id = `toast-${++store.counter}-${Date.now()}`;
85
- const entry = { id, ...data };
86
- store.toasts = [...store.toasts, entry];
87
- notify();
88
- return id;
89
- }
90
- function dismiss(id) {
91
- const store = getStore();
92
- store.toasts = store.toasts.filter((t) => t.id !== id);
93
- notify();
94
- }
95
- /* -------------------------------------------------------------------------- */
96
- /* Sub-components */
97
- /* -------------------------------------------------------------------------- */
98
- const ACCENT = {
99
- default: 'border-l-border',
100
- success: 'border-l-success',
101
- error: 'border-l-destructive',
102
- warning: 'border-l-warning',
103
- accent: 'border-l-accent',
104
- };
184
+ /** @deprecated Sonner renders rows internally. Kept for stand-alone use. */
105
185
  export const Toast = forwardRef(function Toast({ className, variant = 'default', appearance = 'soft', children, ...props }, ref) {
106
- return (_jsx("div", { ref: ref, className: cn(toastVariants({ variant, appearance }), 'border-l-4', ACCENT[variant ?? 'default'], className), ...props, children: children }));
186
+ return (_jsx("div", { ref: ref, className: cn(toastVariants({ variant, appearance }), className), ...props, children: children }));
107
187
  });
188
+ /** @deprecated Use sonner's title slot in `toast()` instead. */
108
189
  export const ToastTitle = forwardRef(function ToastTitle({ className, ...props }, ref) {
109
190
  return _jsx("div", { ref: ref, className: cn('text-sm font-semibold', className), ...props });
110
191
  });
192
+ /** @deprecated Use sonner's `description` option in `toast()` instead. */
111
193
  export const ToastDescription = forwardRef(function ToastDescription({ className, ...props }, ref) {
112
194
  return _jsx("div", { ref: ref, className: cn('text-sm text-muted-foreground', className), ...props });
113
195
  });
196
+ /** @deprecated Use sonner's `action` option in `toast()` instead. */
114
197
  export const ToastAction = forwardRef(function ToastAction({ className, ...props }, ref) {
115
- return (_jsx("button", { ref: ref, type: "button", className: cn('inline-flex shrink-0 items-center rounded-md border border-border bg-transparent px-3 py-1 ' +
116
- 'text-sm font-medium transition-colors duration-150 hover:bg-muted focus-visible:outline-none ' +
117
- 'focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', className), ...props }));
198
+ return (_jsx("button", { ref: ref, type: "button", className: cn('inline-flex shrink-0 items-center rounded-md border border-border bg-transparent px-3 py-1 text-sm font-medium transition-colors duration-150 hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', className), ...props }));
118
199
  });
200
+ /** @deprecated `closeButton` prop on `<Toaster />` renders this automatically. */
119
201
  export const ToastClose = forwardRef(function ToastClose({ className, ...props }, ref) {
120
- return (_jsx("button", { ref: ref, type: "button", "aria-label": "Close", className: cn('absolute right-2 top-2 rounded-md p-1 text-foreground/50 transition-opacity hover:text-foreground ' +
121
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', className), ...props, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [_jsx("path", { d: "M18 6 6 18" }), _jsx("path", { d: "m6 6 12 12" })] }) }));
202
+ return (_jsx("button", { ref: ref, type: "button", "aria-label": "Close", className: cn('absolute right-2 top-2 rounded-md p-1 text-foreground/50 transition-opacity hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', className), ...props, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [_jsx("path", { d: "M18 6 6 18" }), _jsx("path", { d: "m6 6 12 12" })] }) }));
122
203
  });
123
- /* -------------------------------------------------------------------------- */
124
- /* Individual toast item (manages timer + animation) */
125
- /* -------------------------------------------------------------------------- */
126
- const DEFAULT_DURATION = 5000;
127
- function ToastItem({ data, onDismiss, appearance, }) {
128
- const [visible, setVisible] = useState(false);
129
- const [exiting, setExiting] = useState(false);
130
- const timerRef = useRef(undefined);
131
- const remainingRef = useRef(data.duration ?? DEFAULT_DURATION);
132
- // eslint-disable-next-line react-hooks/purity -- initial value only, never re-read during render
133
- const startRef = useRef(Date.now());
134
- const startTimer = useCallback(() => {
135
- startRef.current = Date.now();
136
- timerRef.current = setTimeout(() => {
137
- setExiting(true);
138
- setTimeout(() => onDismiss(data.id), 300);
139
- }, remainingRef.current);
140
- }, [data.id, onDismiss]);
141
- const pauseTimer = useCallback(() => {
142
- if (timerRef.current) {
143
- clearTimeout(timerRef.current);
144
- remainingRef.current -= Date.now() - startRef.current;
145
- if (remainingRef.current < 0)
146
- remainingRef.current = 0;
147
- }
148
- }, []);
149
- useEffect(() => {
150
- // Trigger entry animation on next frame
151
- const raf = requestAnimationFrame(() => setVisible(true));
152
- startTimer();
153
- return () => {
154
- cancelAnimationFrame(raf);
155
- if (timerRef.current)
156
- clearTimeout(timerRef.current);
157
- };
158
- }, [startTimer]);
159
- const handleClose = () => {
160
- if (timerRef.current)
161
- clearTimeout(timerRef.current);
162
- setExiting(true);
163
- setTimeout(() => onDismiss(data.id), 300);
164
- };
165
- const isError = data.variant === 'error';
166
- return (_jsx("div", { role: "status", "aria-live": isError ? 'assertive' : 'polite', className: cn('transform transition-all duration-300', visible && !exiting ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'), onMouseEnter: pauseTimer, onMouseLeave: startTimer, children: _jsxs(Toast, { variant: data.variant, appearance: data.appearance ?? appearance, children: [data.icon ? _jsx("div", { className: "mt-0.5 shrink-0 text-muted-foreground", children: data.icon }) : null, _jsxs("div", { className: "flex-1 space-y-1 pr-6", children: [_jsx(ToastTitle, { children: data.title }), data.description !== undefined && (_jsx(ToastDescription, { children: data.description })), data.action !== undefined && (_jsx("div", { className: "mt-2", children: _jsx(ToastAction, { onClick: data.action.onClick, children: data.action.label }) }))] }), _jsx(ToastClose, { onClick: handleClose })] }) }));
167
- }
168
- /* -------------------------------------------------------------------------- */
169
- /* ToastProvider */
170
- /* -------------------------------------------------------------------------- */
171
- const POSITION_CLASS = {
172
- 'bottom-right': 'bottom-4 right-4',
173
- 'bottom-left': 'bottom-4 left-4',
174
- 'top-right': 'right-4 top-4',
175
- 'top-left': 'left-4 top-4',
176
- };
177
- export function ToastProvider({ children, max = 5, position = 'bottom-right', appearance = 'soft' }) {
178
- const [viewportId] = useState(() => ++getStore().viewportCounter);
179
- useEffect(() => {
180
- const store = getStore();
181
- store.viewports.add(viewportId);
182
- notify();
183
- return () => {
184
- store.viewports.delete(viewportId);
185
- notify();
186
- };
187
- }, [viewportId]);
188
- const items = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
189
- const activeViewportId = useSyncExternalStore(subscribe, getViewportSnapshot, () => undefined);
190
- const visible = items.slice(-max);
191
- const isActiveViewport = viewportId === activeViewportId;
192
- return (_jsxs(_Fragment, { children: [children, isActiveViewport ? (_jsx("div", { "aria-label": "Notifications", className: cn('pointer-events-none fixed z-[100] flex max-w-[420px] flex-col gap-2', POSITION_CLASS[position]), children: visible.map((t) => (_jsx(ToastItem, { data: t, onDismiss: dismiss, appearance: appearance }, t.id))) })) : null] }));
193
- }
194
204
  //# sourceMappingURL=Toast.js.map
package/dist/Toast.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Toast.js","sourceRoot":"","sources":["../src/Toast.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Toast.js","sourceRoot":"","sources":["../src/Toast.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mihcm/ui",
3
- "version": "0.15.1",
3
+ "version": "0.16.0",
4
4
  "description": "Universal primitives (Button, Input, ...) for React, Next.js, and React Native. Tailwind 4 + NativeWind v5.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -454,6 +454,7 @@
454
454
  "react-resizable-panels": "4.11.1",
455
455
  "react-select": "^5.10.2",
456
456
  "recharts": "^3.8.1",
457
+ "sonner": "2.0.7",
457
458
  "tailwind-merge": "^3.6.0",
458
459
  "tailwind-variants": "3.2.2",
459
460
  "vaul": "1.1.2",
package/src/Toast.tsx CHANGED
@@ -3,42 +3,250 @@
3
3
  /**
4
4
  * Toast (web variant — React DOM).
5
5
  *
6
+ * Built on top of [sonner](https://sonner.emilkowal.ski/) so MiHCM apps get
7
+ * every feature the upstream library ships — promise toasts, loading state,
8
+ * action + cancel buttons, swipe-to-dismiss, hover-to-expand stacks, rich
9
+ * colours per type, theme switching, full a11y wiring — without forking.
10
+ *
11
+ * Surface is themed with MiHCM tokens (`bg-card`, `border-border`,
12
+ * `text-foreground`, `text-success-foreground`, etc.) via sonner's
13
+ * `toastOptions.classNames` so the toasts read as part of the rest of the
14
+ * design system regardless of light/dark mode or custom `colorScheme`s.
15
+ *
6
16
  * Two-part API:
7
- * 1. `<ToastProvider>` wraps your app, manages the queue, renders toasts
8
- * in a fixed container at bottom-right.
9
- * 2. `toast()` imperative function — call from anywhere to show a toast.
17
+ * 1. `<Toaster />` mount once near the app root. It renders the queue
18
+ * in a portal at the chosen `position`. Pass `richColors`, `expand`,
19
+ * `closeButton`, `visibleToasts`, `theme`, etc. to tune behaviour.
20
+ * 2. `toast()` — call from anywhere to enqueue. Sub-APIs:
10
21
  *
11
- * Sub-components (`Toast`, `ToastTitle`, `ToastDescription`, `ToastAction`,
12
- * `ToastClose`) are used internally by the provider but exported for
13
- * advanced composition.
22
+ * toast('Title')
23
+ * toast.success('Saved')
24
+ * toast.error('Failed', { description: '...' })
25
+ * toast.warning('Heads up')
26
+ * toast.info('Just so you know')
27
+ * toast.message('Plain')
28
+ * toast.loading('Working…')
29
+ * toast.promise(myPromise, {
30
+ * loading: 'Saving…',
31
+ * success: (data) => `Saved ${data.name}`,
32
+ * error: (err) => `Failed: ${err.message}`,
33
+ * })
34
+ * toast.custom((id) => <MyJSX onDismiss={() => toast.dismiss(id)} />)
35
+ * toast.dismiss() // dismiss all
36
+ * toast.dismiss(id) // dismiss one
14
37
  *
15
- * Variants: default, success, error, warning.
16
- * Auto-dismiss after configurable duration (default 5 000 ms).
17
- * Pause timer on hover; resume on mouse leave.
38
+ * Backward-compat shims for the previous imperative MiHCM API are below —
39
+ * `ToastProvider` is a deprecated alias for `Toaster`; the legacy
40
+ * `Toast`/`ToastTitle`/`ToastDescription`/`ToastAction`/`ToastClose`
41
+ * sub-components remain so any pre-sonner consumer keeps rendering.
18
42
  *
19
43
  * Wiki: docs/components/Toast.md
20
44
  */
21
45
  import {
22
46
  forwardRef,
23
- useCallback,
24
- useEffect,
25
- useRef,
26
- useState,
27
- useSyncExternalStore,
28
47
  type ButtonHTMLAttributes,
48
+ type ComponentProps,
29
49
  type HTMLAttributes,
30
- type ReactNode,
31
50
  } from 'react';
51
+ import { Toaster as SonnerToaster, toast as sonnerToast } from 'sonner';
32
52
  import { cva, type VariantProps } from 'class-variance-authority';
33
53
  import { cn } from './internal/cn.js';
34
54
 
35
55
  /* -------------------------------------------------------------------------- */
36
- /* CVA variants */
56
+ /* Re-exports — the canonical sonner API */
57
+ /* -------------------------------------------------------------------------- */
58
+
59
+ /**
60
+ * Imperative toast API. Backed by sonner.
61
+ *
62
+ * @example
63
+ * toast('Saved');
64
+ * toast.success('Profile updated');
65
+ * toast.error('Network error', { description: 'Retrying in 5s…' });
66
+ * toast.loading('Compiling…');
67
+ * toast.promise(savePost(), {
68
+ * loading: 'Saving…',
69
+ * success: 'Saved!',
70
+ * error: 'Save failed',
71
+ * });
72
+ * toast.dismiss(id);
73
+ */
74
+ export const toast: typeof sonnerToast = sonnerToast;
75
+
76
+ export type { ExternalToast, ToastT, ToasterProps } from 'sonner';
77
+
78
+ /* -------------------------------------------------------------------------- */
79
+ /* Toaster — themed wrapper around sonner's <Toaster /> */
80
+ /* -------------------------------------------------------------------------- */
81
+
82
+ export interface MihcmToasterProps extends ComponentProps<typeof SonnerToaster> {
83
+ /** Default visual treatment for toasts without an explicit appearance. */
84
+ appearance?: 'soft' | 'solid' | 'outline' | 'minimal';
85
+ }
86
+
87
+ /**
88
+ * Mount `<Toaster />` once near the root of your app (e.g. in `layout.tsx`).
89
+ * Forwards every prop to sonner's `<Toaster />`; the only addition is the
90
+ * MiHCM token styling applied via `toastOptions.classNames`.
91
+ *
92
+ * @example
93
+ * // app/layout.tsx
94
+ * import { Toaster } from '@mihcm/ui/Toast';
95
+ * <Toaster richColors closeButton position="bottom-right" />
96
+ */
97
+ export function Toaster({
98
+ position = 'bottom-right',
99
+ expand = false,
100
+ richColors = false,
101
+ closeButton = false,
102
+ visibleToasts = 3,
103
+ duration = 5000,
104
+ theme = 'system',
105
+ toastOptions,
106
+ className,
107
+ appearance,
108
+ ...rest
109
+ }: MihcmToasterProps) {
110
+ void appearance; /* reserved — sonner already handles visual variants via richColors */
111
+
112
+ /*
113
+ * Sonner injects its own CSS that uses these variables to colour each
114
+ * row. By mapping them to MiHCM design-system tokens here, the surface,
115
+ * border, and type tints inherit the brand palette AND light/dark mode
116
+ * flips automatically — no need to fight specificity with Tailwind.
117
+ */
118
+ const sonnerCssVars = {
119
+ '--normal-bg': 'var(--color-card)',
120
+ '--normal-text': 'var(--color-card-foreground)',
121
+ '--normal-border': 'var(--color-border)',
122
+ '--success-bg': 'var(--color-success-50, color-mix(in oklab, var(--color-success) 12%, var(--color-card)))',
123
+ '--success-text': 'var(--color-success-700, var(--color-success))',
124
+ '--success-border': 'var(--color-success)',
125
+ '--error-bg': 'var(--color-destructive-50, color-mix(in oklab, var(--color-destructive) 12%, var(--color-card)))',
126
+ '--error-text': 'var(--color-destructive-700, var(--color-destructive))',
127
+ '--error-border': 'var(--color-destructive)',
128
+ '--warning-bg': 'var(--color-warning-50, color-mix(in oklab, var(--color-warning) 12%, var(--color-card)))',
129
+ '--warning-text': 'var(--color-warning-700, var(--color-warning))',
130
+ '--warning-border': 'var(--color-warning)',
131
+ '--info-bg': 'var(--color-primary-50, color-mix(in oklab, var(--color-primary) 12%, var(--color-card)))',
132
+ '--info-text': 'var(--color-primary-700, var(--color-primary))',
133
+ '--info-border': 'var(--color-primary)',
134
+ } as React.CSSProperties;
135
+
136
+ return (
137
+ <SonnerToaster
138
+ position={position}
139
+ expand={expand}
140
+ richColors={richColors}
141
+ closeButton={closeButton}
142
+ visibleToasts={visibleToasts}
143
+ duration={duration}
144
+ theme={theme}
145
+ className={cn('mihcm-toaster', className)}
146
+ style={{ ...sonnerCssVars, ...(rest.style ?? {}) }}
147
+ toastOptions={{
148
+ ...toastOptions,
149
+ classNames: {
150
+ /*
151
+ * Surface — the toast row itself. Polished default look:
152
+ * - bg-card / text-card-foreground (theme-aware)
153
+ * - shadow-mi-modal for a soft floating elevation
154
+ * - rounded-xl + slightly bigger padding for a modern feel
155
+ * - ring-1 ring-border for crisp edge separation in light mode
156
+ * (the border-border on its own can look washed out)
157
+ * - max-width capped so long messages don't sprawl
158
+ */
159
+ toast: cn(
160
+ 'group toast pointer-events-auto flex w-full items-start gap-3 rounded-xl border border-border bg-card p-4 pr-12',
161
+ 'text-card-foreground shadow-mi-modal ring-1 ring-border/40',
162
+ toastOptions?.classNames?.toast,
163
+ ),
164
+ title: cn('text-sm font-semibold leading-snug text-foreground', toastOptions?.classNames?.title),
165
+ description: cn(
166
+ 'text-sm text-muted-foreground leading-snug',
167
+ toastOptions?.classNames?.description,
168
+ ),
169
+ actionButton: cn(
170
+ 'inline-flex shrink-0 items-center rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
171
+ toastOptions?.classNames?.actionButton,
172
+ ),
173
+ cancelButton: cn(
174
+ 'inline-flex shrink-0 items-center rounded-md border border-border bg-transparent px-3 py-1 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
175
+ toastOptions?.classNames?.cancelButton,
176
+ ),
177
+ closeButton: cn(
178
+ 'absolute right-2 top-2 grid size-6 place-items-center rounded-md border border-transparent bg-transparent text-foreground/60 transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
179
+ toastOptions?.classNames?.closeButton,
180
+ ),
181
+ icon: cn(
182
+ 'mt-0.5 shrink-0 [&_svg]:size-5',
183
+ toastOptions?.classNames?.icon,
184
+ ),
185
+ /*
186
+ * Per-type styling — sonner adds `data-type="success|error|…"`
187
+ * to the toast root. Use richColors-like surface treatment so
188
+ * tone is unmistakeable even without sonner's own richColors
189
+ * (which forces hard-coded colours).
190
+ */
191
+ default: cn('border-border bg-card text-card-foreground', toastOptions?.classNames?.default),
192
+ success: cn(
193
+ 'border-success/30 bg-success/10 text-foreground [&_[data-icon]]:text-success',
194
+ toastOptions?.classNames?.success,
195
+ ),
196
+ error: cn(
197
+ 'border-destructive/30 bg-destructive/10 text-foreground [&_[data-icon]]:text-destructive',
198
+ toastOptions?.classNames?.error,
199
+ ),
200
+ warning: cn(
201
+ 'border-warning/30 bg-warning/10 text-foreground [&_[data-icon]]:text-warning',
202
+ toastOptions?.classNames?.warning,
203
+ ),
204
+ info: cn(
205
+ 'border-primary/30 bg-primary/10 text-foreground [&_[data-icon]]:text-primary',
206
+ toastOptions?.classNames?.info,
207
+ ),
208
+ loading: cn(
209
+ 'border-border bg-card text-foreground',
210
+ toastOptions?.classNames?.loading,
211
+ ),
212
+ },
213
+ }}
214
+ {...rest}
215
+ />
216
+ );
217
+ }
218
+
219
+ /* -------------------------------------------------------------------------- */
220
+ /* Backward-compat layer */
221
+ /* */
222
+ /* The previous MiHCM Toast API exported `ToastProvider`, `Toast`, */
223
+ /* `ToastTitle`, `ToastDescription`, `ToastAction`, `ToastClose`. Keep them */
224
+ /* as thin shims so existing call sites stay green. New code should import */
225
+ /* `Toaster` + `toast` only. */
37
226
  /* -------------------------------------------------------------------------- */
38
227
 
228
+ /**
229
+ * @deprecated Use `<Toaster />` instead. Kept as a wrapping component for
230
+ * pre-sonner consumers — renders children, then mounts the Toaster portal.
231
+ */
232
+ export function ToastProvider({
233
+ children,
234
+ ...rest
235
+ }: MihcmToasterProps & { children?: React.ReactNode }) {
236
+ return (
237
+ <>
238
+ {children}
239
+ <Toaster {...rest} />
240
+ </>
241
+ );
242
+ }
243
+
244
+ export type ToastProviderProps = MihcmToasterProps & { children?: React.ReactNode };
245
+
246
+ /* The original `toastVariants` CVA — kept for any consumer that referenced
247
+ * its variant union types or used it to style a stand-alone Toast row. */
39
248
  export const toastVariants = cva(
40
- 'pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-lg border p-4 shadow-lg ' +
41
- 'transition-all duration-300 ease-out',
249
+ 'pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-lg border p-4 shadow-lg transition-all duration-300 ease-out',
42
250
  {
43
251
  variants: {
44
252
  variant: {
@@ -71,338 +279,106 @@ export const toastVariants = cva(
71
279
  },
72
280
  );
73
281
 
74
- /* -------------------------------------------------------------------------- */
75
- /* Types */
76
- /* -------------------------------------------------------------------------- */
77
-
78
282
  export type ToastVariant = NonNullable<VariantProps<typeof toastVariants>['variant']>;
79
283
  export type ToastAppearance = NonNullable<VariantProps<typeof toastVariants>['appearance']>;
80
284
 
81
- export interface ToastData {
82
- id: string;
83
- title: string;
84
- description?: string;
85
- variant?: ToastVariant;
86
- appearance?: ToastAppearance;
87
- duration?: number;
88
- action?: { label: string; onClick: () => void };
89
- icon?: ReactNode;
90
- }
91
-
92
285
  export interface ToastProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof toastVariants> {
93
286
  className?: string;
94
287
  }
95
288
 
96
- export interface ToastTitleProps extends HTMLAttributes<HTMLDivElement> {
97
- className?: string;
98
- }
99
-
100
- export interface ToastDescriptionProps extends HTMLAttributes<HTMLDivElement> {
101
- className?: string;
102
- }
103
-
104
- export interface ToastActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
105
- className?: string;
106
- }
107
-
108
- export interface ToastCloseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
109
- className?: string;
110
- }
111
-
112
- export interface ToastProviderProps {
113
- children: ReactNode;
114
- /** Maximum number of visible toasts. @default 5 */
115
- max?: number;
116
- /** Screen corner for the toast stack. */
117
- position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
118
- /** Default visual treatment for toasts without an explicit appearance. */
119
- appearance?: ToastAppearance;
120
- }
121
-
122
- /* -------------------------------------------------------------------------- */
123
- /* Global singleton store */
124
- /* */
125
- /* Bundlers that transpile this package (e.g. Next.js `transpilePackages`) */
126
- /* may create multiple module instances. Using `globalThis` ensures toast() */
127
- /* and ToastProvider always share the same queue, even across chunks. */
128
- /* -------------------------------------------------------------------------- */
129
-
130
- type Listener = () => void;
131
-
132
- interface ToastStore {
133
- toasts: ToastData[];
134
- listeners: Set<Listener>;
135
- viewports: Set<number>;
136
- counter: number;
137
- viewportCounter: number;
138
- }
139
-
140
- const STORE_KEY = '__mihcm_toast_store__';
141
-
142
- function getStore(): ToastStore {
143
- const g = globalThis as unknown as Record<string, ToastStore>;
144
- if (!g[STORE_KEY]) {
145
- g[STORE_KEY] = { toasts: [], listeners: new Set(), viewports: new Set(), counter: 0, viewportCounter: 0 };
146
- }
147
- return g[STORE_KEY];
148
- }
149
-
150
- function notify() {
151
- for (const l of getStore().listeners) l();
152
- }
153
-
154
- function getSnapshot(): ToastData[] {
155
- return getStore().toasts;
156
- }
157
-
158
- function getViewportSnapshot(): number | undefined {
159
- return Array.from(getStore().viewports).at(-1);
160
- }
161
-
162
- function subscribe(listener: Listener): () => void {
163
- const store = getStore();
164
- store.listeners.add(listener);
165
- return () => store.listeners.delete(listener);
166
- }
167
-
168
- /** Imperative API — call from anywhere to show a toast. */
169
- export function toast(data: Omit<ToastData, 'id'>): string {
170
- const store = getStore();
171
- const id = `toast-${++store.counter}-${Date.now()}`;
172
- const entry: ToastData = { id, ...data };
173
- store.toasts = [...store.toasts, entry];
174
- notify();
175
- return id;
176
- }
177
-
178
- function dismiss(id: string) {
179
- const store = getStore();
180
- store.toasts = store.toasts.filter((t) => t.id !== id);
181
- notify();
182
- }
183
-
184
- /* -------------------------------------------------------------------------- */
185
- /* Sub-components */
186
- /* -------------------------------------------------------------------------- */
187
-
188
- const ACCENT: Record<ToastVariant, string> = {
189
- default: 'border-l-border',
190
- success: 'border-l-success',
191
- error: 'border-l-destructive',
192
- warning: 'border-l-warning',
193
- accent: 'border-l-accent',
194
- };
195
-
289
+ /** @deprecated Sonner renders rows internally. Kept for stand-alone use. */
196
290
  export const Toast = forwardRef<HTMLDivElement, ToastProps>(function Toast(
197
291
  { className, variant = 'default', appearance = 'soft', children, ...props },
198
292
  ref,
199
293
  ) {
200
294
  return (
201
- <div
202
- ref={ref}
203
- className={cn(toastVariants({ variant, appearance }), 'border-l-4', ACCENT[variant ?? 'default'], className)}
204
- {...props}
205
- >
295
+ <div ref={ref} className={cn(toastVariants({ variant, appearance }), className)} {...props}>
206
296
  {children}
207
297
  </div>
208
298
  );
209
299
  });
210
300
 
211
- export const ToastTitle = forwardRef<HTMLDivElement, ToastTitleProps>(function ToastTitle(
212
- { className, ...props },
213
- ref,
214
- ) {
215
- return <div ref={ref} className={cn('text-sm font-semibold', className)} {...props} />;
216
- });
301
+ /** @deprecated Use sonner's title slot in `toast()` instead. */
302
+ export const ToastTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
303
+ function ToastTitle({ className, ...props }, ref) {
304
+ return <div ref={ref} className={cn('text-sm font-semibold', className)} {...props} />;
305
+ },
306
+ );
217
307
 
218
- export const ToastDescription = forwardRef<HTMLDivElement, ToastDescriptionProps>(
308
+ /** @deprecated Use sonner's `description` option in `toast()` instead. */
309
+ export const ToastDescription = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
219
310
  function ToastDescription({ className, ...props }, ref) {
220
311
  return <div ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />;
221
312
  },
222
313
  );
223
314
 
224
- export const ToastAction = forwardRef<HTMLButtonElement, ToastActionProps>(function ToastAction(
225
- { className, ...props },
226
- ref,
227
- ) {
228
- return (
229
- <button
230
- ref={ref}
231
- type="button"
232
- className={cn(
233
- 'inline-flex shrink-0 items-center rounded-md border border-border bg-transparent px-3 py-1 ' +
234
- 'text-sm font-medium transition-colors duration-150 hover:bg-muted focus-visible:outline-none ' +
235
- 'focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
236
- className,
237
- )}
238
- {...props}
239
- />
240
- );
241
- });
315
+ /** @deprecated Use sonner's `action` option in `toast()` instead. */
316
+ export const ToastAction = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
317
+ function ToastAction({ className, ...props }, ref) {
318
+ return (
319
+ <button
320
+ ref={ref}
321
+ type="button"
322
+ className={cn(
323
+ 'inline-flex shrink-0 items-center rounded-md border border-border bg-transparent px-3 py-1 text-sm font-medium transition-colors duration-150 hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
324
+ className,
325
+ )}
326
+ {...props}
327
+ />
328
+ );
329
+ },
330
+ );
242
331
 
243
- export const ToastClose = forwardRef<HTMLButtonElement, ToastCloseProps>(function ToastClose(
244
- { className, ...props },
245
- ref,
246
- ) {
247
- return (
248
- <button
249
- ref={ref}
250
- type="button"
251
- aria-label="Close"
252
- className={cn(
253
- 'absolute right-2 top-2 rounded-md p-1 text-foreground/50 transition-opacity hover:text-foreground ' +
254
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
255
- className,
256
- )}
257
- {...props}
258
- >
259
- <svg
260
- xmlns="http://www.w3.org/2000/svg"
261
- width="16"
262
- height="16"
263
- viewBox="0 0 24 24"
264
- fill="none"
265
- stroke="currentColor"
266
- strokeWidth={2}
267
- strokeLinecap="round"
268
- strokeLinejoin="round"
269
- aria-hidden
332
+ /** @deprecated `closeButton` prop on `<Toaster />` renders this automatically. */
333
+ export const ToastClose = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
334
+ function ToastClose({ className, ...props }, ref) {
335
+ return (
336
+ <button
337
+ ref={ref}
338
+ type="button"
339
+ aria-label="Close"
340
+ className={cn(
341
+ 'absolute right-2 top-2 rounded-md p-1 text-foreground/50 transition-opacity hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
342
+ className,
343
+ )}
344
+ {...props}
270
345
  >
271
- <path d="M18 6 6 18" />
272
- <path d="m6 6 12 12" />
273
- </svg>
274
- </button>
275
- );
276
- });
277
-
278
- /* -------------------------------------------------------------------------- */
279
- /* Individual toast item (manages timer + animation) */
280
- /* -------------------------------------------------------------------------- */
281
-
282
- const DEFAULT_DURATION = 5000;
283
-
284
- function ToastItem({
285
- data,
286
- onDismiss,
287
- appearance,
288
- }: {
289
- data: ToastData;
290
- onDismiss: (id: string) => void;
291
- appearance: ToastAppearance;
292
- }) {
293
- const [visible, setVisible] = useState(false);
294
- const [exiting, setExiting] = useState(false);
295
- const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);
296
- const remainingRef = useRef(data.duration ?? DEFAULT_DURATION);
297
- // eslint-disable-next-line react-hooks/purity -- initial value only, never re-read during render
298
- const startRef = useRef(Date.now());
299
-
300
- const startTimer = useCallback(() => {
301
- startRef.current = Date.now();
302
- timerRef.current = setTimeout(() => {
303
- setExiting(true);
304
- setTimeout(() => onDismiss(data.id), 300);
305
- }, remainingRef.current);
306
- }, [data.id, onDismiss]);
307
-
308
- const pauseTimer = useCallback(() => {
309
- if (timerRef.current) {
310
- clearTimeout(timerRef.current);
311
- remainingRef.current -= Date.now() - startRef.current;
312
- if (remainingRef.current < 0) remainingRef.current = 0;
313
- }
314
- }, []);
315
-
316
- useEffect(() => {
317
- // Trigger entry animation on next frame
318
- const raf = requestAnimationFrame(() => setVisible(true));
319
- startTimer();
320
- return () => {
321
- cancelAnimationFrame(raf);
322
- if (timerRef.current) clearTimeout(timerRef.current);
323
- };
324
- }, [startTimer]);
325
-
326
- const handleClose = () => {
327
- if (timerRef.current) clearTimeout(timerRef.current);
328
- setExiting(true);
329
- setTimeout(() => onDismiss(data.id), 300);
330
- };
331
-
332
- const isError = data.variant === 'error';
346
+ <svg
347
+ xmlns="http://www.w3.org/2000/svg"
348
+ width="16"
349
+ height="16"
350
+ viewBox="0 0 24 24"
351
+ fill="none"
352
+ stroke="currentColor"
353
+ strokeWidth={2}
354
+ strokeLinecap="round"
355
+ strokeLinejoin="round"
356
+ aria-hidden
357
+ >
358
+ <path d="M18 6 6 18" />
359
+ <path d="m6 6 12 12" />
360
+ </svg>
361
+ </button>
362
+ );
363
+ },
364
+ );
333
365
 
334
- return (
335
- <div
336
- role="status"
337
- aria-live={isError ? 'assertive' : 'polite'}
338
- className={cn(
339
- 'transform transition-all duration-300',
340
- visible && !exiting ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0',
341
- )}
342
- onMouseEnter={pauseTimer}
343
- onMouseLeave={startTimer}
344
- >
345
- <Toast variant={data.variant} appearance={data.appearance ?? appearance}>
346
- {data.icon ? <div className="mt-0.5 shrink-0 text-muted-foreground">{data.icon}</div> : null}
347
- <div className="flex-1 space-y-1 pr-6">
348
- <ToastTitle>{data.title}</ToastTitle>
349
- {data.description !== undefined && (
350
- <ToastDescription>{data.description}</ToastDescription>
351
- )}
352
- {data.action !== undefined && (
353
- <div className="mt-2">
354
- <ToastAction onClick={data.action.onClick}>{data.action.label}</ToastAction>
355
- </div>
356
- )}
357
- </div>
358
- <ToastClose onClick={handleClose} />
359
- </Toast>
360
- </div>
361
- );
366
+ /**
367
+ * Legacy `ToastData` shape kept for typing in any pre-sonner consumer.
368
+ * @deprecated Sonner uses its own `ExternalToast` shape; prefer that.
369
+ */
370
+ export interface ToastData {
371
+ id: string;
372
+ title: string;
373
+ description?: string;
374
+ variant?: ToastVariant;
375
+ appearance?: ToastAppearance;
376
+ duration?: number;
377
+ action?: { label: string; onClick: () => void };
378
+ icon?: React.ReactNode;
362
379
  }
363
380
 
364
- /* -------------------------------------------------------------------------- */
365
- /* ToastProvider */
366
- /* -------------------------------------------------------------------------- */
367
-
368
- const POSITION_CLASS: Record<NonNullable<ToastProviderProps['position']>, string> = {
369
- 'bottom-right': 'bottom-4 right-4',
370
- 'bottom-left': 'bottom-4 left-4',
371
- 'top-right': 'right-4 top-4',
372
- 'top-left': 'left-4 top-4',
373
- };
374
-
375
- export function ToastProvider({ children, max = 5, position = 'bottom-right', appearance = 'soft' }: ToastProviderProps) {
376
- const [viewportId] = useState(() => ++getStore().viewportCounter);
377
-
378
- useEffect(() => {
379
- const store = getStore();
380
- store.viewports.add(viewportId);
381
- notify();
382
- return () => {
383
- store.viewports.delete(viewportId);
384
- notify();
385
- };
386
- }, [viewportId]);
387
-
388
- const items = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
389
- const activeViewportId = useSyncExternalStore(subscribe, getViewportSnapshot, () => undefined);
390
- const visible = items.slice(-max);
391
- const isActiveViewport = viewportId === activeViewportId;
392
-
393
- return (
394
- <>
395
- {children}
396
- {isActiveViewport ? (
397
- <div
398
- aria-label="Notifications"
399
- className={cn('pointer-events-none fixed z-[100] flex max-w-[420px] flex-col gap-2', POSITION_CLASS[position])}
400
- >
401
- {visible.map((t) => (
402
- <ToastItem key={t.id} data={t} onDismiss={dismiss} appearance={appearance} />
403
- ))}
404
- </div>
405
- ) : null}
406
- </>
407
- );
408
- }
381
+ export interface ToastTitleProps extends HTMLAttributes<HTMLDivElement> {}
382
+ export interface ToastDescriptionProps extends HTMLAttributes<HTMLDivElement> {}
383
+ export interface ToastActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {}
384
+ export interface ToastCloseProps extends ButtonHTMLAttributes<HTMLButtonElement> {}