@particle-academy/react-fancy 5.40.0 → 5.41.1

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.
@@ -0,0 +1,300 @@
1
+ 'use strict';
2
+
3
+ var chunkMOU6O324_cjs = require('./chunk-MOU6O324.cjs');
4
+ var chunkNBZC6LOB_cjs = require('./chunk-NBZC6LOB.cjs');
5
+ var chunkSNHU2AI4_cjs = require('./chunk-SNHU2AI4.cjs');
6
+ var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
7
+ var react = require('react');
8
+ var lucideReact = require('lucide-react');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ var ToastContext = react.createContext(null);
12
+ function useToast() {
13
+ const ctx = react.useContext(ToastContext);
14
+ if (!ctx) {
15
+ throw new Error("useToast must be used within a <Toast.Provider>");
16
+ }
17
+ return ctx;
18
+ }
19
+ var VARIANT_STYLES = {
20
+ default: "border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900",
21
+ success: "border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950",
22
+ error: "border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950",
23
+ warning: "border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950",
24
+ info: "border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950"
25
+ };
26
+ var VARIANT_ICON_COLORS = {
27
+ default: "text-zinc-400",
28
+ success: "text-emerald-500",
29
+ error: "text-red-500",
30
+ warning: "text-amber-500",
31
+ info: "text-blue-500"
32
+ };
33
+ function ToastItem({ data, onDismiss }) {
34
+ const { id, title, description, variant = "default", action } = data;
35
+ const duration = data.duration ?? (action ? 0 : 5e3);
36
+ react.useEffect(() => {
37
+ if (duration <= 0) return;
38
+ const timer = setTimeout(() => onDismiss(id), duration);
39
+ return () => clearTimeout(timer);
40
+ }, [id, duration, onDismiss]);
41
+ return /* @__PURE__ */ jsxRuntime.jsx(
42
+ "div",
43
+ {
44
+ "data-react-fancy-toast-item": "",
45
+ role: "alert",
46
+ onKeyDown: (e) => {
47
+ if (e.key === "Escape") onDismiss(id);
48
+ },
49
+ className: chunkZU5Q77OT_cjs.cn(
50
+ "fancy-toast-in pointer-events-auto w-80 rounded-xl border p-4 shadow-lg",
51
+ VARIANT_STYLES[variant]
52
+ ),
53
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
54
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkZU5Q77OT_cjs.cn("mt-0.5 shrink-0", VARIANT_ICON_COLORS[variant]), children: [
55
+ variant === "success" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { size: 16 }),
56
+ variant === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { size: 16 }),
57
+ variant === "warning" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { size: 16 }),
58
+ variant === "info" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { size: 16 })
59
+ ] }),
60
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
61
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-zinc-900 dark:text-zinc-100", children: title }),
62
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400", children: description })
63
+ ] }),
64
+ action && /* @__PURE__ */ jsxRuntime.jsx(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ onClick: () => {
69
+ action.onClick();
70
+ onDismiss(id);
71
+ },
72
+ className: "shrink-0 self-center rounded-md px-2 py-1 text-xs font-medium text-zinc-700 underline-offset-2 transition-colors hover:bg-zinc-100 hover:underline dark:text-zinc-200 dark:hover:bg-zinc-800",
73
+ children: action.label
74
+ }
75
+ ),
76
+ /* @__PURE__ */ jsxRuntime.jsx(
77
+ "button",
78
+ {
79
+ type: "button",
80
+ onClick: () => onDismiss(id),
81
+ className: "shrink-0 rounded p-0.5 text-zinc-400 transition-colors hover:text-zinc-600 dark:hover:text-zinc-300",
82
+ "aria-label": "Dismiss",
83
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14 })
84
+ }
85
+ )
86
+ ] })
87
+ }
88
+ );
89
+ }
90
+ ToastItem.displayName = "ToastItem";
91
+ var POSITION_STYLES = {
92
+ "top-right": "top-4 right-4",
93
+ "top-left": "top-4 left-4",
94
+ "bottom-right": "bottom-4 right-4",
95
+ "bottom-left": "bottom-4 left-4"
96
+ };
97
+ var WHEEL_STEP = 50;
98
+ var CARD = "rounded-xl border border-zinc-200 bg-white p-4 shadow-lg dark:border-zinc-700 dark:bg-zinc-900";
99
+ function defaultKey(item, index) {
100
+ const id = item?.id;
101
+ return typeof id === "string" || typeof id === "number" ? String(id) : String(index);
102
+ }
103
+ function isTextField(target) {
104
+ if (!(target instanceof HTMLElement)) return false;
105
+ return target.isContentEditable || target.getAttribute("contenteditable") === "true" || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName);
106
+ }
107
+ function ToastStack({
108
+ items,
109
+ renderItem,
110
+ getKey = defaultKey,
111
+ depth = 2,
112
+ offset = 8,
113
+ scaleStep = 0.05,
114
+ frontIndex: controlledFront,
115
+ defaultFrontIndex = 0,
116
+ onFrontIndexChange,
117
+ position = "bottom-right",
118
+ label = "Notifications",
119
+ cardClassName,
120
+ className
121
+ }) {
122
+ const [rawFront, setFront] = chunkSNHU2AI4_cjs.useControllableState(
123
+ controlledFront,
124
+ defaultFrontIndex,
125
+ onFrontIndexChange
126
+ );
127
+ const count = items.length;
128
+ const front = count === 0 ? 0 : (rawFront % count + count) % count;
129
+ const stackRef = react.useRef(null);
130
+ const wheelTravel = react.useRef(0);
131
+ const live = react.useRef({ front, count });
132
+ live.current = { front, count };
133
+ const step = (by) => {
134
+ const { front: current, count: n } = live.current;
135
+ if (n < 2) return;
136
+ setFront(((current + by) % n + n) % n);
137
+ };
138
+ const stepRef = react.useRef(step);
139
+ stepRef.current = step;
140
+ react.useEffect(() => {
141
+ const el = stackRef.current;
142
+ if (!el) return;
143
+ const onWheel = (e) => {
144
+ if (live.current.count < 2 || e.deltaY === 0) return;
145
+ e.preventDefault();
146
+ if (e.deltaMode !== 0) {
147
+ wheelTravel.current = 0;
148
+ stepRef.current(Math.sign(e.deltaY));
149
+ return;
150
+ }
151
+ if (Math.abs(e.deltaY) >= WHEEL_STEP) {
152
+ wheelTravel.current = 0;
153
+ stepRef.current(Math.sign(e.deltaY));
154
+ return;
155
+ }
156
+ wheelTravel.current += e.deltaY;
157
+ if (Math.abs(wheelTravel.current) >= WHEEL_STEP) {
158
+ stepRef.current(Math.sign(wheelTravel.current));
159
+ wheelTravel.current = 0;
160
+ }
161
+ };
162
+ el.addEventListener("wheel", onWheel, { passive: false });
163
+ return () => el.removeEventListener("wheel", onWheel);
164
+ }, [count > 0, position]);
165
+ if (count === 0) return null;
166
+ const visibleBehind = Math.min(Math.max(0, depth), count - 1);
167
+ const hidden = count - 1 - visibleBehind;
168
+ const card = (index, k) => {
169
+ const item = items[index];
170
+ const isFront = k === 0;
171
+ return /* @__PURE__ */ jsxRuntime.jsx(
172
+ "div",
173
+ {
174
+ "data-react-fancy-toast-stack-card": isFront ? "front" : "behind",
175
+ "aria-hidden": isFront ? void 0 : true,
176
+ inert: isFront ? void 0 : true,
177
+ className: chunkZU5Q77OT_cjs.cn(
178
+ CARD,
179
+ "origin-top transition-transform duration-200",
180
+ isFront ? "relative" : "pointer-events-none absolute inset-0 overflow-hidden",
181
+ cardClassName
182
+ ),
183
+ style: {
184
+ zIndex: depth + 1 - k,
185
+ transform: isFront ? void 0 : `translateY(-${k * offset}px) scale(${1 - k * scaleStep})`
186
+ },
187
+ children: renderItem(item, { index, isFront })
188
+ },
189
+ getKey(item, index)
190
+ );
191
+ };
192
+ const stackEl = /* @__PURE__ */ jsxRuntime.jsxs(
193
+ "div",
194
+ {
195
+ ref: stackRef,
196
+ "data-react-fancy-toast-stack": "",
197
+ role: "region",
198
+ "aria-label": label,
199
+ tabIndex: 0,
200
+ onKeyDown: (e) => {
201
+ if (isTextField(e.target)) return;
202
+ if (e.key === "ArrowDown" || e.key === "ArrowRight") {
203
+ e.preventDefault();
204
+ step(1);
205
+ } else if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
206
+ e.preventDefault();
207
+ step(-1);
208
+ }
209
+ },
210
+ className: chunkZU5Q77OT_cjs.cn(
211
+ "pointer-events-auto relative w-80 rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-violet-500 focus-visible:ring-offset-2",
212
+ className
213
+ ),
214
+ style: { paddingTop: visibleBehind * offset },
215
+ children: [
216
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
217
+ Array.from({ length: visibleBehind }, (_, i) => i + 1).map(
218
+ (k) => card((front + k) % count, k)
219
+ ),
220
+ card(front, 0)
221
+ ] }),
222
+ hidden > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
223
+ chunkMOU6O324_cjs.Badge,
224
+ {
225
+ "data-react-fancy-toast-stack-more": "",
226
+ size: "sm",
227
+ variant: "soft",
228
+ color: "zinc",
229
+ className: "absolute -top-2 right-2 z-20",
230
+ children: [
231
+ "+",
232
+ hidden
233
+ ]
234
+ }
235
+ ),
236
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-react-fancy-toast-stack-status": "", "aria-live": "polite", className: "sr-only", children: count > 1 ? `${front + 1} of ${count}` : "" })
237
+ ]
238
+ }
239
+ );
240
+ if (position === "inline") return stackEl;
241
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkNBZC6LOB_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
242
+ "div",
243
+ {
244
+ "data-react-fancy-toast-stack-position": position,
245
+ className: chunkZU5Q77OT_cjs.cn("pointer-events-none fixed z-[100]", POSITION_STYLES[position]),
246
+ children: stackEl
247
+ }
248
+ ) });
249
+ }
250
+ ToastStack.displayName = "ToastStack";
251
+ var POSITION_STYLES2 = {
252
+ "top-right": "top-4 right-4",
253
+ "top-left": "top-4 left-4",
254
+ "bottom-right": "bottom-4 right-4",
255
+ "bottom-left": "bottom-4 left-4"
256
+ };
257
+ function ToastProvider({
258
+ children,
259
+ position = "bottom-right",
260
+ maxToasts = 5
261
+ }) {
262
+ const [toasts, setToasts] = react.useState([]);
263
+ const idCounter = react.useRef(0);
264
+ const toast = react.useCallback(
265
+ (data) => {
266
+ const id = `toast-${++idCounter.current}`;
267
+ setToasts((prev) => [...prev.slice(-(maxToasts - 1)), { ...data, id }]);
268
+ return id;
269
+ },
270
+ [maxToasts]
271
+ );
272
+ const dismiss = react.useCallback((id) => {
273
+ setToasts((prev) => prev.filter((t) => t.id !== id));
274
+ }, []);
275
+ const ctx = react.useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);
276
+ return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: ctx, children: [
277
+ children,
278
+ /* @__PURE__ */ jsxRuntime.jsx(chunkNBZC6LOB_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
279
+ "div",
280
+ {
281
+ "data-react-fancy-toast": "",
282
+ className: chunkZU5Q77OT_cjs.cn(
283
+ "fixed z-[100] flex flex-col gap-2 pointer-events-none",
284
+ POSITION_STYLES2[position]
285
+ ),
286
+ children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToastItem, { data: t, onDismiss: dismiss }, t.id))
287
+ }
288
+ ) })
289
+ ] });
290
+ }
291
+ var Toast = {
292
+ Provider: ToastProvider,
293
+ Stack: ToastStack,
294
+ Item: ToastItem
295
+ };
296
+
297
+ exports.Toast = Toast;
298
+ exports.useToast = useToast;
299
+ //# sourceMappingURL=chunk-UBZFOTZN.cjs.map
300
+ //# sourceMappingURL=chunk-UBZFOTZN.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Toast/Toast.context.ts","../src/components/Toast/ToastItem.tsx","../src/components/Toast/ToastStack.tsx","../src/components/Toast/Toast.tsx"],"names":["createContext","useContext","useEffect","jsx","cn","jsxs","Check","XCircle","AlertTriangle","Info","X","useControllableState","useRef","Badge","Portal","POSITION_STYLES","useState","useCallback","useMemo"],"mappings":"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","file":"chunk-UBZFOTZN.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ToastContextValue } from \"./Toast.types\";\n\nexport const ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a <Toast.Provider>\");\n }\n return ctx;\n}\n","import { useEffect } from \"react\";\nimport { AlertTriangle, Check, Info, X, XCircle } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { ToastItemProps } from \"./Toast.types\";\n\nconst VARIANT_STYLES = {\n default:\n \"border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900\",\n success:\n \"border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950\",\n error:\n \"border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950\",\n warning:\n \"border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950\",\n info: \"border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950\",\n} as const;\n\nconst VARIANT_ICON_COLORS = {\n default: \"text-zinc-400\",\n success: \"text-emerald-500\",\n error: \"text-red-500\",\n warning: \"text-amber-500\",\n info: \"text-blue-500\",\n} as const;\n\nexport function ToastItem({ data, onDismiss }: ToastItemProps) {\n const { id, title, description, variant = \"default\", action } = data;\n // An action toast does not expire by default.\n const duration = data.duration ?? (action ? 0 : 5000);\n\n useEffect(() => {\n if (duration <= 0) return;\n const timer = setTimeout(() => onDismiss(id), duration);\n return () => clearTimeout(timer);\n }, [id, duration, onDismiss]);\n\n return (\n <div\n data-react-fancy-toast-item=\"\"\n role=\"alert\"\n // Scoped to the toast rather than the document: a global Escape handler\n // would fight whatever modal or drawer is already listening.\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onDismiss(id);\n }}\n className={cn(\n \"fancy-toast-in pointer-events-auto w-80 rounded-xl border p-4 shadow-lg\",\n VARIANT_STYLES[variant],\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className={cn(\"mt-0.5 shrink-0\", VARIANT_ICON_COLORS[variant])}>\n {variant === \"success\" && <Check size={16} />}\n {variant === \"error\" && <XCircle size={16} />}\n {variant === \"warning\" && <AlertTriangle size={16} />}\n {variant === \"info\" && <Info size={16} />}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-zinc-900 dark:text-zinc-100\">{title}</p>\n {description && (\n <p className=\"mt-1 text-xs text-zinc-500 dark:text-zinc-400\">\n {description}\n </p>\n )}\n </div>\n {action && (\n <button\n type=\"button\"\n onClick={() => {\n action.onClick();\n // The offer is consumed; leaving it up invites undoing an\n // already-undone action.\n onDismiss(id);\n }}\n className=\"shrink-0 self-center rounded-md px-2 py-1 text-xs font-medium text-zinc-700 underline-offset-2 transition-colors hover:bg-zinc-100 hover:underline dark:text-zinc-200 dark:hover:bg-zinc-800\"\n >\n {action.label}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onDismiss(id)}\n className=\"shrink-0 rounded p-0.5 text-zinc-400 transition-colors hover:text-zinc-600 dark:hover:text-zinc-300\"\n aria-label=\"Dismiss\"\n >\n <X size={14} />\n </button>\n </div>\n </div>\n );\n}\n\nToastItem.displayName = \"ToastItem\";\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport { Portal } from \"../Portal\";\nimport { Badge } from \"../Badge\";\nimport type { ToastPosition } from \"./Toast.types\";\n\nexport interface ToastStackProps<T> {\n /**\n * Everything to show — the stack is a VIEW of this list and owns none of it.\n * There is no limit and no timer: an item leaves only when you remove it.\n */\n items: readonly T[];\n /** One card's content, actions included. Only the front card is interactive. */\n renderItem: (item: T, state: { index: number; isFront: boolean }) => ReactNode;\n /** A stable key per item. Defaults to `item.id`, then the index. */\n getKey?: (item: T, index: number) => string;\n /** How many cards show behind the front one. Default 2. */\n depth?: number;\n /** How far each card behind peeks out above the one in front, in px. Default 8. */\n offset?: number;\n /** How much smaller each card behind is than the one in front. Default 0.05. */\n scaleStep?: number;\n /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */\n frontIndex?: number;\n defaultFrontIndex?: number;\n onFrontIndexChange?: (index: number) => void;\n /** A screen corner, or `\"inline\"` to render where it is placed. Default `\"bottom-right\"`. */\n position?: ToastPosition | \"inline\";\n /** The stack's accessible name. Default \"Notifications\". */\n label?: string;\n /** Classes for each card's shell, merged onto the defaults. */\n cardClassName?: string;\n className?: string;\n}\n\nconst POSITION_STYLES: Record<ToastPosition, string> = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n};\n\n/** Pixels of wheel travel that count as one step. A mouse notch is ~100; a trackpad sends many small ones. */\nconst WHEEL_STEP = 50;\n\nconst CARD =\n \"rounded-xl border border-zinc-200 bg-white p-4 shadow-lg dark:border-zinc-700 dark:bg-zinc-900\";\n\nfunction defaultKey(item: unknown, index: number): string {\n const id = (item as { id?: unknown } | null)?.id;\n return typeof id === \"string\" || typeof id === \"number\" ? String(id) : String(index);\n}\n\nfunction isTextField(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.isContentEditable ||\n target.getAttribute(\"contenteditable\") === \"true\" ||\n /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName)\n );\n}\n\n/**\n * A controlled stack of actionable toasts — approval requests, say — that the\n * person walks through rather than races.\n *\n * Built for react-fancy#33. The owner's requirements were that requests stack\n * behind each other with a slight top offset, that scrolling over the stack\n * walks through them, and that a pending request NEVER expires or disappears.\n * The last is why this is a view of the caller's list rather than a queue it\n * keeps: there is nothing here that can drop an item, because nothing here owns\n * one. (The imperative provider's `maxToasts` silently drops the oldest.)\n */\nexport function ToastStack<T>({\n items,\n renderItem,\n getKey = defaultKey,\n depth = 2,\n offset = 8,\n scaleStep = 0.05,\n frontIndex: controlledFront,\n defaultFrontIndex = 0,\n onFrontIndexChange,\n position = \"bottom-right\",\n label = \"Notifications\",\n cardClassName,\n className,\n}: ToastStackProps<T>) {\n const [rawFront, setFront] = useControllableState(\n controlledFront,\n defaultFrontIndex,\n onFrontIndexChange,\n );\n const count = items.length;\n // Clamped for display rather than corrected through onChange: a list that\n // shrinks under a far-forward index must not make render report a change.\n const front = count === 0 ? 0 : ((rawFront % count) + count) % count;\n\n const stackRef = useRef<HTMLDivElement>(null);\n const wheelTravel = useRef(0);\n const live = useRef({ front, count });\n live.current = { front, count };\n\n const step = (by: number) => {\n const { front: current, count: n } = live.current;\n if (n < 2) return;\n setFront((((current + by) % n) + n) % n);\n };\n const stepRef = useRef(step);\n stepRef.current = step;\n\n /*\n * A native listener, because React's wheel listener is passive and cannot stop\n * the page scrolling underneath — and a stack that cycles AND scrolls the page\n * moves two things at once under the person's hand.\n */\n useEffect(() => {\n const el = stackRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (live.current.count < 2 || e.deltaY === 0) return;\n e.preventDefault();\n\n // Line or page mode: every event is a notch.\n if (e.deltaMode !== 0) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n // A notch-sized event steps at once; small trackpad deltas add up first.\n if (Math.abs(e.deltaY) >= WHEEL_STEP) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n wheelTravel.current += e.deltaY;\n if (Math.abs(wheelTravel.current) >= WHEEL_STEP) {\n stepRef.current(Math.sign(wheelTravel.current));\n wheelTravel.current = 0;\n }\n };\n\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n // Re-bound when the element can change: it appears with the first item, and\n // moving between a corner and inline remounts it.\n }, [count > 0, position]);\n\n if (count === 0) return null;\n\n const visibleBehind = Math.min(Math.max(0, depth), count - 1);\n const hidden = count - 1 - visibleBehind;\n\n const card = (index: number, k: number) => {\n const item = items[index];\n const isFront = k === 0;\n return (\n <div\n key={getKey(item, index)}\n data-react-fancy-toast-stack-card={isFront ? \"front\" : \"behind\"}\n aria-hidden={isFront ? undefined : true}\n inert={isFront ? undefined : true}\n className={cn(\n CARD,\n \"origin-top transition-transform duration-200\",\n isFront ? \"relative\" : \"pointer-events-none absolute inset-0 overflow-hidden\",\n cardClassName,\n )}\n style={{\n zIndex: depth + 1 - k,\n transform: isFront ? undefined : `translateY(-${k * offset}px) scale(${1 - k * scaleStep})`,\n }}\n >\n {renderItem(item, { index, isFront })}\n </div>\n );\n };\n\n const stackEl = (\n <div\n ref={stackRef}\n data-react-fancy-toast-stack=\"\"\n role=\"region\"\n aria-label={label}\n tabIndex={0}\n onKeyDown={(e) => {\n if (isTextField(e.target)) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n step(1);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n step(-1);\n }\n }}\n className={cn(\n \"pointer-events-auto relative w-80 rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-violet-500 focus-visible:ring-offset-2\",\n className,\n )}\n style={{ paddingTop: visibleBehind * offset }}\n >\n <div className=\"relative\">\n {/* z-index decides what paints on top; the front card sizes the box. */}\n {Array.from({ length: visibleBehind }, (_, i) => i + 1).map((k) =>\n card((front + k) % count, k),\n )}\n {card(front, 0)}\n </div>\n {hidden > 0 && (\n <Badge\n data-react-fancy-toast-stack-more=\"\"\n size=\"sm\"\n variant=\"soft\"\n color=\"zinc\"\n className=\"absolute -top-2 right-2 z-20\"\n >\n +{hidden}\n </Badge>\n )}\n <span data-react-fancy-toast-stack-status=\"\" aria-live=\"polite\" className=\"sr-only\">\n {count > 1 ? `${front + 1} of ${count}` : \"\"}\n </span>\n </div>\n );\n\n if (position === \"inline\") return stackEl;\n\n return (\n <Portal>\n <div\n data-react-fancy-toast-stack-position={position}\n className={cn(\"pointer-events-none fixed z-[100]\", POSITION_STYLES[position])}\n >\n {stackEl}\n </div>\n </Portal>\n );\n}\n\nToastStack.displayName = \"ToastStack\";\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ToastContext } from \"./Toast.context\";\nimport { ToastItem } from \"./ToastItem\";\nimport { ToastStack } from \"./ToastStack\";\nimport type { ToastData, ToastProviderProps } from \"./Toast.types\";\n\nconst POSITION_STYLES = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n} as const;\n\nfunction ToastProvider({\n children,\n position = \"bottom-right\",\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastData[]>([]);\n const idCounter = useRef(0);\n\n const toast = useCallback(\n (data: Omit<ToastData, \"id\">) => {\n const id = `toast-${++idCounter.current}`;\n setToasts((prev) => [...prev.slice(-(maxToasts - 1)), { ...data, id }]);\n return id;\n },\n [maxToasts],\n );\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const ctx = useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);\n\n return (\n <ToastContext.Provider value={ctx}>\n {children}\n <Portal>\n <div\n data-react-fancy-toast=\"\"\n className={cn(\n \"fixed z-[100] flex flex-col gap-2 pointer-events-none\",\n POSITION_STYLES[position],\n )}\n >\n {toasts.map((t) => (\n <ToastItem key={t.id} data={t} onDismiss={dismiss} />\n ))}\n </div>\n </Portal>\n </ToastContext.Provider>\n );\n}\n\nexport const Toast = {\n Provider: ToastProvider,\n Stack: ToastStack,\n Item: ToastItem,\n};\n"]}
package/dist/index.cjs CHANGED
@@ -18,7 +18,7 @@ require('./chunk-XURQVDCN.cjs');
18
18
  var chunkCOH45MGW_cjs = require('./chunk-COH45MGW.cjs');
19
19
  var chunkYMDYDUBH_cjs = require('./chunk-YMDYDUBH.cjs');
20
20
  var chunkRLMU3NHQ_cjs = require('./chunk-RLMU3NHQ.cjs');
21
- var chunk7HMEDY24_cjs = require('./chunk-7HMEDY24.cjs');
21
+ var chunkUBZFOTZN_cjs = require('./chunk-UBZFOTZN.cjs');
22
22
  var chunk7VLRHXLQ_cjs = require('./chunk-7VLRHXLQ.cjs');
23
23
  var chunk5P3PISAX_cjs = require('./chunk-5P3PISAX.cjs');
24
24
  var chunkOS2QC3NE_cjs = require('./chunk-OS2QC3NE.cjs');
@@ -179,11 +179,11 @@ Object.defineProperty(exports, "Timeline", {
179
179
  });
180
180
  Object.defineProperty(exports, "Toast", {
181
181
  enumerable: true,
182
- get: function () { return chunk7HMEDY24_cjs.Toast; }
182
+ get: function () { return chunkUBZFOTZN_cjs.Toast; }
183
183
  });
184
184
  Object.defineProperty(exports, "useToast", {
185
185
  enumerable: true,
186
- get: function () { return chunk7HMEDY24_cjs.useToast; }
186
+ get: function () { return chunkUBZFOTZN_cjs.useToast; }
187
187
  });
188
188
  Object.defineProperty(exports, "TreeNav", {
189
189
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -54,7 +54,7 @@ export { Dropdown, DropdownContextValue, DropdownItemProps, DropdownItemsProps,
54
54
  export { ContextMenu, ContextMenuContentProps, ContextMenuContextValue, ContextMenuItemProps, ContextMenuProps, ContextMenuSeparatorProps, ContextMenuTriggerProps, useContextMenu } from './context-menu.cjs';
55
55
  export { Modal, ModalBodyProps, ModalContextValue, ModalFooterProps, ModalHeaderProps, ModalProps, useModal } from './modal.cjs';
56
56
  export { Drawer, DrawerAttach, DrawerBodyProps, DrawerContainerProps, DrawerContextValue, DrawerFooterProps, DrawerHeaderProps, DrawerProps, DrawerSide, DrawerSize, useDrawer } from './drawer.cjs';
57
- export { Toast, ToastAction, ToastContextValue, ToastData, ToastPosition, ToastProviderProps, ToastVariant, useToast } from './toast.cjs';
57
+ export { Toast, ToastAction, ToastContextValue, ToastData, ToastPosition, ToastProviderProps, ToastStackProps, ToastVariant, useToast } from './toast.cjs';
58
58
  export { Command, CommandContextValue, CommandEmptyProps, CommandGroupProps, CommandInputProps, CommandItemProps, CommandListProps, CommandProps, useCommand } from './command.cjs';
59
59
  export { Tabs, TabsContextValue, TabsListProps, TabsPanelProps, TabsPanelsProps, TabsProps, TabsTabProps, TabsVariant, useTabs } from './tabs.cjs';
60
60
  export { Accordion, AccordionContentProps, AccordionContextValue, AccordionItemProps, AccordionProps, AccordionTriggerProps, useAccordion } from './accordion.cjs';
package/dist/index.d.ts CHANGED
@@ -54,7 +54,7 @@ export { Dropdown, DropdownContextValue, DropdownItemProps, DropdownItemsProps,
54
54
  export { ContextMenu, ContextMenuContentProps, ContextMenuContextValue, ContextMenuItemProps, ContextMenuProps, ContextMenuSeparatorProps, ContextMenuTriggerProps, useContextMenu } from './context-menu.js';
55
55
  export { Modal, ModalBodyProps, ModalContextValue, ModalFooterProps, ModalHeaderProps, ModalProps, useModal } from './modal.js';
56
56
  export { Drawer, DrawerAttach, DrawerBodyProps, DrawerContainerProps, DrawerContextValue, DrawerFooterProps, DrawerHeaderProps, DrawerProps, DrawerSide, DrawerSize, useDrawer } from './drawer.js';
57
- export { Toast, ToastAction, ToastContextValue, ToastData, ToastPosition, ToastProviderProps, ToastVariant, useToast } from './toast.js';
57
+ export { Toast, ToastAction, ToastContextValue, ToastData, ToastPosition, ToastProviderProps, ToastStackProps, ToastVariant, useToast } from './toast.js';
58
58
  export { Command, CommandContextValue, CommandEmptyProps, CommandGroupProps, CommandInputProps, CommandItemProps, CommandListProps, CommandProps, useCommand } from './command.js';
59
59
  export { Tabs, TabsContextValue, TabsListProps, TabsPanelProps, TabsPanelsProps, TabsProps, TabsTabProps, TabsVariant, useTabs } from './tabs.js';
60
60
  export { Accordion, AccordionContentProps, AccordionContextValue, AccordionItemProps, AccordionProps, AccordionTriggerProps, useAccordion } from './accordion.js';
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import './chunk-TMR56BBE.js';
16
16
  export { TimeGrid } from './chunk-7CN7IHES.js';
17
17
  export { TimePicker } from './chunk-OTCLBINT.js';
18
18
  export { Timeline } from './chunk-7JDVCQXD.js';
19
- export { Toast, useToast } from './chunk-JICO4LTT.js';
19
+ export { Toast, useToast } from './chunk-3AQLEMH7.js';
20
20
  export { TreeNav, useTreeNav } from './chunk-NUPQJ5SJ.js';
21
21
  export { Section } from './chunk-SLJD25VV.js';
22
22
  export { Separator } from './chunk-ZLWCZV7R.js';
package/dist/toast.cjs CHANGED
@@ -1,18 +1,21 @@
1
1
  'use strict';
2
2
 
3
- var chunk7HMEDY24_cjs = require('./chunk-7HMEDY24.cjs');
3
+ var chunkUBZFOTZN_cjs = require('./chunk-UBZFOTZN.cjs');
4
+ require('./chunk-VBWRH4UW.cjs');
5
+ require('./chunk-MOU6O324.cjs');
4
6
  require('./chunk-NBZC6LOB.cjs');
7
+ require('./chunk-SNHU2AI4.cjs');
5
8
  require('./chunk-ZU5Q77OT.cjs');
6
9
 
7
10
 
8
11
 
9
12
  Object.defineProperty(exports, "Toast", {
10
13
  enumerable: true,
11
- get: function () { return chunk7HMEDY24_cjs.Toast; }
14
+ get: function () { return chunkUBZFOTZN_cjs.Toast; }
12
15
  });
13
16
  Object.defineProperty(exports, "useToast", {
14
17
  enumerable: true,
15
- get: function () { return chunk7HMEDY24_cjs.useToast; }
18
+ get: function () { return chunkUBZFOTZN_cjs.useToast; }
16
19
  });
17
20
  //# sourceMappingURL=toast.cjs.map
18
21
  //# sourceMappingURL=toast.cjs.map
package/dist/toast.d.cts CHANGED
@@ -44,11 +44,65 @@ interface ToastItemProps {
44
44
  onDismiss: (id: string) => void;
45
45
  }
46
46
 
47
+ declare function ToastItem({ data, onDismiss }: ToastItemProps): react.JSX.Element;
48
+ declare namespace ToastItem {
49
+ var displayName: string;
50
+ }
51
+
52
+ interface ToastStackProps<T> {
53
+ /**
54
+ * Everything to show — the stack is a VIEW of this list and owns none of it.
55
+ * There is no limit and no timer: an item leaves only when you remove it.
56
+ */
57
+ items: readonly T[];
58
+ /** One card's content, actions included. Only the front card is interactive. */
59
+ renderItem: (item: T, state: {
60
+ index: number;
61
+ isFront: boolean;
62
+ }) => ReactNode;
63
+ /** A stable key per item. Defaults to `item.id`, then the index. */
64
+ getKey?: (item: T, index: number) => string;
65
+ /** How many cards show behind the front one. Default 2. */
66
+ depth?: number;
67
+ /** How far each card behind peeks out above the one in front, in px. Default 8. */
68
+ offset?: number;
69
+ /** How much smaller each card behind is than the one in front. Default 0.05. */
70
+ scaleStep?: number;
71
+ /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */
72
+ frontIndex?: number;
73
+ defaultFrontIndex?: number;
74
+ onFrontIndexChange?: (index: number) => void;
75
+ /** A screen corner, or `"inline"` to render where it is placed. Default `"bottom-right"`. */
76
+ position?: ToastPosition | "inline";
77
+ /** The stack's accessible name. Default "Notifications". */
78
+ label?: string;
79
+ /** Classes for each card's shell, merged onto the defaults. */
80
+ cardClassName?: string;
81
+ className?: string;
82
+ }
83
+ /**
84
+ * A controlled stack of actionable toasts — approval requests, say — that the
85
+ * person walks through rather than races.
86
+ *
87
+ * Built for react-fancy#33. The owner's requirements were that requests stack
88
+ * behind each other with a slight top offset, that scrolling over the stack
89
+ * walks through them, and that a pending request NEVER expires or disappears.
90
+ * The last is why this is a view of the caller's list rather than a queue it
91
+ * keeps: there is nothing here that can drop an item, because nothing here owns
92
+ * one. (The imperative provider's `maxToasts` silently drops the oldest.)
93
+ */
94
+ declare function ToastStack<T>({ items, renderItem, getKey, depth, offset, scaleStep, frontIndex: controlledFront, defaultFrontIndex, onFrontIndexChange, position, label, cardClassName, className, }: ToastStackProps<T>): react.JSX.Element | null;
95
+ declare namespace ToastStack {
96
+ var displayName: string;
97
+ }
98
+
47
99
  declare function ToastProvider({ children, position, maxToasts, }: ToastProviderProps): react.JSX.Element;
48
100
  declare const Toast: {
49
101
  Provider: typeof ToastProvider;
102
+ Stack: typeof ToastStack;
103
+ Item: typeof ToastItem;
50
104
  };
51
105
 
52
106
  declare function useToast(): ToastContextValue;
53
107
 
54
- export { Toast, type ToastAction, type ToastContextValue, type ToastData, type ToastItemProps, type ToastPosition, type ToastProviderProps, type ToastVariant, useToast };
108
+ export { Toast, type ToastAction, type ToastContextValue, type ToastData, type ToastItemProps, type ToastPosition, type ToastProviderProps, type ToastStackProps, type ToastVariant, useToast };
package/dist/toast.d.ts CHANGED
@@ -44,11 +44,65 @@ interface ToastItemProps {
44
44
  onDismiss: (id: string) => void;
45
45
  }
46
46
 
47
+ declare function ToastItem({ data, onDismiss }: ToastItemProps): react.JSX.Element;
48
+ declare namespace ToastItem {
49
+ var displayName: string;
50
+ }
51
+
52
+ interface ToastStackProps<T> {
53
+ /**
54
+ * Everything to show — the stack is a VIEW of this list and owns none of it.
55
+ * There is no limit and no timer: an item leaves only when you remove it.
56
+ */
57
+ items: readonly T[];
58
+ /** One card's content, actions included. Only the front card is interactive. */
59
+ renderItem: (item: T, state: {
60
+ index: number;
61
+ isFront: boolean;
62
+ }) => ReactNode;
63
+ /** A stable key per item. Defaults to `item.id`, then the index. */
64
+ getKey?: (item: T, index: number) => string;
65
+ /** How many cards show behind the front one. Default 2. */
66
+ depth?: number;
67
+ /** How far each card behind peeks out above the one in front, in px. Default 8. */
68
+ offset?: number;
69
+ /** How much smaller each card behind is than the one in front. Default 0.05. */
70
+ scaleStep?: number;
71
+ /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */
72
+ frontIndex?: number;
73
+ defaultFrontIndex?: number;
74
+ onFrontIndexChange?: (index: number) => void;
75
+ /** A screen corner, or `"inline"` to render where it is placed. Default `"bottom-right"`. */
76
+ position?: ToastPosition | "inline";
77
+ /** The stack's accessible name. Default "Notifications". */
78
+ label?: string;
79
+ /** Classes for each card's shell, merged onto the defaults. */
80
+ cardClassName?: string;
81
+ className?: string;
82
+ }
83
+ /**
84
+ * A controlled stack of actionable toasts — approval requests, say — that the
85
+ * person walks through rather than races.
86
+ *
87
+ * Built for react-fancy#33. The owner's requirements were that requests stack
88
+ * behind each other with a slight top offset, that scrolling over the stack
89
+ * walks through them, and that a pending request NEVER expires or disappears.
90
+ * The last is why this is a view of the caller's list rather than a queue it
91
+ * keeps: there is nothing here that can drop an item, because nothing here owns
92
+ * one. (The imperative provider's `maxToasts` silently drops the oldest.)
93
+ */
94
+ declare function ToastStack<T>({ items, renderItem, getKey, depth, offset, scaleStep, frontIndex: controlledFront, defaultFrontIndex, onFrontIndexChange, position, label, cardClassName, className, }: ToastStackProps<T>): react.JSX.Element | null;
95
+ declare namespace ToastStack {
96
+ var displayName: string;
97
+ }
98
+
47
99
  declare function ToastProvider({ children, position, maxToasts, }: ToastProviderProps): react.JSX.Element;
48
100
  declare const Toast: {
49
101
  Provider: typeof ToastProvider;
102
+ Stack: typeof ToastStack;
103
+ Item: typeof ToastItem;
50
104
  };
51
105
 
52
106
  declare function useToast(): ToastContextValue;
53
107
 
54
- export { Toast, type ToastAction, type ToastContextValue, type ToastData, type ToastItemProps, type ToastPosition, type ToastProviderProps, type ToastVariant, useToast };
108
+ export { Toast, type ToastAction, type ToastContextValue, type ToastData, type ToastItemProps, type ToastPosition, type ToastProviderProps, type ToastStackProps, type ToastVariant, useToast };
package/dist/toast.js CHANGED
@@ -1,5 +1,8 @@
1
- export { Toast, useToast } from './chunk-JICO4LTT.js';
1
+ export { Toast, useToast } from './chunk-3AQLEMH7.js';
2
+ import './chunk-IQ4KQJAO.js';
3
+ import './chunk-6FCQD2KQ.js';
2
4
  import './chunk-WHEXTDPV.js';
5
+ import './chunk-EDYAXGUM.js';
3
6
  import './chunk-MMW2JGKZ.js';
4
7
  //# sourceMappingURL=toast.js.map
5
8
  //# sourceMappingURL=toast.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/react-fancy",
3
- "version": "5.40.0",
3
+ "version": "5.41.1",
4
4
  "description": "React UI component library for Human+ UX — controlled, agent-bridgeable primitives",
5
5
  "repository": {
6
6
  "type": "git",