@lerianstudio/sindarian-ui 2.0.0-beta.14 → 2.0.0-beta.16

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/copy-field/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAmCD,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,MAAc,EACd,WAAW,EACX,WAA0B,EAC1B,SAAwB,EACxB,UAA4B,EAC5B,SAAS,EACT,aAAa,EACb,IAAY,EACZ,WAAW,EACX,mBAAmB,EACpB,EAAE,cAAc,qBAqLhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/copy-field/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAmCD,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,MAAc,EACd,WAAW,EACX,WAA0B,EAC1B,SAAwB,EACxB,UAA4B,EAC5B,SAAS,EACT,aAAa,EACb,IAAY,EACZ,WAAW,EACX,mBAAmB,EACpB,EAAE,cAAc,qBAwLhB"}
@@ -111,7 +111,10 @@ function CopyField({ value, label, masked = false, onCopyLabel, revealLabel = 'S
111
111
  };
112
112
  const handleFallback = () => {
113
113
  selectFieldText();
114
- toast({ title: fallbackLabel ?? FALLBACK_COPY_LABEL });
114
+ toast({
115
+ variant: 'destructive',
116
+ title: fallbackLabel ?? FALLBACK_COPY_LABEL
117
+ });
115
118
  };
116
119
  const handleCopy = async () => {
117
120
  if (!isClipboardAvailable()) {
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,+BAqB9C"}
1
+ {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,+BAqB9C"}
@@ -4,12 +4,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.Toaster = Toaster;
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  const sonner_1 = require("sonner");
7
+ const use_toast_1 = require("../../../hooks/use-toast");
7
8
  const theme_provider_1 = require("../../../theme/theme-provider");
8
9
  function Toaster({ theme }) {
9
10
  // Optional read: a Toaster mounted outside any ThemeProvider must still
10
11
  // render, so this cannot go through `useTheme`, which throws.
11
12
  const themeContext = (0, theme_provider_1.useOptionalTheme)();
12
- return ((0, jsx_runtime_1.jsx)(sonner_1.Toaster, { theme: theme ?? themeContext?.resolvedTheme ?? 'system', position: "bottom-right", visibleToasts: 3, duration: 10000, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
13
+ return ((0, jsx_runtime_1.jsx)(sonner_1.Toaster, { theme: theme ?? themeContext?.resolvedTheme ?? 'system', position: "bottom-right", visibleToasts: 3, duration: use_toast_1.DEFAULT_DURATION, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
13
14
  className: 'font-sans !text-sm !font-medium'
14
15
  } }));
15
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/copy-field/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAmCD,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,MAAc,EACd,WAAW,EACX,WAA0B,EAC1B,SAAwB,EACxB,UAA4B,EAC5B,SAAS,EACT,aAAa,EACb,IAAY,EACZ,WAAW,EACX,mBAAmB,EACpB,EAAE,cAAc,qBAqLhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/copy-field/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAmCD,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,MAAc,EACd,WAAW,EACX,WAA0B,EAC1B,SAAwB,EACxB,UAA4B,EAC5B,SAAS,EACT,aAAa,EACb,IAAY,EACZ,WAAW,EACX,mBAAmB,EACpB,EAAE,cAAc,qBAwLhB"}
@@ -75,7 +75,10 @@ export function CopyField({ value, label, masked = false, onCopyLabel, revealLab
75
75
  };
76
76
  const handleFallback = () => {
77
77
  selectFieldText();
78
- toast({ title: fallbackLabel ?? FALLBACK_COPY_LABEL });
78
+ toast({
79
+ variant: 'destructive',
80
+ title: fallbackLabel ?? FALLBACK_COPY_LABEL
81
+ });
79
82
  };
80
83
  const handleCopy = async () => {
81
84
  if (!isClipboardAvailable()) {
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,+BAqB9C"}
1
+ {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,+BAqB9C"}
@@ -1,12 +1,13 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { Toaster as SonnerToaster } from 'sonner';
4
+ import { DEFAULT_DURATION } from '../../../hooks/use-toast.js';
4
5
  import { useOptionalTheme } from '../../../theme/theme-provider.js';
5
6
  export function Toaster({ theme }) {
6
7
  // Optional read: a Toaster mounted outside any ThemeProvider must still
7
8
  // render, so this cannot go through `useTheme`, which throws.
8
9
  const themeContext = useOptionalTheme();
9
- return (_jsx(SonnerToaster, { theme: theme ?? themeContext?.resolvedTheme ?? 'system', position: "bottom-right", visibleToasts: 3, duration: 10000, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
10
+ return (_jsx(SonnerToaster, { theme: theme ?? themeContext?.resolvedTheme ?? 'system', position: "bottom-right", visibleToasts: 3, duration: DEFAULT_DURATION, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
10
11
  className: 'font-sans !text-sm !font-medium'
11
12
  } }));
12
13
  }
@@ -1,4 +1,10 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast/index.js';
2
+ /**
3
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
4
+ * anything raised without one. The two must not drift apart, so the Toaster
5
+ * imports this rather than repeating the literal.
6
+ */
7
+ export declare const DEFAULT_DURATION = 10000;
2
8
  type ToastVariant = 'default' | 'success' | 'warning' | 'destructive';
3
9
  type ToasterToast = {
4
10
  id: string | number;
@@ -6,9 +12,19 @@ type ToasterToast = {
6
12
  description?: React.ReactNode;
7
13
  variant?: ToastVariant;
8
14
  action?: ToastActionElement;
15
+ /**
16
+ * Auto-dismiss delay in ms, which must be greater than 0: sonner resolves it
17
+ * as `toast.duration || toasterDuration || default`, so `0` reads as unset
18
+ * and the toast silently takes the `<Toaster />` default instead of closing
19
+ * at once. Omit it to take the variant's own lifetime: `destructive` stays
20
+ * until dismissed, every other variant closes after 10s.
21
+ */
22
+ duration?: number;
23
+ };
24
+ type Toast = Omit<ToasterToast, 'id'> & {
25
+ id?: ToasterToast['id'];
9
26
  };
10
- type Toast = Omit<ToasterToast, 'id'>;
11
- declare function toast({ title, description, variant, ...rest }: Toast): {
27
+ declare function toast({ title, description, variant, duration, id, ...rest }: Toast): {
12
28
  id: string | number;
13
29
  dismiss: () => string | number;
14
30
  update: (props: Partial<ToasterToast>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAI/D,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAC5B,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;AAErC,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBA+B1C,OAAO,CAAC,YAAY,CAAC;EAQxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAA;AAerC,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;CAAE,CAAA;AAiCnE,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBAsCxD,OAAO,CAAC,YAAY,CAAC;EASxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
@@ -1,39 +1,83 @@
1
1
  'use client';
2
2
  import { toast as sonnerToast } from 'sonner';
3
- const DEFAULT_DURATION = 10000;
4
- function toast({ title, description, variant, ...rest }) {
3
+ /**
4
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
5
+ * anything raised without one. The two must not drift apart, so the Toaster
6
+ * imports this rather than repeating the literal.
7
+ */
8
+ export const DEFAULT_DURATION = 10000;
9
+ /**
10
+ * A destructive toast reports something the operator has to read -- a refused
11
+ * money operation, a failed copy of a show-once secret, a language switch that
12
+ * did not take. It stays up until dismissed instead of auto-closing.
13
+ *
14
+ * `Infinity` is how sonner disables the auto-close timer (it short-circuits the
15
+ * timer effect rather than calling `setTimeout(fn, Infinity)`, which would fire
16
+ * immediately). `<Toaster />` already passes `closeButton`, and sonner gates the
17
+ * close button on that flag alone, never on the duration -- so a persistent
18
+ * toast still renders its dismiss affordance.
19
+ */
20
+ const PERSIST_UNTIL_DISMISSED = Infinity;
21
+ const isPlainText = (value) => value === undefined || typeof value === 'string';
22
+ /**
23
+ * Two identical errors share one toast instead of stacking: same variant, same
24
+ * text -- same id, and sonner updates the one already on screen.
25
+ *
26
+ * Unbounded stacking is worse for a persistent toast than for a transient one.
27
+ * `<Toaster />` shows three at a time and renders the rest `opacity: 0;
28
+ * pointer-events: none`, so a fourth error nobody can read is also a fourth
29
+ * error nobody can close -- and without an auto-dismiss, nothing ahead of it
30
+ * clears on its own.
31
+ *
32
+ * Only plain-text toasts collapse. A `ReactNode` has no stable key and
33
+ * `String(node)` would fold unrelated errors onto one id.
34
+ *
35
+ * ponytail: the ceiling is still three. Distinct persistent errors past the
36
+ * third queue behind the front three until one is dismissed; lifting that means
37
+ * raising `visibleToasts`, not more work here.
38
+ */
39
+ function collapseKey(title, description) {
40
+ if (!isPlainText(title) || !isPlainText(description)) {
41
+ return undefined;
42
+ }
43
+ return `destructive:${JSON.stringify([title ?? null, description ?? null])}`;
44
+ }
45
+ function toast({ title, description, variant, duration, id, ...rest }) {
5
46
  const message = title ?? '';
47
+ const toastId = variant === 'destructive' && id === undefined
48
+ ? collapseKey(title, description)
49
+ : id;
6
50
  const options = {
7
51
  description,
8
- ...rest
52
+ ...rest,
53
+ ...(toastId !== undefined && { id: toastId }),
54
+ duration: duration ??
55
+ (variant === 'destructive' ? PERSIST_UNTIL_DISMISSED : DEFAULT_DURATION)
9
56
  };
10
- let id;
57
+ let raisedId;
11
58
  switch (variant) {
12
59
  case 'success':
13
- options.duration = DEFAULT_DURATION;
14
- id = sonnerToast.success(message, options);
60
+ raisedId = sonnerToast.success(message, options);
15
61
  break;
16
62
  case 'warning':
17
- options.duration = DEFAULT_DURATION;
18
- id = sonnerToast.warning(message, options);
63
+ raisedId = sonnerToast.warning(message, options);
19
64
  break;
20
65
  case 'destructive':
21
- options.duration = DEFAULT_DURATION;
22
- id = sonnerToast.error(message, options);
66
+ raisedId = sonnerToast.error(message, options);
23
67
  break;
24
68
  default:
25
- options.duration = DEFAULT_DURATION;
26
- id = sonnerToast(message, options);
69
+ raisedId = sonnerToast(message, options);
27
70
  break;
28
71
  }
29
72
  return {
30
- id,
31
- dismiss: () => sonnerToast.dismiss(id),
73
+ id: raisedId,
74
+ dismiss: () => sonnerToast.dismiss(raisedId),
32
75
  update: (props) => {
33
76
  sonnerToast(props.title ?? message, {
34
- id,
77
+ ...rest,
78
+ id: raisedId,
35
79
  description: props.description ?? description,
36
- ...rest
80
+ duration: props.duration ?? options.duration
37
81
  });
38
82
  }
39
83
  };
@@ -1,6 +1,12 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast/index.js';
2
2
  /** Extra toast props for the severity helpers (the variant is fixed per helper). */
3
3
  export interface ToastOptions {
4
+ /**
5
+ * Caller-controlled toast identity. A repeat under the same id updates the
6
+ * toast in place instead of stacking a second one; omit it and a destructive
7
+ * toast derives its own from the title and description.
8
+ */
9
+ id?: string | number;
4
10
  /** Optional action element rendered inside the toast. */
5
11
  action?: ToastActionElement;
6
12
  /**
@@ -9,6 +15,13 @@ export interface ToastOptions {
9
15
  * it, so it is not rendered. Put it in `description` if it must be visible.
10
16
  */
11
17
  errorCode?: string;
18
+ /**
19
+ * Auto-dismiss delay in ms, overriding the variant's own lifetime for this
20
+ * one call. Must be greater than 0 -- sonner reads `0` as unset and falls
21
+ * back to the `<Toaster />` default. Omit it and `errorToast` stays until
22
+ * dismissed while `successToast` and `warningToast` close after 10s.
23
+ */
24
+ duration?: number;
12
25
  }
13
26
  export declare function successToast(title: string, description?: string, opts?: Partial<ToastOptions>): void;
14
27
  export declare function errorToast(title: string, description?: string, opts?: Partial<ToastOptions>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/toast/helpers.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/toast/helpers.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,yDAAyD;IACzD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAkBD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN"}
@@ -16,7 +16,14 @@
16
16
  */
17
17
  import { toast } from '../hooks/use-toast.js';
18
18
  function raise(variant, title, description, opts) {
19
- toast({ action: opts?.action, variant, title, description });
19
+ toast({
20
+ action: opts?.action,
21
+ variant,
22
+ title,
23
+ description,
24
+ duration: opts?.duration,
25
+ id: opts?.id
26
+ });
20
27
  }
21
28
  export function successToast(title, description, opts) {
22
29
  raise('success', title, description, opts);
@@ -1,4 +1,10 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast';
2
+ /**
3
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
4
+ * anything raised without one. The two must not drift apart, so the Toaster
5
+ * imports this rather than repeating the literal.
6
+ */
7
+ export declare const DEFAULT_DURATION = 10000;
2
8
  type ToastVariant = 'default' | 'success' | 'warning' | 'destructive';
3
9
  type ToasterToast = {
4
10
  id: string | number;
@@ -6,9 +12,19 @@ type ToasterToast = {
6
12
  description?: React.ReactNode;
7
13
  variant?: ToastVariant;
8
14
  action?: ToastActionElement;
15
+ /**
16
+ * Auto-dismiss delay in ms, which must be greater than 0: sonner resolves it
17
+ * as `toast.duration || toasterDuration || default`, so `0` reads as unset
18
+ * and the toast silently takes the `<Toaster />` default instead of closing
19
+ * at once. Omit it to take the variant's own lifetime: `destructive` stays
20
+ * until dismissed, every other variant closes after 10s.
21
+ */
22
+ duration?: number;
23
+ };
24
+ type Toast = Omit<ToasterToast, 'id'> & {
25
+ id?: ToasterToast['id'];
9
26
  };
10
- type Toast = Omit<ToasterToast, 'id'>;
11
- declare function toast({ title, description, variant, ...rest }: Toast): {
27
+ declare function toast({ title, description, variant, duration, id, ...rest }: Toast): {
12
28
  id: string | number;
13
29
  dismiss: () => string | number;
14
30
  update: (props: Partial<ToasterToast>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAI/D,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAC5B,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;AAErC,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBA+B1C,OAAO,CAAC,YAAY,CAAC;EAQxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAA;AAerC,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;CAAE,CAAA;AAiCnE,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBAsCxD,OAAO,CAAC,YAAY,CAAC;EASxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
@@ -1,43 +1,88 @@
1
1
  'use client';
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.DEFAULT_DURATION = void 0;
4
5
  exports.useToast = useToast;
5
6
  exports.toast = toast;
6
7
  const sonner_1 = require("sonner");
7
- const DEFAULT_DURATION = 10000;
8
- function toast({ title, description, variant, ...rest }) {
8
+ /**
9
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
10
+ * anything raised without one. The two must not drift apart, so the Toaster
11
+ * imports this rather than repeating the literal.
12
+ */
13
+ exports.DEFAULT_DURATION = 10000;
14
+ /**
15
+ * A destructive toast reports something the operator has to read -- a refused
16
+ * money operation, a failed copy of a show-once secret, a language switch that
17
+ * did not take. It stays up until dismissed instead of auto-closing.
18
+ *
19
+ * `Infinity` is how sonner disables the auto-close timer (it short-circuits the
20
+ * timer effect rather than calling `setTimeout(fn, Infinity)`, which would fire
21
+ * immediately). `<Toaster />` already passes `closeButton`, and sonner gates the
22
+ * close button on that flag alone, never on the duration -- so a persistent
23
+ * toast still renders its dismiss affordance.
24
+ */
25
+ const PERSIST_UNTIL_DISMISSED = Infinity;
26
+ const isPlainText = (value) => value === undefined || typeof value === 'string';
27
+ /**
28
+ * Two identical errors share one toast instead of stacking: same variant, same
29
+ * text -- same id, and sonner updates the one already on screen.
30
+ *
31
+ * Unbounded stacking is worse for a persistent toast than for a transient one.
32
+ * `<Toaster />` shows three at a time and renders the rest `opacity: 0;
33
+ * pointer-events: none`, so a fourth error nobody can read is also a fourth
34
+ * error nobody can close -- and without an auto-dismiss, nothing ahead of it
35
+ * clears on its own.
36
+ *
37
+ * Only plain-text toasts collapse. A `ReactNode` has no stable key and
38
+ * `String(node)` would fold unrelated errors onto one id.
39
+ *
40
+ * ponytail: the ceiling is still three. Distinct persistent errors past the
41
+ * third queue behind the front three until one is dismissed; lifting that means
42
+ * raising `visibleToasts`, not more work here.
43
+ */
44
+ function collapseKey(title, description) {
45
+ if (!isPlainText(title) || !isPlainText(description)) {
46
+ return undefined;
47
+ }
48
+ return `destructive:${JSON.stringify([title ?? null, description ?? null])}`;
49
+ }
50
+ function toast({ title, description, variant, duration, id, ...rest }) {
9
51
  const message = title ?? '';
52
+ const toastId = variant === 'destructive' && id === undefined
53
+ ? collapseKey(title, description)
54
+ : id;
10
55
  const options = {
11
56
  description,
12
- ...rest
57
+ ...rest,
58
+ ...(toastId !== undefined && { id: toastId }),
59
+ duration: duration ??
60
+ (variant === 'destructive' ? PERSIST_UNTIL_DISMISSED : exports.DEFAULT_DURATION)
13
61
  };
14
- let id;
62
+ let raisedId;
15
63
  switch (variant) {
16
64
  case 'success':
17
- options.duration = DEFAULT_DURATION;
18
- id = sonner_1.toast.success(message, options);
65
+ raisedId = sonner_1.toast.success(message, options);
19
66
  break;
20
67
  case 'warning':
21
- options.duration = DEFAULT_DURATION;
22
- id = sonner_1.toast.warning(message, options);
68
+ raisedId = sonner_1.toast.warning(message, options);
23
69
  break;
24
70
  case 'destructive':
25
- options.duration = DEFAULT_DURATION;
26
- id = sonner_1.toast.error(message, options);
71
+ raisedId = sonner_1.toast.error(message, options);
27
72
  break;
28
73
  default:
29
- options.duration = DEFAULT_DURATION;
30
- id = (0, sonner_1.toast)(message, options);
74
+ raisedId = (0, sonner_1.toast)(message, options);
31
75
  break;
32
76
  }
33
77
  return {
34
- id,
35
- dismiss: () => sonner_1.toast.dismiss(id),
78
+ id: raisedId,
79
+ dismiss: () => sonner_1.toast.dismiss(raisedId),
36
80
  update: (props) => {
37
81
  (0, sonner_1.toast)(props.title ?? message, {
38
- id,
82
+ ...rest,
83
+ id: raisedId,
39
84
  description: props.description ?? description,
40
- ...rest
85
+ duration: props.duration ?? options.duration
41
86
  });
42
87
  }
43
88
  };
@@ -1,6 +1,12 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast';
2
2
  /** Extra toast props for the severity helpers (the variant is fixed per helper). */
3
3
  export interface ToastOptions {
4
+ /**
5
+ * Caller-controlled toast identity. A repeat under the same id updates the
6
+ * toast in place instead of stacking a second one; omit it and a destructive
7
+ * toast derives its own from the title and description.
8
+ */
9
+ id?: string | number;
4
10
  /** Optional action element rendered inside the toast. */
5
11
  action?: ToastActionElement;
6
12
  /**
@@ -9,6 +15,13 @@ export interface ToastOptions {
9
15
  * it, so it is not rendered. Put it in `description` if it must be visible.
10
16
  */
11
17
  errorCode?: string;
18
+ /**
19
+ * Auto-dismiss delay in ms, overriding the variant's own lifetime for this
20
+ * one call. Must be greater than 0 -- sonner reads `0` as unset and falls
21
+ * back to the `<Toaster />` default. Omit it and `errorToast` stays until
22
+ * dismissed while `successToast` and `warningToast` close after 10s.
23
+ */
24
+ duration?: number;
12
25
  }
13
26
  export declare function successToast(title: string, description?: string, opts?: Partial<ToastOptions>): void;
14
27
  export declare function errorToast(title: string, description?: string, opts?: Partial<ToastOptions>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/toast/helpers.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/toast/helpers.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,yDAAyD;IACzD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAkBD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN"}
@@ -21,7 +21,14 @@ exports.warningToast = warningToast;
21
21
  */
22
22
  const use_toast_1 = require("../hooks/use-toast");
23
23
  function raise(variant, title, description, opts) {
24
- (0, use_toast_1.toast)({ action: opts?.action, variant, title, description });
24
+ (0, use_toast_1.toast)({
25
+ action: opts?.action,
26
+ variant,
27
+ title,
28
+ description,
29
+ duration: opts?.duration,
30
+ id: opts?.id
31
+ });
25
32
  }
26
33
  function successToast(title, description, opts) {
27
34
  raise('success', title, description, opts);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerianstudio/sindarian-ui",
3
- "version": "2.0.0-beta.14",
3
+ "version": "2.0.0-beta.16",
4
4
  "description": "Sindarian UI - A UI library for Midaz Console",
5
5
  "license": "ISC",
6
6
  "author": {