@fluix-ui/react 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,760 @@
1
+ 'use strict';
2
+
3
+ var core = require('@fluix-ui/core');
4
+ var react = require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/index.ts
8
+ function DefaultIcon({ state }) {
9
+ switch (state) {
10
+ case "success":
11
+ return /* @__PURE__ */ jsxRuntime.jsx(
12
+ "svg",
13
+ {
14
+ width: "14",
15
+ height: "14",
16
+ viewBox: "0 0 24 24",
17
+ fill: "none",
18
+ stroke: "currentColor",
19
+ strokeWidth: "2.5",
20
+ strokeLinecap: "round",
21
+ strokeLinejoin: "round",
22
+ "aria-hidden": true,
23
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" })
24
+ }
25
+ );
26
+ case "error":
27
+ return /* @__PURE__ */ jsxRuntime.jsxs(
28
+ "svg",
29
+ {
30
+ width: "14",
31
+ height: "14",
32
+ viewBox: "0 0 24 24",
33
+ fill: "none",
34
+ stroke: "currentColor",
35
+ strokeWidth: "2.5",
36
+ strokeLinecap: "round",
37
+ strokeLinejoin: "round",
38
+ "aria-hidden": true,
39
+ children: [
40
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
41
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
42
+ ]
43
+ }
44
+ );
45
+ case "warning":
46
+ return /* @__PURE__ */ jsxRuntime.jsxs(
47
+ "svg",
48
+ {
49
+ width: "14",
50
+ height: "14",
51
+ viewBox: "0 0 24 24",
52
+ fill: "none",
53
+ stroke: "currentColor",
54
+ strokeWidth: "2.5",
55
+ strokeLinecap: "round",
56
+ strokeLinejoin: "round",
57
+ "aria-hidden": true,
58
+ children: [
59
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
60
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
61
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
62
+ ]
63
+ }
64
+ );
65
+ case "info":
66
+ return /* @__PURE__ */ jsxRuntime.jsxs(
67
+ "svg",
68
+ {
69
+ width: "14",
70
+ height: "14",
71
+ viewBox: "0 0 24 24",
72
+ fill: "none",
73
+ stroke: "currentColor",
74
+ strokeWidth: "2.5",
75
+ strokeLinecap: "round",
76
+ strokeLinejoin: "round",
77
+ "aria-hidden": true,
78
+ children: [
79
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
80
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
81
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
82
+ ]
83
+ }
84
+ );
85
+ case "loading":
86
+ return /* @__PURE__ */ jsxRuntime.jsxs(
87
+ "svg",
88
+ {
89
+ width: "14",
90
+ height: "14",
91
+ viewBox: "0 0 24 24",
92
+ fill: "none",
93
+ stroke: "currentColor",
94
+ strokeWidth: "2.5",
95
+ strokeLinecap: "round",
96
+ strokeLinejoin: "round",
97
+ "aria-hidden": true,
98
+ "data-fluix-icon": "spin",
99
+ children: [
100
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }),
101
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }),
102
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }),
103
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }),
104
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }),
105
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }),
106
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }),
107
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })
108
+ ]
109
+ }
110
+ );
111
+ case "action":
112
+ return /* @__PURE__ */ jsxRuntime.jsxs(
113
+ "svg",
114
+ {
115
+ width: "14",
116
+ height: "14",
117
+ viewBox: "0 0 24 24",
118
+ fill: "none",
119
+ stroke: "currentColor",
120
+ strokeWidth: "2.5",
121
+ strokeLinecap: "round",
122
+ strokeLinejoin: "round",
123
+ "aria-hidden": true,
124
+ children: [
125
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
126
+ /* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "10 8 16 12 10 16 10 8", fill: "currentColor", stroke: "none" })
127
+ ]
128
+ }
129
+ );
130
+ default:
131
+ return null;
132
+ }
133
+ }
134
+ function renderToastIcon(icon, state) {
135
+ if (icon != null) {
136
+ if (typeof icon === "object" && icon !== null && "type" in icon) {
137
+ return icon;
138
+ }
139
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: String(icon) });
140
+ }
141
+ return /* @__PURE__ */ jsxRuntime.jsx(DefaultIcon, { state });
142
+ }
143
+
144
+ // src/toast.root-vars.ts
145
+ function getToastRootVars(input) {
146
+ return {
147
+ "--_h": `${input.open ? input.expanded : input.height}px`,
148
+ "--_pw": `${input.resolvedPillWidth}px`,
149
+ "--_px": `${input.pillX}px`,
150
+ "--_ht": `translateY(${input.open ? input.edge === "bottom" ? 3 : -3 : 0}px) scale(${input.open ? 0.9 : 1})`,
151
+ "--_co": `${input.open ? 1 : 0}`,
152
+ "--_cy": `${input.open ? 0 : -14}px`,
153
+ "--_cm": `${input.open ? input.expandedContent : 0}px`,
154
+ "--_by": `${input.open ? input.height - input.bodyMergeOverlap : input.height}px`,
155
+ "--_bh": `${input.open ? input.expandedContent : 0}px`,
156
+ "--_bo": `${input.open ? 1 : 0}`
157
+ };
158
+ }
159
+
160
+ // src/toast.viewport-offset.ts
161
+ function resolveOffsetValue(value) {
162
+ return typeof value === "number" ? `${value}px` : value;
163
+ }
164
+ function resolveSides(offset) {
165
+ if (offset == null) return {};
166
+ if (typeof offset === "number" || typeof offset === "string") {
167
+ const value = resolveOffsetValue(offset);
168
+ return { top: value, right: value, bottom: value, left: value };
169
+ }
170
+ const top = offset.top != null ? resolveOffsetValue(offset.top) : void 0;
171
+ const right = offset.right != null ? resolveOffsetValue(offset.right) : void 0;
172
+ const bottom = offset.bottom != null ? resolveOffsetValue(offset.bottom) : void 0;
173
+ const left = offset.left != null ? resolveOffsetValue(offset.left) : void 0;
174
+ return { top, right, bottom, left };
175
+ }
176
+ function getViewportOffsetStyle(offset, position) {
177
+ const sides = resolveSides(offset);
178
+ const style = {};
179
+ if (position.startsWith("top") && sides.top) style.top = sides.top;
180
+ if (position.startsWith("bottom") && sides.bottom) style.bottom = sides.bottom;
181
+ if (position.endsWith("right") && sides.right) style.right = sides.right;
182
+ if (position.endsWith("left") && sides.left) style.left = sides.left;
183
+ if (position.endsWith("center")) {
184
+ if (sides.left) style.paddingLeft = sides.left;
185
+ if (sides.right) style.paddingRight = sides.right;
186
+ }
187
+ return style;
188
+ }
189
+ var WIDTH = 350;
190
+ var HEIGHT = 40;
191
+ var PILL_PADDING = 10;
192
+ var MIN_EXPAND_RATIO = 2.25;
193
+ var HEADER_EXIT_MS = 600 * 0.7;
194
+ var BODY_MERGE_OVERLAP = 6;
195
+ function getPillAlign(position) {
196
+ if (position.includes("right")) return "right";
197
+ if (position.includes("center")) return "center";
198
+ return "left";
199
+ }
200
+ function ToastItem({
201
+ item,
202
+ machine,
203
+ localState,
204
+ onLocalStateChange
205
+ }) {
206
+ const rootRef = react.useRef(null);
207
+ const headerRef = react.useRef(null);
208
+ const innerRef = react.useRef(null);
209
+ const contentRef = react.useRef(null);
210
+ const pillRef = react.useRef(null);
211
+ const connectCleanupRef = react.useRef(null);
212
+ const hoveringRef = react.useRef(false);
213
+ const pendingDismissRef = react.useRef(false);
214
+ const dismissRequestedRef = react.useRef(false);
215
+ const forcedDismissTimerRef = react.useRef(null);
216
+ const headerPadRef = react.useRef(null);
217
+ const pillRoRef = react.useRef(null);
218
+ const pillRafRef = react.useRef(0);
219
+ const pillObservedRef = react.useRef(null);
220
+ const headerExitRef = react.useRef(null);
221
+ const onLocalStateChangeRef = react.useRef(onLocalStateChange);
222
+ onLocalStateChangeRef.current = onLocalStateChange;
223
+ const pillAnimRef = react.useRef(null);
224
+ const pillFirstRef = react.useRef(true);
225
+ const prevPillRef = react.useRef({ x: 0, width: HEIGHT, height: HEIGHT });
226
+ const [pillWidth, setPillWidth] = react.useState(0);
227
+ const [contentHeight, setContentHeight] = react.useState(0);
228
+ const headerKey = `${item.state}-${item.title ?? item.state}`;
229
+ const [headerLayer, setHeaderLayer] = react.useState(() => ({
230
+ current: {
231
+ key: headerKey,
232
+ view: {
233
+ state: item.state,
234
+ title: item.title ?? item.state,
235
+ icon: item.icon,
236
+ styles: item.styles
237
+ }
238
+ },
239
+ prev: null
240
+ }));
241
+ const { ready, expanded: isExpanded } = localState;
242
+ const roundness = item.roundness ?? core.TOAST_DEFAULTS.roundness;
243
+ const blur = Math.min(10, Math.max(6, roundness * 0.45));
244
+ const filterId = `fluix-gooey-${item.id.replace(/[^a-z0-9-]/gi, "-")}`;
245
+ const hasDesc = Boolean(item.description) || Boolean(item.button);
246
+ const isLoading = item.state === "loading";
247
+ const open = hasDesc && isExpanded && !isLoading;
248
+ const position = getPillAlign(item.position);
249
+ const edge = item.position.startsWith("top") ? "bottom" : "top";
250
+ const resolvedPillWidth = Math.max(pillWidth || HEIGHT, HEIGHT);
251
+ const pillHeight = HEIGHT + blur * 3;
252
+ const pillX = position === "right" ? WIDTH - resolvedPillWidth : position === "center" ? (WIDTH - resolvedPillWidth) / 2 : 0;
253
+ const minExpanded = HEIGHT * MIN_EXPAND_RATIO;
254
+ const rawExpanded = hasDesc ? Math.max(minExpanded, HEIGHT + contentHeight) : minExpanded;
255
+ const frozenExpandedRef = react.useRef(rawExpanded);
256
+ if (open) {
257
+ frozenExpandedRef.current = rawExpanded;
258
+ }
259
+ const expanded = open ? rawExpanded : frozenExpandedRef.current;
260
+ const expandedContent = Math.max(0, expanded - HEIGHT);
261
+ const svgHeight = hasDesc ? Math.max(expanded, minExpanded) : HEIGHT;
262
+ const viewBox = `0 0 ${WIDTH} ${svgHeight}`;
263
+ const attrs = react.useMemo(
264
+ () => core.Toaster.getAttrs(item, { ready, expanded: isExpanded }),
265
+ [item, ready, isExpanded]
266
+ );
267
+ const rootVars = react.useMemo(
268
+ () => getToastRootVars({
269
+ open,
270
+ expanded,
271
+ height: HEIGHT,
272
+ resolvedPillWidth,
273
+ pillX,
274
+ edge,
275
+ expandedContent,
276
+ bodyMergeOverlap: BODY_MERGE_OVERLAP
277
+ }),
278
+ [open, expanded, resolvedPillWidth, pillX, edge, expandedContent]
279
+ );
280
+ react.useLayoutEffect(() => {
281
+ const el = rootRef.current;
282
+ if (!el) return;
283
+ for (const [key, value] of Object.entries(rootVars)) {
284
+ el.style.setProperty(key, value);
285
+ }
286
+ }, [rootVars]);
287
+ react.useLayoutEffect(() => {
288
+ setHeaderLayer((state) => {
289
+ if (state.current.key === headerKey) {
290
+ const newView = {
291
+ state: item.state,
292
+ title: item.title ?? item.state,
293
+ icon: item.icon,
294
+ styles: item.styles
295
+ };
296
+ if (state.current.view === newView) return state;
297
+ return { ...state, current: { key: headerKey, view: newView } };
298
+ }
299
+ return {
300
+ prev: state.current,
301
+ current: {
302
+ key: headerKey,
303
+ view: {
304
+ state: item.state,
305
+ title: item.title ?? item.state,
306
+ icon: item.icon,
307
+ styles: item.styles
308
+ }
309
+ }
310
+ };
311
+ });
312
+ }, [headerKey, item.state, item.title, item.icon, item.styles]);
313
+ react.useEffect(() => {
314
+ if (!headerLayer.prev) return;
315
+ if (headerExitRef.current) clearTimeout(headerExitRef.current);
316
+ headerExitRef.current = setTimeout(() => {
317
+ setHeaderLayer((s) => s.prev ? { ...s, prev: null } : s);
318
+ headerExitRef.current = null;
319
+ }, HEADER_EXIT_MS);
320
+ return () => {
321
+ if (headerExitRef.current) clearTimeout(headerExitRef.current);
322
+ };
323
+ }, [headerLayer.prev]);
324
+ react.useLayoutEffect(() => {
325
+ const el = innerRef.current;
326
+ const header = headerRef.current;
327
+ if (!el || !header) return;
328
+ if (headerPadRef.current === null) {
329
+ const cs = getComputedStyle(header);
330
+ headerPadRef.current = Number.parseFloat(cs.paddingLeft) + Number.parseFloat(cs.paddingRight);
331
+ }
332
+ const px = headerPadRef.current;
333
+ const measure = () => {
334
+ const w = el.scrollWidth + px + PILL_PADDING;
335
+ if (w > PILL_PADDING) {
336
+ setPillWidth((prev) => prev === w ? prev : w);
337
+ }
338
+ };
339
+ measure();
340
+ if (!pillRoRef.current) {
341
+ pillRoRef.current = new ResizeObserver(() => {
342
+ cancelAnimationFrame(pillRafRef.current);
343
+ pillRafRef.current = requestAnimationFrame(() => {
344
+ const inner = innerRef.current;
345
+ const pad = headerPadRef.current ?? 0;
346
+ if (!inner) return;
347
+ const w = inner.scrollWidth + pad + PILL_PADDING;
348
+ if (w > PILL_PADDING) {
349
+ setPillWidth((prev) => prev === w ? prev : w);
350
+ }
351
+ });
352
+ });
353
+ }
354
+ if (pillObservedRef.current !== el) {
355
+ if (pillObservedRef.current) {
356
+ pillRoRef.current.unobserve(pillObservedRef.current);
357
+ }
358
+ pillRoRef.current.observe(el);
359
+ pillObservedRef.current = el;
360
+ }
361
+ }, []);
362
+ react.useLayoutEffect(() => {
363
+ if (!hasDesc) {
364
+ setContentHeight(0);
365
+ return;
366
+ }
367
+ const el = contentRef.current;
368
+ if (!el) return;
369
+ const measure = () => {
370
+ const h = el.scrollHeight;
371
+ setContentHeight((prev) => prev === h ? prev : h);
372
+ };
373
+ measure();
374
+ let rafId = 0;
375
+ const ro = new ResizeObserver(() => {
376
+ cancelAnimationFrame(rafId);
377
+ rafId = requestAnimationFrame(measure);
378
+ });
379
+ ro.observe(el);
380
+ return () => {
381
+ cancelAnimationFrame(rafId);
382
+ ro.disconnect();
383
+ };
384
+ }, [hasDesc]);
385
+ react.useEffect(() => {
386
+ const timer = setTimeout(() => {
387
+ onLocalStateChangeRef.current({ ready: true });
388
+ }, 32);
389
+ return () => clearTimeout(timer);
390
+ }, []);
391
+ react.useEffect(() => {
392
+ hoveringRef.current = false;
393
+ pendingDismissRef.current = false;
394
+ dismissRequestedRef.current = false;
395
+ if (forcedDismissTimerRef.current) {
396
+ clearTimeout(forcedDismissTimerRef.current);
397
+ forcedDismissTimerRef.current = null;
398
+ }
399
+ }, []);
400
+ react.useEffect(() => {
401
+ const el = pillRef.current;
402
+ if (!el || !ready) return;
403
+ const prev = prevPillRef.current;
404
+ const next = { x: pillX, width: resolvedPillWidth, height: open ? pillHeight : HEIGHT };
405
+ if (prev.x === next.x && prev.width === next.width && prev.height === next.height) return;
406
+ pillAnimRef.current?.cancel();
407
+ if (pillFirstRef.current) {
408
+ pillFirstRef.current = false;
409
+ el.setAttribute("x", String(next.x));
410
+ el.setAttribute("width", String(next.width));
411
+ el.setAttribute("height", String(next.height));
412
+ prevPillRef.current = next;
413
+ return;
414
+ }
415
+ const anim = core.animateSpring(
416
+ el,
417
+ {
418
+ x: { from: prev.x, to: next.x, unit: "px" },
419
+ width: { from: prev.width, to: next.width, unit: "px" },
420
+ height: { from: prev.height, to: next.height, unit: "px" }
421
+ },
422
+ core.FLUIX_SPRING
423
+ );
424
+ pillAnimRef.current = anim;
425
+ prevPillRef.current = next;
426
+ return () => {
427
+ anim?.cancel();
428
+ };
429
+ }, [ready, pillX, resolvedPillWidth, open, pillHeight]);
430
+ react.useEffect(() => {
431
+ const duration = item.duration;
432
+ if (duration == null || duration <= 0) return;
433
+ const timer = setTimeout(() => {
434
+ if (hoveringRef.current) {
435
+ pendingDismissRef.current = true;
436
+ forcedDismissTimerRef.current = setTimeout(() => {
437
+ if (dismissRequestedRef.current) return;
438
+ dismissRequestedRef.current = true;
439
+ pendingDismissRef.current = false;
440
+ machine.dismiss(item.id);
441
+ }, 1200);
442
+ return;
443
+ }
444
+ pendingDismissRef.current = false;
445
+ dismissRequestedRef.current = true;
446
+ machine.dismiss(item.id);
447
+ }, duration);
448
+ return () => {
449
+ clearTimeout(timer);
450
+ if (forcedDismissTimerRef.current) {
451
+ clearTimeout(forcedDismissTimerRef.current);
452
+ forcedDismissTimerRef.current = null;
453
+ }
454
+ };
455
+ }, [item.id, item.duration, machine]);
456
+ react.useEffect(() => {
457
+ if (!ready) return;
458
+ const timers = [];
459
+ if (item.autoExpandDelayMs != null && item.autoExpandDelayMs > 0) {
460
+ timers.push(
461
+ setTimeout(() => {
462
+ if (!hoveringRef.current) onLocalStateChangeRef.current({ expanded: true });
463
+ }, item.autoExpandDelayMs)
464
+ );
465
+ }
466
+ if (item.autoCollapseDelayMs != null && item.autoCollapseDelayMs > 0) {
467
+ timers.push(
468
+ setTimeout(() => {
469
+ if (!hoveringRef.current) onLocalStateChangeRef.current({ expanded: false });
470
+ }, item.autoCollapseDelayMs)
471
+ );
472
+ }
473
+ return () => timers.forEach(clearTimeout);
474
+ }, [item.autoExpandDelayMs, item.autoCollapseDelayMs, ready]);
475
+ react.useEffect(() => {
476
+ const el = rootRef.current;
477
+ if (!el) return;
478
+ const callbacks = {
479
+ onExpand: () => {
480
+ if (item.exiting || dismissRequestedRef.current) return;
481
+ onLocalStateChangeRef.current({ expanded: true });
482
+ },
483
+ onCollapse: () => {
484
+ if (item.exiting || dismissRequestedRef.current) return;
485
+ if (item.autopilot !== false) return;
486
+ onLocalStateChangeRef.current({ expanded: false });
487
+ },
488
+ onDismiss: () => {
489
+ if (dismissRequestedRef.current) return;
490
+ dismissRequestedRef.current = true;
491
+ machine.dismiss(item.id);
492
+ },
493
+ onHoverStart: () => {
494
+ hoveringRef.current = true;
495
+ },
496
+ onHoverEnd: () => {
497
+ hoveringRef.current = false;
498
+ if (pendingDismissRef.current) {
499
+ pendingDismissRef.current = false;
500
+ if (dismissRequestedRef.current) return;
501
+ dismissRequestedRef.current = true;
502
+ machine.dismiss(item.id);
503
+ }
504
+ }
505
+ };
506
+ const { destroy } = core.Toaster.connect(el, callbacks, item);
507
+ connectCleanupRef.current = destroy;
508
+ return () => {
509
+ destroy();
510
+ connectCleanupRef.current = null;
511
+ };
512
+ }, [item, machine]);
513
+ react.useEffect(() => {
514
+ return () => {
515
+ pillRoRef.current?.disconnect();
516
+ cancelAnimationFrame(pillRafRef.current);
517
+ };
518
+ }, []);
519
+ return /* @__PURE__ */ jsxRuntime.jsxs("button", { ref: rootRef, type: "button", ...attrs.root, children: [
520
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ...attrs.canvas, children: /* @__PURE__ */ jsxRuntime.jsxs(
521
+ "svg",
522
+ {
523
+ xmlns: "http://www.w3.org/2000/svg",
524
+ "data-fluix-svg": true,
525
+ width: WIDTH,
526
+ height: svgHeight,
527
+ viewBox,
528
+ "aria-hidden": true,
529
+ children: [
530
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs(
531
+ "filter",
532
+ {
533
+ id: filterId,
534
+ x: "-20%",
535
+ y: "-20%",
536
+ width: "140%",
537
+ height: "140%",
538
+ colorInterpolationFilters: "sRGB",
539
+ children: [
540
+ /* @__PURE__ */ jsxRuntime.jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: blur, result: "blur" }),
541
+ /* @__PURE__ */ jsxRuntime.jsx(
542
+ "feColorMatrix",
543
+ {
544
+ in: "blur",
545
+ type: "matrix",
546
+ values: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10",
547
+ result: "goo"
548
+ }
549
+ ),
550
+ /* @__PURE__ */ jsxRuntime.jsx("feComposite", { in: "SourceGraphic", in2: "goo", operator: "atop" })
551
+ ]
552
+ }
553
+ ) }),
554
+ /* @__PURE__ */ jsxRuntime.jsxs("g", { filter: `url(#${filterId})`, children: [
555
+ /* @__PURE__ */ jsxRuntime.jsx(
556
+ "rect",
557
+ {
558
+ ref: pillRef,
559
+ "data-fluix-pill": true,
560
+ x: pillX,
561
+ y: 0,
562
+ width: resolvedPillWidth,
563
+ height: HEIGHT,
564
+ rx: roundness,
565
+ ry: roundness,
566
+ fill: item.fill ?? "#FFFFFF"
567
+ }
568
+ ),
569
+ /* @__PURE__ */ jsxRuntime.jsx(
570
+ "rect",
571
+ {
572
+ "data-fluix-body": true,
573
+ x: 0,
574
+ y: HEIGHT,
575
+ width: WIDTH,
576
+ height: 0,
577
+ rx: roundness,
578
+ ry: roundness,
579
+ fill: item.fill ?? "#FFFFFF",
580
+ opacity: 0
581
+ }
582
+ )
583
+ ] })
584
+ ]
585
+ }
586
+ ) }),
587
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: headerRef, ...attrs.header, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-fluix-header-stack": true, children: [
588
+ /* @__PURE__ */ jsxRuntime.jsxs(
589
+ "div",
590
+ {
591
+ ref: innerRef,
592
+ "data-fluix-header-inner": true,
593
+ "data-layer": "current",
594
+ children: [
595
+ /* @__PURE__ */ jsxRuntime.jsx(
596
+ "div",
597
+ {
598
+ ...attrs.badge,
599
+ "data-state": headerLayer.current.view.state,
600
+ className: headerLayer.current.view.styles?.badge,
601
+ children: renderToastIcon(headerLayer.current.view.icon, headerLayer.current.view.state)
602
+ }
603
+ ),
604
+ /* @__PURE__ */ jsxRuntime.jsx(
605
+ "span",
606
+ {
607
+ ...attrs.title,
608
+ "data-state": headerLayer.current.view.state,
609
+ className: headerLayer.current.view.styles?.title,
610
+ children: headerLayer.current.view.title
611
+ }
612
+ )
613
+ ]
614
+ },
615
+ headerLayer.current.key
616
+ ),
617
+ headerLayer.prev && /* @__PURE__ */ jsxRuntime.jsxs(
618
+ "div",
619
+ {
620
+ "data-fluix-header-inner": true,
621
+ "data-layer": "prev",
622
+ "data-exiting": "true",
623
+ children: [
624
+ /* @__PURE__ */ jsxRuntime.jsx(
625
+ "div",
626
+ {
627
+ "data-fluix-badge": true,
628
+ "data-state": headerLayer.prev.view.state,
629
+ className: headerLayer.prev.view.styles?.badge,
630
+ children: renderToastIcon(headerLayer.prev.view.icon, headerLayer.prev.view.state)
631
+ }
632
+ ),
633
+ /* @__PURE__ */ jsxRuntime.jsx(
634
+ "span",
635
+ {
636
+ "data-fluix-title": true,
637
+ "data-state": headerLayer.prev.view.state,
638
+ className: headerLayer.prev.view.styles?.title,
639
+ children: headerLayer.prev.view.title
640
+ }
641
+ )
642
+ ]
643
+ },
644
+ headerLayer.prev.key
645
+ )
646
+ ] }) }),
647
+ hasDesc && /* @__PURE__ */ jsxRuntime.jsx("div", { ...attrs.content, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: contentRef, ...attrs.description, className: item.styles?.description, children: [
648
+ typeof item.description === "string" ? item.description : item.description,
649
+ item.button && /* @__PURE__ */ jsxRuntime.jsx(
650
+ "button",
651
+ {
652
+ ...attrs.button,
653
+ type: "button",
654
+ className: item.styles?.button,
655
+ onClick: (e) => {
656
+ e.stopPropagation();
657
+ item.button?.onClick();
658
+ },
659
+ children: item.button.title
660
+ }
661
+ )
662
+ ] }) })
663
+ ] });
664
+ }
665
+ var EMPTY_STATE = { toasts: [], config: { position: "top-right" } };
666
+ function getServerSnapshot() {
667
+ return EMPTY_STATE;
668
+ }
669
+ function ViewportGroup({
670
+ position,
671
+ layout,
672
+ offset,
673
+ children
674
+ }) {
675
+ const sectionRef = react.useRef(null);
676
+ const offsetStyle = react.useMemo(() => getViewportOffsetStyle(offset, position), [offset, position]);
677
+ react.useLayoutEffect(() => {
678
+ const el = sectionRef.current;
679
+ if (!el) return;
680
+ el.style.top = "";
681
+ el.style.right = "";
682
+ el.style.bottom = "";
683
+ el.style.left = "";
684
+ el.style.paddingLeft = "";
685
+ el.style.paddingRight = "";
686
+ Object.assign(el.style, offsetStyle);
687
+ }, [offsetStyle]);
688
+ return /* @__PURE__ */ jsxRuntime.jsx("section", { ref: sectionRef, ...core.Toaster.getViewportAttrs(position, layout), children });
689
+ }
690
+ function Toaster({ config } = {}) {
691
+ const machine = react.useMemo(() => core.Toaster.getMachine(), []);
692
+ const snapshot = react.useSyncExternalStore(
693
+ machine.store.subscribe,
694
+ machine.store.getSnapshot,
695
+ getServerSnapshot
696
+ );
697
+ react.useEffect(() => {
698
+ if (config) machine.configure(config);
699
+ }, [machine, config]);
700
+ const [localState, setLocalState] = react.useState(() => ({}));
701
+ const setToastLocal = react.useCallback(
702
+ (id, patch) => {
703
+ setLocalState((prev) => {
704
+ const next = { ...prev };
705
+ if (!next[id]) next[id] = { ready: false, expanded: false };
706
+ next[id] = { ...next[id], ...patch };
707
+ return next;
708
+ });
709
+ },
710
+ []
711
+ );
712
+ react.useEffect(() => {
713
+ const ids = new Set(snapshot.toasts.map((t) => t.id));
714
+ setLocalState((prev) => {
715
+ const next = {};
716
+ for (const id of ids) {
717
+ next[id] = prev[id] ?? { ready: false, expanded: false };
718
+ }
719
+ return Object.keys(next).length ? next : prev;
720
+ });
721
+ }, [snapshot.toasts]);
722
+ const byPosition = react.useMemo(() => {
723
+ const map = /* @__PURE__ */ new Map();
724
+ for (const item of snapshot.toasts) {
725
+ const list = map.get(item.position) ?? [];
726
+ list.push(item);
727
+ map.set(item.position, list);
728
+ }
729
+ return map;
730
+ }, [snapshot.toasts]);
731
+ const resolvedOffset = snapshot.config?.offset ?? config?.offset;
732
+ const resolvedLayout = snapshot.config?.layout ?? config?.layout ?? "stack";
733
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from(byPosition.entries()).map(([position, toasts]) => /* @__PURE__ */ jsxRuntime.jsx(
734
+ ViewportGroup,
735
+ {
736
+ position,
737
+ layout: resolvedLayout,
738
+ offset: resolvedOffset,
739
+ children: toasts.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
740
+ ToastItem,
741
+ {
742
+ item,
743
+ machine,
744
+ localState: localState[item.id] ?? { ready: false, expanded: false },
745
+ onLocalStateChange: (patch) => setToastLocal(item.id, patch)
746
+ },
747
+ item.instanceId
748
+ ))
749
+ },
750
+ position
751
+ )) });
752
+ }
753
+
754
+ Object.defineProperty(exports, "fluix", {
755
+ enumerable: true,
756
+ get: function () { return core.fluix; }
757
+ });
758
+ exports.Toaster = Toaster;
759
+ //# sourceMappingURL=index.cjs.map
760
+ //# sourceMappingURL=index.cjs.map