@choice-ui/react 1.6.7 → 1.6.9

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 (100) hide show
  1. package/dist/components/code-block/dist/index.d.ts +11 -14
  2. package/dist/components/code-block/dist/index.js +120 -93
  3. package/dist/components/code-block/src/code-block.d.ts +1 -2
  4. package/dist/components/code-block/src/code-block.js +11 -21
  5. package/dist/components/code-block/src/components/code-block-code.js +25 -13
  6. package/dist/components/code-block/src/components/code-block-content.d.ts +1 -1
  7. package/dist/components/code-block/src/components/code-block-content.js +14 -11
  8. package/dist/components/code-block/src/components/code-block-footer.js +4 -3
  9. package/dist/components/code-block/src/components/code-block-header.js +5 -6
  10. package/dist/components/code-block/src/hooks/index.d.ts +0 -1
  11. package/dist/components/code-block/src/hooks/use-code-block.js +26 -5
  12. package/dist/components/code-block/src/hooks/use-scroll-detection.d.ts +1 -2
  13. package/dist/components/code-block/src/hooks/use-scroll-detection.js +18 -12
  14. package/dist/components/code-block/src/types.d.ts +3 -5
  15. package/dist/components/code-block/src/utils/extract-code.js +23 -0
  16. package/dist/components/command/src/components/command-list.js +15 -3
  17. package/dist/components/description/dist/index.d.ts +8 -0
  18. package/dist/components/description/dist/index.js +29 -0
  19. package/dist/components/description/src/description.d.ts +6 -0
  20. package/dist/components/description/src/description.js +18 -0
  21. package/dist/components/description/src/index.d.ts +2 -0
  22. package/dist/components/description/src/tv.d.ts +13 -0
  23. package/dist/components/description/src/tv.js +15 -0
  24. package/dist/components/description/tsup.config.d.ts +2 -0
  25. package/dist/components/emoji-picker/dist/index.d.ts +1 -0
  26. package/dist/components/emoji-picker/dist/index.js +4 -2
  27. package/dist/components/emoji-picker/src/emoji-picker.d.ts +1 -0
  28. package/dist/components/emoji-picker/src/emoji-picker.js +4 -2
  29. package/dist/components/error-message/dist/index.d.ts +8 -0
  30. package/dist/components/error-message/dist/index.js +30 -0
  31. package/dist/components/error-message/src/error-message.d.ts +6 -0
  32. package/dist/components/error-message/src/error-message.js +19 -0
  33. package/dist/components/error-message/src/index.d.ts +2 -0
  34. package/dist/components/error-message/src/tv.d.ts +13 -0
  35. package/dist/components/error-message/src/tv.js +15 -0
  36. package/dist/components/error-message/tsup.config.d.ts +2 -0
  37. package/dist/components/form/src/adapters/base-adapter.js +4 -2
  38. package/dist/components/form/src/tv.d.ts +0 -12
  39. package/dist/components/form/src/tv.js +1 -13
  40. package/dist/components/index.d.ts +3 -0
  41. package/dist/components/md-render/dist/index.d.ts +2 -1
  42. package/dist/components/md-render/dist/index.js +5 -9
  43. package/dist/components/md-render/src/components/markdown-components.js +1 -7
  44. package/dist/components/md-render/src/md-render.js +4 -2
  45. package/dist/components/md-render/src/types.d.ts +2 -1
  46. package/dist/components/notifications/dist/index.d.ts +1 -5
  47. package/dist/components/notifications/src/notifications.d.ts +0 -1
  48. package/dist/components/notifications/src/notifications.js +0 -1
  49. package/dist/components/numeric-input/dist/index.d.ts +23 -9
  50. package/dist/components/numeric-input/dist/index.js +26 -3
  51. package/dist/components/numeric-input/src/components/numeric-input-menu-trigger.js +4 -1
  52. package/dist/components/numeric-input/src/hooks/index.d.ts +1 -0
  53. package/dist/components/numeric-input/src/hooks/use-numeric-long-press.d.ts +13 -0
  54. package/dist/components/numeric-input/src/hooks/use-numeric-long-press.js +27 -0
  55. package/dist/components/numeric-input/src/index.d.ts +1 -0
  56. package/dist/components/numeric-input/src/tv.js +22 -2
  57. package/dist/components/picture-preview/dist/index.d.ts +5 -0
  58. package/dist/components/picture-preview/dist/index.js +287 -140
  59. package/dist/components/picture-preview/src/hooks/useWheelHandler.d.ts +6 -1
  60. package/dist/components/picture-preview/src/hooks/useWheelHandler.js +25 -7
  61. package/dist/components/picture-preview/src/picture-preview.d.ts +5 -0
  62. package/dist/components/picture-preview/src/picture-preview.js +214 -123
  63. package/dist/components/picture-preview/src/tv.d.ts +93 -3
  64. package/dist/components/picture-preview/src/tv.js +48 -10
  65. package/dist/components/separator/dist/index.d.ts +1 -8
  66. package/dist/components/separator/src/separator.d.ts +1 -8
  67. package/dist/components/separator/src/separator.js +33 -5
  68. package/dist/components/separator/src/tv.d.ts +39 -18
  69. package/dist/components/separator/src/tv.js +37 -7
  70. package/dist/components/text-field/dist/index.d.ts +2 -3
  71. package/dist/components/text-field/dist/index.js +4 -19
  72. package/dist/components/text-field/src/components/index.d.ts +0 -1
  73. package/dist/components/text-field/src/text-field.d.ts +3 -2
  74. package/dist/components/text-field/src/text-field.js +2 -2
  75. package/dist/components/text-field/src/tv.d.ts +3 -3
  76. package/dist/components/text-field/src/tv.js +1 -6
  77. package/dist/components/toast/dist/index.d.ts +248 -0
  78. package/dist/components/toast/src/components/index.d.ts +3 -0
  79. package/dist/components/toast/src/components/toast-progress-bar.d.ts +7 -0
  80. package/dist/components/toast/src/components/toast-progress-bar.js +53 -0
  81. package/dist/components/toast/src/components/toaster-item.d.ts +26 -0
  82. package/dist/components/toast/src/components/toaster-item.js +416 -0
  83. package/dist/components/toast/src/components/toaster-slots.d.ts +87 -0
  84. package/dist/components/toast/src/components/toaster-slots.js +38 -0
  85. package/dist/components/toast/src/index.d.ts +5 -0
  86. package/dist/components/toast/src/store.d.ts +101 -0
  87. package/dist/components/toast/src/store.js +205 -0
  88. package/dist/components/toast/src/toaster.d.ts +87 -0
  89. package/dist/components/toast/src/toaster.js +271 -0
  90. package/dist/components/toast/src/tv.d.ts +365 -0
  91. package/dist/components/toast/src/tv.js +412 -0
  92. package/dist/components/toast/src/types.d.ts +79 -0
  93. package/dist/components/toast/tsup.config.d.ts +2 -0
  94. package/dist/index.js +11 -2
  95. package/dist/styles/components.css +2 -0
  96. package/package.json +1 -1
  97. package/dist/components/code-block/src/hooks/use-line-count.d.ts +0 -2
  98. package/dist/components/code-block/src/hooks/use-line-count.js +0 -27
  99. package/dist/components/text-field/src/components/field-description.d.ts +0 -2
  100. package/dist/components/text-field/src/components/field-description.js +0 -16
@@ -0,0 +1,205 @@
1
+ const stores = /* @__PURE__ */ new Map();
2
+ const subscribers = /* @__PURE__ */ new Map();
3
+ const DEFAULT_TOASTER_ID = "default";
4
+ const MAX_TOASTS_PER_TOASTER = 100;
5
+ let toastCounter = 0;
6
+ const MAX_COUNTER = Number.MAX_SAFE_INTEGER - 1;
7
+ function generateId() {
8
+ if (toastCounter >= MAX_COUNTER) {
9
+ toastCounter = 0;
10
+ }
11
+ return `toast-${++toastCounter}-${Date.now()}`;
12
+ }
13
+ function validateToasterId(toasterId) {
14
+ if (typeof toasterId !== "string" || toasterId.length === 0) {
15
+ return DEFAULT_TOASTER_ID;
16
+ }
17
+ return toasterId.slice(0, 64);
18
+ }
19
+ function getStore(toasterId = DEFAULT_TOASTER_ID) {
20
+ if (!stores.has(toasterId)) {
21
+ stores.set(toasterId, {
22
+ toasts: [],
23
+ expanded: false,
24
+ position: "bottom-right"
25
+ });
26
+ }
27
+ return stores.get(toasterId);
28
+ }
29
+ function updateStore(toasterId, updates) {
30
+ const current = getStore(toasterId);
31
+ const newState = { ...current, ...updates };
32
+ stores.set(toasterId, newState);
33
+ return newState;
34
+ }
35
+ function notify(toasterId = DEFAULT_TOASTER_ID) {
36
+ const subs = subscribers.get(toasterId);
37
+ if (subs) {
38
+ subs.forEach((callback) => callback(getStore(toasterId)));
39
+ }
40
+ }
41
+ function subscribe(callback, toasterId = DEFAULT_TOASTER_ID) {
42
+ const validatedId = validateToasterId(toasterId);
43
+ if (!subscribers.has(validatedId)) {
44
+ subscribers.set(validatedId, /* @__PURE__ */ new Set());
45
+ }
46
+ subscribers.get(validatedId).add(callback);
47
+ return () => {
48
+ const subs = subscribers.get(validatedId);
49
+ subs == null ? void 0 : subs.delete(callback);
50
+ if ((subs == null ? void 0 : subs.size) === 0) {
51
+ subscribers.delete(validatedId);
52
+ const store = stores.get(validatedId);
53
+ if ((store == null ? void 0 : store.toasts.length) === 0) {
54
+ stores.delete(validatedId);
55
+ }
56
+ }
57
+ };
58
+ }
59
+ function getSnapshot(toasterId = DEFAULT_TOASTER_ID) {
60
+ return getStore(toasterId);
61
+ }
62
+ function setToasterConfig(config, toasterId = DEFAULT_TOASTER_ID) {
63
+ updateStore(toasterId, config);
64
+ notify(toasterId);
65
+ }
66
+ function addToast(title, type, options = {}, toasterId = DEFAULT_TOASTER_ID) {
67
+ const validatedId = validateToasterId(toasterId);
68
+ const store = getStore(validatedId);
69
+ const id = options.id ?? generateId();
70
+ const existingIndex = store.toasts.findIndex((t) => t.id === id);
71
+ const toastData = {
72
+ id,
73
+ type,
74
+ variant: options.variant,
75
+ title,
76
+ description: options.description,
77
+ descriptionHtml: options.descriptionHtml,
78
+ duration: options.duration,
79
+ icon: options.icon,
80
+ action: options.action,
81
+ cancel: options.cancel,
82
+ onClose: options.onClose,
83
+ onAutoClose: options.onAutoClose,
84
+ dismissible: options.dismissible ?? true,
85
+ createdAt: Date.now()
86
+ };
87
+ let newToasts;
88
+ if (existingIndex !== -1) {
89
+ newToasts = [...store.toasts];
90
+ newToasts[existingIndex] = toastData;
91
+ } else {
92
+ newToasts = [toastData, ...store.toasts];
93
+ if (newToasts.length > MAX_TOASTS_PER_TOASTER) {
94
+ const removed = newToasts.splice(MAX_TOASTS_PER_TOASTER);
95
+ removed.forEach((t) => {
96
+ var _a;
97
+ return (_a = t.onClose) == null ? void 0 : _a.call(t);
98
+ });
99
+ }
100
+ }
101
+ updateStore(validatedId, { toasts: newToasts });
102
+ notify(validatedId);
103
+ return id;
104
+ }
105
+ function dismiss(id, toasterId = DEFAULT_TOASTER_ID) {
106
+ var _a;
107
+ const store = getStore(toasterId);
108
+ const toast2 = store.toasts.find((t) => t.id === id);
109
+ if (toast2) {
110
+ (_a = toast2.onClose) == null ? void 0 : _a.call(toast2);
111
+ const newToasts = store.toasts.filter((t) => t.id !== id);
112
+ updateStore(toasterId, { toasts: newToasts });
113
+ notify(toasterId);
114
+ }
115
+ }
116
+ function dismissAll(toasterId) {
117
+ if (toasterId) {
118
+ const store = getStore(toasterId);
119
+ store.toasts.forEach((t) => {
120
+ var _a;
121
+ return (_a = t.onClose) == null ? void 0 : _a.call(t);
122
+ });
123
+ updateStore(toasterId, { toasts: [] });
124
+ notify(toasterId);
125
+ } else {
126
+ stores.forEach((store, id) => {
127
+ store.toasts.forEach((t) => {
128
+ var _a;
129
+ return (_a = t.onClose) == null ? void 0 : _a.call(t);
130
+ });
131
+ updateStore(id, { toasts: [] });
132
+ notify(id);
133
+ });
134
+ }
135
+ }
136
+ function updateHeight(id, height, toasterId = DEFAULT_TOASTER_ID) {
137
+ const store = getStore(toasterId);
138
+ const toastIndex = store.toasts.findIndex((t) => t.id === id);
139
+ if (toastIndex !== -1 && store.toasts[toastIndex].height !== height) {
140
+ const newToasts = [...store.toasts];
141
+ newToasts[toastIndex] = { ...newToasts[toastIndex], height };
142
+ updateStore(toasterId, { toasts: newToasts });
143
+ notify(toasterId);
144
+ }
145
+ }
146
+ function setExpanded(expanded, toasterId = DEFAULT_TOASTER_ID) {
147
+ updateStore(toasterId, { expanded });
148
+ notify(toasterId);
149
+ }
150
+ function promiseToast(promise, options, toasterId = DEFAULT_TOASTER_ID) {
151
+ const loadingOpts = typeof options.loading === "string" ? { title: options.loading } : options.loading;
152
+ const id = addToast(
153
+ loadingOpts.title,
154
+ "loading",
155
+ { ...loadingOpts, duration: Infinity },
156
+ toasterId
157
+ );
158
+ promise.then((data) => {
159
+ const successOpts = typeof options.success === "function" ? options.success(data) : options.success;
160
+ const opts = typeof successOpts === "string" ? { title: successOpts } : successOpts;
161
+ addToast(opts.title, "success", { ...opts, id }, toasterId);
162
+ }).catch((err) => {
163
+ const errorOpts = typeof options.error === "function" ? options.error(err) : options.error;
164
+ const opts = typeof errorOpts === "string" ? { title: errorOpts } : errorOpts;
165
+ addToast(opts.title, "error", { ...opts, id }, toasterId);
166
+ });
167
+ return promise;
168
+ }
169
+ function createToastApi(toasterId = DEFAULT_TOASTER_ID) {
170
+ const validatedId = validateToasterId(toasterId);
171
+ const api = (title, options) => addToast(title, "default", options, validatedId);
172
+ api.success = (title, options) => addToast(title, "success", options, validatedId);
173
+ api.error = (title, options) => addToast(title, "error", options, validatedId);
174
+ api.warning = (title, options) => addToast(title, "warning", options, validatedId);
175
+ api.info = (title, options) => addToast(title, "info", options, validatedId);
176
+ api.loading = (title, options) => addToast(title, "loading", options, validatedId);
177
+ api.promise = (promise, options) => promiseToast(promise, options, validatedId);
178
+ api.dismiss = (id) => dismiss(id, validatedId);
179
+ api.dismissAll = () => dismissAll(validatedId);
180
+ return api;
181
+ }
182
+ const toastApiCache = /* @__PURE__ */ new Map();
183
+ function getOrCreateToastApi(toasterId) {
184
+ const validatedId = validateToasterId(toasterId);
185
+ let api = toastApiCache.get(validatedId);
186
+ if (!api) {
187
+ api = createToastApi(validatedId);
188
+ toastApiCache.set(validatedId, api);
189
+ }
190
+ return api;
191
+ }
192
+ const baseToast = createToastApi();
193
+ const toast = Object.assign(baseToast, {
194
+ use: (toasterId) => getOrCreateToastApi(toasterId)
195
+ });
196
+ export {
197
+ dismiss,
198
+ dismissAll,
199
+ getSnapshot,
200
+ setExpanded,
201
+ setToasterConfig,
202
+ subscribe,
203
+ toast,
204
+ updateHeight
205
+ };
@@ -0,0 +1,87 @@
1
+ import { ReactNode } from 'react';
2
+ import { ToasterActionsSlot, ToasterDescriptionSlot, ToasterIconSlot, ToasterItemSlot, ToasterTitleSlot } from './components';
3
+ import { ToastPosition } from './types';
4
+ export interface ToasterProps {
5
+ /**
6
+ * Unique ID for this Toaster instance
7
+ * Use this to have multiple Toaster instances in the same app
8
+ * @default "default"
9
+ */
10
+ id?: string;
11
+ /**
12
+ * Position of the toaster
13
+ * @default "bottom-right"
14
+ */
15
+ position?: ToastPosition;
16
+ /**
17
+ * Render toasts into a custom container
18
+ */
19
+ container?: HTMLElement | null;
20
+ /**
21
+ * Label for accessibility
22
+ * @default "Notifications"
23
+ */
24
+ label?: string;
25
+ /**
26
+ * Whether to use a portal for rendering
27
+ * @default true
28
+ */
29
+ portal?: boolean;
30
+ /**
31
+ * Offset from viewport edges in pixels
32
+ * @default 16
33
+ */
34
+ offset?: number;
35
+ /**
36
+ * Default duration for toasts in ms
37
+ * @default 5000
38
+ */
39
+ duration?: number;
40
+ /**
41
+ * Maximum number of visible toasts
42
+ * @default 3
43
+ */
44
+ visibleToasts?: number;
45
+ /**
46
+ * Additional class name
47
+ */
48
+ className?: string;
49
+ /**
50
+ * Children - use Toaster.Item to customize toast rendering
51
+ */
52
+ children?: ReactNode;
53
+ /**
54
+ * Show countdown progress bar at the bottom of each toast
55
+ * @default false
56
+ */
57
+ showProgress?: boolean;
58
+ /**
59
+ * Layout mode for toasts
60
+ * @default "default"
61
+ */
62
+ layout?: "default" | "compact";
63
+ }
64
+ interface ToasterComponent extends React.MemoExoticComponent<React.ForwardRefExoticComponent<ToasterProps & React.RefAttributes<HTMLDivElement>>> {
65
+ Item: typeof ToasterItemSlot;
66
+ Icon: typeof ToasterIconSlot;
67
+ Title: typeof ToasterTitleSlot;
68
+ Description: typeof ToasterDescriptionSlot;
69
+ Actions: typeof ToasterActionsSlot;
70
+ }
71
+ /**
72
+ * Toaster component with compound pattern
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * <Toaster id="my-toaster">
77
+ * <Toaster.Item className="custom-class">
78
+ * <Toaster.Icon>{(type, defaultIcon) => <CustomIcon type={type} />}</Toaster.Icon>
79
+ * <Toaster.Title className="font-bold uppercase" />
80
+ * <Toaster.Description className="text-sm" />
81
+ * <Toaster.Actions>{(action, cancel, close) => <CustomActions />}</Toaster.Actions>
82
+ * </Toaster.Item>
83
+ * </Toaster>
84
+ * ```
85
+ */
86
+ export declare const Toaster: ToasterComponent;
87
+ export {};
@@ -0,0 +1,271 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { AnimatePresence } from "framer-motion";
3
+ import { memo, forwardRef, useMemo, Children, isValidElement, useRef, useState, useCallback, useSyncExternalStore, useEffect } from "react";
4
+ import { createPortal } from "react-dom";
5
+ import { useEventCallback } from "usehooks-ts";
6
+ import { subscribe, getSnapshot, setToasterConfig, dismiss, setExpanded } from "./store.js";
7
+ import { toastViewportTv } from "./tv.js";
8
+ import { ToasterActionsSlot, ToasterDescriptionSlot, ToasterTitleSlot, ToasterIconSlot, ToasterItemSlot } from "./components/toaster-slots.js";
9
+ import { DEFAULT_HEIGHT, GAP, ToasterItem } from "./components/toaster-item.js";
10
+ import { tcx } from "../../../shared/utils/tcx/tcx.js";
11
+ import { mergeRefs } from "../../../shared/utils/merge-refs/merge-refs.js";
12
+ let sharedPortalContainer = null;
13
+ let portalRefCount = 0;
14
+ function getSharedPortalContainer() {
15
+ if (!sharedPortalContainer && typeof document !== "undefined") {
16
+ sharedPortalContainer = document.createElement("div");
17
+ sharedPortalContainer.setAttribute("data-toast-portal", "");
18
+ document.body.appendChild(sharedPortalContainer);
19
+ }
20
+ return sharedPortalContainer;
21
+ }
22
+ function releaseSharedPortalContainer() {
23
+ portalRefCount--;
24
+ if (portalRefCount <= 0 && sharedPortalContainer) {
25
+ sharedPortalContainer.remove();
26
+ sharedPortalContainer = null;
27
+ portalRefCount = 0;
28
+ }
29
+ }
30
+ const ToasterRoot = memo(
31
+ forwardRef(function Toaster2({
32
+ id: toasterId = "default",
33
+ position = "bottom-right",
34
+ container,
35
+ label = "Notifications",
36
+ portal = true,
37
+ offset = 16,
38
+ duration = 5e3,
39
+ visibleToasts = 3,
40
+ className,
41
+ children,
42
+ showProgress = false,
43
+ layout = "default"
44
+ }, ref) {
45
+ const collectedSlots = useMemo(() => {
46
+ const slots = {};
47
+ Children.forEach(children, (child) => {
48
+ if (isValidElement(child) && child.type === ToasterItemSlot) {
49
+ const itemProps = child.props;
50
+ slots.itemClassName = itemProps.className;
51
+ slots.itemStyle = itemProps.style;
52
+ Children.forEach(itemProps.children, (slotChild) => {
53
+ if (!isValidElement(slotChild)) return;
54
+ if (slotChild.type === ToasterIconSlot) {
55
+ const iconProps = slotChild.props;
56
+ slots.iconClassName = iconProps.className;
57
+ slots.iconStyle = iconProps.style;
58
+ slots.renderIcon = iconProps.children;
59
+ } else if (slotChild.type === ToasterTitleSlot) {
60
+ const titleProps = slotChild.props;
61
+ slots.titleClassName = titleProps.className;
62
+ slots.titleStyle = titleProps.style;
63
+ } else if (slotChild.type === ToasterDescriptionSlot) {
64
+ const descProps = slotChild.props;
65
+ slots.descriptionClassName = descProps.className;
66
+ slots.descriptionStyle = descProps.style;
67
+ } else if (slotChild.type === ToasterActionsSlot) {
68
+ const actionsProps = slotChild.props;
69
+ slots.actionsClassName = actionsProps.className;
70
+ slots.actionsStyle = actionsProps.style;
71
+ slots.renderActions = actionsProps.children;
72
+ }
73
+ });
74
+ }
75
+ });
76
+ return slots;
77
+ }, [children]);
78
+ const internalRef = useRef(null);
79
+ const [hovering, setHovering] = useState(false);
80
+ const subscribeToStore = useCallback(
81
+ (callback) => subscribe(callback, toasterId),
82
+ [toasterId]
83
+ );
84
+ const getStoreSnapshot = useCallback(() => getSnapshot(toasterId), [toasterId]);
85
+ const state = useSyncExternalStore(subscribeToStore, getStoreSnapshot, getStoreSnapshot);
86
+ useEffect(() => {
87
+ setToasterConfig({ position }, toasterId);
88
+ }, [position, toasterId]);
89
+ const timersRef = useRef(/* @__PURE__ */ new Map());
90
+ const remainingRef = useRef(/* @__PURE__ */ new Map());
91
+ useEffect(() => {
92
+ const currentIds = new Set(state.toasts.map((t) => t.id));
93
+ timersRef.current.forEach((timer, id) => {
94
+ if (!currentIds.has(id)) {
95
+ clearTimeout(timer);
96
+ timersRef.current.delete(id);
97
+ remainingRef.current.delete(id);
98
+ }
99
+ });
100
+ state.toasts.forEach((toast) => {
101
+ var _a;
102
+ if (toast.type === "loading") return;
103
+ const toastDuration = toast.duration ?? duration;
104
+ if (toastDuration <= 0) return;
105
+ const hasTimer = timersRef.current.has(toast.id);
106
+ if (hovering) {
107
+ if (hasTimer) {
108
+ clearTimeout(timersRef.current.get(toast.id));
109
+ timersRef.current.delete(toast.id);
110
+ const elapsed = Date.now() - toast.createdAt;
111
+ const remaining = Math.max(0, toastDuration - elapsed);
112
+ remainingRef.current.set(toast.id, remaining);
113
+ }
114
+ } else {
115
+ if (!hasTimer) {
116
+ let delay = remainingRef.current.get(toast.id);
117
+ if (delay === void 0) {
118
+ const elapsed = Date.now() - toast.createdAt;
119
+ delay = Math.max(0, toastDuration - elapsed);
120
+ }
121
+ remainingRef.current.delete(toast.id);
122
+ if (delay <= 0) {
123
+ (_a = toast.onAutoClose) == null ? void 0 : _a.call(toast);
124
+ dismiss(toast.id, toasterId);
125
+ return;
126
+ }
127
+ const timer = setTimeout(() => {
128
+ var _a2;
129
+ (_a2 = toast.onAutoClose) == null ? void 0 : _a2.call(toast);
130
+ dismiss(toast.id, toasterId);
131
+ timersRef.current.delete(toast.id);
132
+ remainingRef.current.delete(toast.id);
133
+ }, delay);
134
+ timersRef.current.set(toast.id, timer);
135
+ }
136
+ }
137
+ });
138
+ }, [state.toasts, duration, hovering, toasterId]);
139
+ useEffect(() => {
140
+ return () => {
141
+ timersRef.current.forEach((timer) => clearTimeout(timer));
142
+ timersRef.current.clear();
143
+ remainingRef.current.clear();
144
+ };
145
+ }, []);
146
+ const handleMouseEnter = useEventCallback(() => {
147
+ setHovering(true);
148
+ setExpanded(true, toasterId);
149
+ });
150
+ const handleMouseLeave = useEventCallback(() => {
151
+ setHovering(false);
152
+ setExpanded(false, toasterId);
153
+ });
154
+ const handleKeyDown = useEventCallback((e) => {
155
+ var _a;
156
+ if (e.key === "F6" && state.toasts.length > 0) {
157
+ e.preventDefault();
158
+ const firstToast = (_a = internalRef.current) == null ? void 0 : _a.querySelector(
159
+ '[role="alertdialog"], [role="status"]'
160
+ );
161
+ if (firstToast instanceof HTMLElement) {
162
+ firstToast.focus();
163
+ }
164
+ }
165
+ });
166
+ const visibleToastsList = useMemo(
167
+ () => state.toasts.slice(0, visibleToasts),
168
+ [state.toasts, visibleToasts]
169
+ );
170
+ useEffect(() => {
171
+ if (visibleToastsList.length === 0 && hovering) {
172
+ setHovering(false);
173
+ setExpanded(false, toasterId);
174
+ }
175
+ }, [visibleToastsList.length, hovering, toasterId]);
176
+ const containerHeight = useMemo(() => {
177
+ var _a;
178
+ if (visibleToastsList.length === 0) return void 0;
179
+ if (state.expanded) {
180
+ const totalHeight = visibleToastsList.reduce((acc, toast, index) => {
181
+ const height = toast.height || DEFAULT_HEIGHT;
182
+ const gap = index < visibleToastsList.length - 1 ? GAP : 0;
183
+ return acc + height + gap;
184
+ }, 0);
185
+ return totalHeight;
186
+ } else {
187
+ const frontmostHeight = ((_a = visibleToastsList[0]) == null ? void 0 : _a.height) || DEFAULT_HEIGHT;
188
+ const peekOffset = (visibleToastsList.length - 1) * 8;
189
+ return frontmostHeight + peekOffset;
190
+ }
191
+ }, [state.expanded, visibleToastsList]);
192
+ const toastHeights = useMemo(
193
+ () => visibleToastsList.map((t) => t.height ?? 0),
194
+ [visibleToastsList]
195
+ );
196
+ const tv = toastViewportTv({ position, expanded: state.expanded, layout });
197
+ const viewportStyle = useMemo(() => {
198
+ var _a;
199
+ const frontmostHeight = (_a = visibleToastsList[0]) == null ? void 0 : _a.height;
200
+ return {
201
+ "--toast-frontmost-height": frontmostHeight ? `${frontmostHeight}px` : void 0,
202
+ "--toast-offset": `${offset}px`,
203
+ height: containerHeight ? `${containerHeight}px` : void 0
204
+ };
205
+ }, [visibleToastsList, offset, containerHeight]);
206
+ useEffect(() => {
207
+ if (portal && !container) {
208
+ portalRefCount++;
209
+ return releaseSharedPortalContainer;
210
+ }
211
+ }, [portal, container]);
212
+ if (visibleToastsList.length === 0) return null;
213
+ const content = /* @__PURE__ */ jsx(
214
+ "div",
215
+ {
216
+ ref: mergeRefs(internalRef, ref),
217
+ role: "region",
218
+ "aria-live": "polite",
219
+ "aria-atomic": "false",
220
+ "aria-relevant": "additions text",
221
+ "aria-label": label,
222
+ tabIndex: -1,
223
+ "data-toaster": true,
224
+ "data-toaster-id": toasterId,
225
+ "data-position": position,
226
+ style: viewportStyle,
227
+ className: tcx(tv, className),
228
+ onKeyDown: handleKeyDown,
229
+ onMouseEnter: handleMouseEnter,
230
+ onMouseLeave: handleMouseLeave,
231
+ children: /* @__PURE__ */ jsx(AnimatePresence, { children: visibleToastsList.map((toast, index) => /* @__PURE__ */ jsx(
232
+ ToasterItem,
233
+ {
234
+ toast,
235
+ index,
236
+ total: visibleToastsList.length,
237
+ expanded: state.expanded,
238
+ position,
239
+ toasterId,
240
+ toastHeights,
241
+ slotProps: collectedSlots,
242
+ showProgress,
243
+ defaultDuration: duration,
244
+ isPaused: hovering,
245
+ layout
246
+ },
247
+ toast.id
248
+ )) })
249
+ }
250
+ );
251
+ if (!portal) {
252
+ return content;
253
+ }
254
+ const portalContainer = container ?? getSharedPortalContainer();
255
+ if (!portalContainer) {
256
+ return content;
257
+ }
258
+ return createPortal(content, portalContainer);
259
+ })
260
+ );
261
+ ToasterRoot.displayName = "Toaster";
262
+ const Toaster = Object.assign(ToasterRoot, {
263
+ Item: ToasterItemSlot,
264
+ Icon: ToasterIconSlot,
265
+ Title: ToasterTitleSlot,
266
+ Description: ToasterDescriptionSlot,
267
+ Actions: ToasterActionsSlot
268
+ });
269
+ export {
270
+ Toaster
271
+ };