@zag-js/toast 0.50.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,926 +1,2 @@
1
- // src/toast-group.connect.ts
2
- import { isMachine, subscribe } from "@zag-js/core";
3
- import { contains } from "@zag-js/dom-query";
4
- import { runIfFn, uuid } from "@zag-js/utils";
5
-
6
- // src/toast.anatomy.ts
7
- import { createAnatomy } from "@zag-js/anatomy";
8
- var anatomy = createAnatomy("toast").parts(
9
- "group",
10
- "root",
11
- "title",
12
- "description",
13
- "actionTrigger",
14
- "closeTrigger"
15
- );
16
- var parts = anatomy.build();
17
-
18
- // src/toast.dom.ts
19
- import { createScope } from "@zag-js/dom-query";
20
- var dom = createScope({
21
- getRegionId: (placement) => `toast-group:${placement}`,
22
- getRegionEl: (ctx, placement) => dom.getById(ctx, `toast-group:${placement}`),
23
- getRootId: (ctx) => `toast:${ctx.id}`,
24
- getRootEl: (ctx) => dom.getById(ctx, dom.getRootId(ctx)),
25
- getTitleId: (ctx) => `toast:${ctx.id}:title`,
26
- getDescriptionId: (ctx) => `toast:${ctx.id}:description`,
27
- getCloseTriggerId: (ctx) => `toast${ctx.id}:close`
28
- });
29
-
30
- // src/toast.utils.ts
31
- import { MAX_Z_INDEX } from "@zag-js/dom-query";
32
- function getToastsByPlacement(toasts, placement) {
33
- return toasts.filter((toast) => toast.state.context.placement === placement);
34
- }
35
- var defaultTimeouts = {
36
- info: 5e3,
37
- error: 5e3,
38
- success: 2e3,
39
- loading: Infinity,
40
- DEFAULT: 5e3
41
- };
42
- function getToastDuration(duration, type) {
43
- return duration ?? defaultTimeouts[type] ?? defaultTimeouts.DEFAULT;
44
- }
45
- function getGroupPlacementStyle(ctx, placement) {
46
- const offset = ctx.offsets;
47
- const computedOffset = typeof offset === "string" ? { left: offset, right: offset, bottom: offset, top: offset } : offset;
48
- const rtl = ctx.dir === "rtl";
49
- const computedPlacement = placement.replace("-start", rtl ? "-right" : "-left").replace("-end", rtl ? "-left" : "-right");
50
- const isRighty = computedPlacement.includes("right");
51
- const isLefty = computedPlacement.includes("left");
52
- const styles = {
53
- position: "fixed",
54
- pointerEvents: ctx.count > 0 ? void 0 : "none",
55
- display: "flex",
56
- flexDirection: "column",
57
- "--gap": `${ctx.gap}px`,
58
- "--first-height": `${ctx.heights[0]?.height || 0}px`,
59
- zIndex: MAX_Z_INDEX
60
- };
61
- let alignItems = "center";
62
- if (isRighty)
63
- alignItems = "flex-end";
64
- if (isLefty)
65
- alignItems = "flex-start";
66
- styles.alignItems = alignItems;
67
- if (computedPlacement.includes("top")) {
68
- const offset2 = computedOffset.top;
69
- styles.top = `max(env(safe-area-inset-top, 0px), ${offset2})`;
70
- }
71
- if (computedPlacement.includes("bottom")) {
72
- const offset2 = computedOffset.bottom;
73
- styles.bottom = `max(env(safe-area-inset-bottom, 0px), ${offset2})`;
74
- }
75
- if (!computedPlacement.includes("left")) {
76
- const offset2 = computedOffset.right;
77
- styles.insetInlineEnd = `calc(env(safe-area-inset-right, 0px) + ${offset2})`;
78
- }
79
- if (!computedPlacement.includes("right")) {
80
- const offset2 = computedOffset.left;
81
- styles.insetInlineStart = `calc(env(safe-area-inset-left, 0px) + ${offset2})`;
82
- }
83
- return styles;
84
- }
85
- function getPlacementStyle(ctx, visible) {
86
- const [side] = ctx.placement.split("-");
87
- const sibling = !ctx.frontmost;
88
- const overlap = !ctx.stacked;
89
- const styles = {
90
- position: "absolute",
91
- pointerEvents: "auto",
92
- "--opacity": "0",
93
- "--remove-delay": `${ctx.removeDelay}ms`,
94
- "--duration": `${ctx.type === "loading" ? Number.MAX_SAFE_INTEGER : ctx.duration}ms`,
95
- "--initial-height": `${ctx.height}px`,
96
- "--offset": `${ctx.offset}px`,
97
- "--index": ctx.index,
98
- "--z-index": ctx.zIndex,
99
- "--lift-amount": "calc(var(--lift) * var(--gap))",
100
- "--y": "100%",
101
- "--x": "0"
102
- };
103
- const assign = (overrides) => Object.assign(styles, overrides);
104
- if (side === "top") {
105
- assign({
106
- top: "0",
107
- "--sign": "-1",
108
- "--y": "-100%",
109
- "--lift": "1"
110
- });
111
- } else if (side === "bottom") {
112
- assign({
113
- bottom: "0",
114
- "--sign": "1",
115
- "--y": "100%",
116
- "--lift": "-1"
117
- });
118
- }
119
- if (ctx.mounted) {
120
- assign({
121
- "--y": "0",
122
- "--opacity": "1"
123
- });
124
- if (ctx.stacked) {
125
- assign({
126
- "--y": "calc(var(--lift) * var(--offset))",
127
- "--height": "var(--initial-height)"
128
- });
129
- }
130
- }
131
- if (!visible) {
132
- assign({
133
- "--opacity": "0",
134
- pointerEvents: "none"
135
- });
136
- }
137
- if (sibling && overlap) {
138
- assign({
139
- "--base-scale": "var(--index) * 0.05 + 1",
140
- "--y": "calc(var(--lift-amount) * var(--index))",
141
- "--scale": "calc(-1 * var(--base-scale))",
142
- "--height": "var(--first-height)"
143
- });
144
- if (!visible) {
145
- assign({
146
- "--y": "calc(var(--sign) * 40%)"
147
- });
148
- }
149
- }
150
- if (sibling && ctx.stacked && !visible) {
151
- assign({
152
- "--y": "calc(var(--lift) * var(--offset) + var(--lift) * -100%)"
153
- });
154
- }
155
- if (ctx.frontmost && !visible) {
156
- assign({
157
- "--y": "calc(var(--lift) * -100%)"
158
- });
159
- }
160
- return styles;
161
- }
162
- function getGhostBeforeStyle(ctx, visible) {
163
- const styles = {
164
- position: "absolute",
165
- inset: "0",
166
- scale: "1 2",
167
- pointerEvents: visible ? "none" : "auto"
168
- };
169
- const assign = (overrides) => Object.assign(styles, overrides);
170
- if (ctx.frontmost && !visible) {
171
- assign({
172
- height: "calc(var(--initial-height) + 80%)"
173
- });
174
- }
175
- return styles;
176
- }
177
- function getGhostAfterStyle(_ctx, _visible) {
178
- return {
179
- position: "absolute",
180
- left: "0",
181
- height: "calc(var(--gap) + 2px)",
182
- bottom: "100%",
183
- width: "100%"
184
- };
185
- }
186
-
187
- // src/toast-group.connect.ts
188
- function groupConnect(serviceOrState, send, normalize) {
189
- function getState() {
190
- const result = isMachine(serviceOrState) ? serviceOrState.getState() : serviceOrState;
191
- return result;
192
- }
193
- function getToastsByPlacementImpl(placement) {
194
- return getToastsByPlacement(getState().context.toasts, placement);
195
- }
196
- function isVisible(id) {
197
- const toasts = getState().context.toasts;
198
- if (!toasts.length)
199
- return false;
200
- return !!toasts.find((toast) => toast.id == id);
201
- }
202
- function create(options) {
203
- const uid = `toast:${uuid()}`;
204
- const id = options.id ? options.id : uid;
205
- if (isVisible(id))
206
- return id;
207
- send({ type: "ADD_TOAST", toast: { ...options, id } });
208
- return id;
209
- }
210
- function update(id, options) {
211
- if (!isVisible(id))
212
- return id;
213
- send({ type: "UPDATE_TOAST", id, toast: options });
214
- return id;
215
- }
216
- function upsert(options) {
217
- const { id } = options;
218
- const visible = id ? isVisible(id) : false;
219
- if (visible && id != null) {
220
- return update(id, options);
221
- } else {
222
- return create(options);
223
- }
224
- }
225
- function dismiss(id) {
226
- if (id == null) {
227
- send("DISMISS_ALL");
228
- } else if (isVisible(id)) {
229
- send({ type: "DISMISS_TOAST", id });
230
- }
231
- }
232
- return {
233
- getCount() {
234
- return getState().context.count;
235
- },
236
- getPlacements() {
237
- const toasts = getState().context.toasts;
238
- const placements = toasts.map((toast) => toast.state.context.placement);
239
- return Array.from(new Set(placements));
240
- },
241
- getToastsByPlacement: getToastsByPlacementImpl,
242
- isVisible,
243
- create,
244
- update,
245
- upsert,
246
- dismiss,
247
- remove(id) {
248
- if (id == null) {
249
- send("REMOVE_ALL");
250
- } else if (isVisible(id)) {
251
- send({ type: "REMOVE_TOAST", id });
252
- }
253
- },
254
- dismissByPlacement(placement) {
255
- const toasts = getToastsByPlacementImpl(placement);
256
- toasts.forEach((toast) => dismiss(toast.id));
257
- },
258
- loading(options) {
259
- return upsert({ ...options, type: "loading" });
260
- },
261
- success(options) {
262
- return upsert({ ...options, type: "success" });
263
- },
264
- error(options) {
265
- return upsert({ ...options, type: "error" });
266
- },
267
- promise(promise, options, shared = {}) {
268
- const id = upsert({ ...shared, ...options.loading, type: "loading" });
269
- runIfFn(promise).then((response) => {
270
- const successOptions = runIfFn(options.success, response);
271
- upsert({ ...shared, ...successOptions, id, type: "success" });
272
- }).catch((error) => {
273
- const errorOptions = runIfFn(options.error, error);
274
- upsert({ ...shared, ...errorOptions, id, type: "error" });
275
- }).finally(() => {
276
- options.finally?.();
277
- });
278
- return id;
279
- },
280
- pause(id) {
281
- if (id == null) {
282
- send("PAUSE_ALL");
283
- } else if (isVisible(id)) {
284
- send({ type: "PAUSE_TOAST", id });
285
- }
286
- },
287
- resume(id) {
288
- if (id == null) {
289
- send("RESUME_ALL");
290
- } else if (isVisible(id)) {
291
- send({ type: "RESUME_TOAST", id });
292
- }
293
- },
294
- getGroupProps(options) {
295
- const { placement, label = "Notifications" } = options;
296
- const state = getState();
297
- const hotkeyLabel = state.context.hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, "");
298
- const [side, align = "center"] = placement.split("-");
299
- return normalize.element({
300
- ...parts.group.attrs,
301
- dir: state.context.dir,
302
- tabIndex: -1,
303
- "aria-label": `${placement} ${label} ${hotkeyLabel}`,
304
- id: dom.getRegionId(placement),
305
- "data-placement": placement,
306
- "data-side": side,
307
- "data-align": align,
308
- "aria-live": "polite",
309
- role: "region",
310
- style: getGroupPlacementStyle(state.context, placement),
311
- onMouseMove() {
312
- send({ type: "REGION.POINTER_ENTER", placement });
313
- },
314
- onMouseLeave() {
315
- send({ type: "REGION.POINTER_LEAVE", placement });
316
- },
317
- onFocus(event) {
318
- send({ type: "REGION.FOCUS", target: event.relatedTarget });
319
- },
320
- onBlur(event) {
321
- if (state.context.isFocusWithin && !contains(event.currentTarget, event.relatedTarget)) {
322
- send({ type: "REGION.BLUR" });
323
- }
324
- }
325
- });
326
- },
327
- subscribe(fn) {
328
- const state = getState();
329
- return subscribe(state.context.toasts, () => {
330
- const toasts = getToastsByPlacementImpl(state.context.placement);
331
- const contexts = toasts.map((toast) => toast.getState().context);
332
- fn(contexts);
333
- });
334
- }
335
- };
336
- }
337
-
338
- // src/toast-group.machine.ts
339
- import { createMachine as createMachine2, ref } from "@zag-js/core";
340
- import { trackDismissableBranch } from "@zag-js/dismissable";
341
- import { addDomEvent } from "@zag-js/dom-event";
342
- import { compact as compact2 } from "@zag-js/utils";
343
-
344
- // src/toast.machine.ts
345
- import { createMachine, guards } from "@zag-js/core";
346
- import { queryAll, raf } from "@zag-js/dom-query";
347
- import { compact, warn } from "@zag-js/utils";
348
- var { not, and, or } = guards;
349
- function createToastMachine(options) {
350
- const { type = "info", duration, id = "1", placement = "bottom", removeDelay = 200, ...restProps } = options;
351
- const ctx = compact(restProps);
352
- const computedDuration = getToastDuration(duration, type);
353
- return createMachine(
354
- {
355
- id,
356
- context: {
357
- id,
358
- type,
359
- remaining: computedDuration,
360
- duration: computedDuration,
361
- removeDelay,
362
- createdAt: Date.now(),
363
- placement,
364
- ...ctx,
365
- height: 0,
366
- offset: 0,
367
- frontmost: false,
368
- mounted: false,
369
- index: -1,
370
- zIndex: 0
371
- },
372
- initial: type === "loading" ? "visible:persist" : "visible",
373
- on: {
374
- UPDATE: [
375
- {
376
- guard: and("hasTypeChanged", "isChangingToLoading"),
377
- target: "visible:persist",
378
- actions: ["setContext"]
379
- },
380
- {
381
- guard: or("hasDurationChanged", "hasTypeChanged"),
382
- target: "visible:updating",
383
- actions: ["setContext"]
384
- },
385
- {
386
- actions: ["setContext"]
387
- }
388
- ],
389
- MEASURE: {
390
- actions: ["measureHeight"]
391
- }
392
- },
393
- entry: ["invokeOnVisible"],
394
- activities: ["trackHeight"],
395
- states: {
396
- "visible:updating": {
397
- tags: ["visible", "updating"],
398
- after: {
399
- 0: "visible"
400
- }
401
- },
402
- "visible:persist": {
403
- tags: ["visible", "paused"],
404
- on: {
405
- RESUME: {
406
- guard: not("isLoadingType"),
407
- target: "visible",
408
- actions: ["setCreatedAt"]
409
- },
410
- DISMISS: "dismissing"
411
- }
412
- },
413
- visible: {
414
- tags: ["visible"],
415
- after: {
416
- VISIBLE_DURATION: "dismissing"
417
- },
418
- on: {
419
- DISMISS: "dismissing",
420
- PAUSE: {
421
- target: "visible:persist",
422
- actions: "setRemainingDuration"
423
- }
424
- }
425
- },
426
- dismissing: {
427
- entry: "invokeOnDismiss",
428
- after: {
429
- REMOVE_DELAY: {
430
- target: "unmounted",
431
- actions: "notifyParentToRemove"
432
- }
433
- }
434
- },
435
- unmounted: {
436
- entry: "invokeOnUnmount",
437
- type: "final"
438
- }
439
- }
440
- },
441
- {
442
- activities: {
443
- trackHeight(ctx2, _evt, { self }) {
444
- let cleanup;
445
- raf(() => {
446
- const rootEl = dom.getRootEl(ctx2);
447
- if (!rootEl)
448
- return;
449
- ctx2.mounted = true;
450
- const ghosts = queryAll(rootEl, "[data-ghost]");
451
- warn(
452
- ghosts.length !== 2,
453
- "[toast] No ghost element found in toast. Render the `ghostBefore` and `ghostAfter` elements"
454
- );
455
- const syncHeight = () => {
456
- const originalHeight = rootEl.style.height;
457
- rootEl.style.height = "auto";
458
- const newHeight = rootEl.getBoundingClientRect().height;
459
- rootEl.style.height = originalHeight;
460
- ctx2.height = newHeight;
461
- self.sendParent({ type: "UPDATE_HEIGHT", id: self.id, height: newHeight, placement: ctx2.placement });
462
- };
463
- syncHeight();
464
- const win = dom.getWin(ctx2);
465
- const observer = new win.MutationObserver(syncHeight);
466
- observer.observe(rootEl, { childList: true, subtree: true, characterData: true });
467
- cleanup = () => observer.disconnect();
468
- });
469
- return () => cleanup?.();
470
- }
471
- },
472
- guards: {
473
- isChangingToLoading: (_, evt) => evt.toast?.type === "loading",
474
- isLoadingType: (ctx2) => ctx2.type === "loading",
475
- hasTypeChanged: (ctx2, evt) => evt.toast?.type != null && evt.toast.type !== ctx2.type,
476
- hasDurationChanged: (ctx2, evt) => evt.toast?.duration != null && evt.toast.duration !== ctx2.duration
477
- },
478
- delays: {
479
- VISIBLE_DURATION: (ctx2) => ctx2.remaining,
480
- REMOVE_DELAY: (ctx2) => ctx2.removeDelay
481
- },
482
- actions: {
483
- measureHeight(ctx2, _evt, { self }) {
484
- raf(() => {
485
- const rootEl = dom.getRootEl(ctx2);
486
- if (!rootEl)
487
- return;
488
- ctx2.mounted = true;
489
- const originalHeight = rootEl.style.height;
490
- rootEl.style.height = "auto";
491
- const newHeight = rootEl.getBoundingClientRect().height;
492
- rootEl.style.height = originalHeight;
493
- ctx2.height = newHeight;
494
- self.sendParent({ type: "UPDATE_HEIGHT", id: self.id, height: newHeight, placement: ctx2.placement });
495
- });
496
- },
497
- setRemainingDuration(ctx2) {
498
- ctx2.remaining -= Date.now() - ctx2.createdAt;
499
- },
500
- setCreatedAt(ctx2) {
501
- ctx2.createdAt = Date.now();
502
- },
503
- notifyParentToRemove(_ctx, _evt, { self }) {
504
- self.sendParent({ type: "REMOVE_TOAST", id: self.id });
505
- },
506
- invokeOnDismiss(ctx2) {
507
- ctx2.onStatusChange?.({ status: "dismissing" });
508
- },
509
- invokeOnUnmount(ctx2) {
510
- ctx2.onStatusChange?.({ status: "unmounted" });
511
- },
512
- invokeOnVisible(ctx2) {
513
- ctx2.onStatusChange?.({ status: "visible" });
514
- },
515
- setContext(ctx2, evt) {
516
- const duration2 = evt.toast?.duration;
517
- const type2 = evt.toast?.type ?? ctx2.type;
518
- const computedDuration2 = getToastDuration(duration2, type2);
519
- Object.assign(ctx2, {
520
- ...evt.toast,
521
- duration: computedDuration2,
522
- remaining: computedDuration2
523
- });
524
- }
525
- }
526
- }
527
- );
528
- }
529
-
530
- // src/toast-group.machine.ts
531
- function groupMachine(userContext) {
532
- const ctx = compact2(userContext);
533
- return createMachine2(
534
- {
535
- id: "toaster",
536
- initial: ctx.overlap ? "overlap" : "stack",
537
- context: {
538
- dir: "ltr",
539
- max: Number.MAX_SAFE_INTEGER,
540
- gap: 16,
541
- pauseOnPageIdle: false,
542
- hotkey: ["altKey", "KeyT"],
543
- offsets: "1rem",
544
- placement: "bottom",
545
- removeDelay: 200,
546
- ...ctx,
547
- toasts: [],
548
- lastFocusedEl: null,
549
- isFocusWithin: false,
550
- heights: []
551
- },
552
- computed: {
553
- count: (ctx2) => ctx2.toasts.length
554
- },
555
- activities: ["trackDocumentVisibility", "trackHotKeyPress"],
556
- watch: {
557
- toasts: ["collapsedIfEmpty", "setDismissableBranch"]
558
- },
559
- exit: ["removeToasts", "clearDismissableBranch", "clearLastFocusedEl"],
560
- on: {
561
- PAUSE_TOAST: {
562
- actions: ["pauseToast"]
563
- },
564
- PAUSE_ALL: {
565
- actions: ["pauseToasts"]
566
- },
567
- RESUME_TOAST: {
568
- actions: ["resumeToast"]
569
- },
570
- RESUME_ALL: {
571
- actions: ["resumeToasts"]
572
- },
573
- ADD_TOAST: {
574
- guard: "isWithinRange",
575
- actions: ["createToast", "syncToastIndex"]
576
- },
577
- UPDATE_TOAST: {
578
- actions: ["updateToast"]
579
- },
580
- DISMISS_TOAST: {
581
- actions: ["dismissToast"]
582
- },
583
- DISMISS_ALL: {
584
- actions: ["dismissToasts"]
585
- },
586
- REMOVE_TOAST: {
587
- actions: ["removeToast", "syncToastIndex", "syncToastOffset"]
588
- },
589
- REMOVE_ALL: {
590
- actions: ["removeToasts"]
591
- },
592
- UPDATE_HEIGHT: {
593
- actions: ["syncHeights", "syncToastOffset"]
594
- },
595
- "DOC.HOTKEY": {
596
- actions: ["focusRegionEl"]
597
- },
598
- "REGION.BLUR": [
599
- {
600
- guard: "isOverlapping",
601
- target: "overlap",
602
- actions: ["resumeToasts", "restoreLastFocusedEl"]
603
- },
604
- {
605
- actions: ["resumeToasts", "restoreLastFocusedEl"]
606
- }
607
- ]
608
- },
609
- states: {
610
- stack: {
611
- entry: ["expandToasts"],
612
- on: {
613
- "REGION.POINTER_LEAVE": [
614
- {
615
- guard: "isOverlapping",
616
- target: "overlap",
617
- actions: ["resumeToasts"]
618
- },
619
- {
620
- actions: ["resumeToasts"]
621
- }
622
- ],
623
- "REGION.OVERLAP": {
624
- target: "overlap"
625
- },
626
- "REGION.FOCUS": {
627
- actions: ["setLastFocusedEl", "pauseToasts"]
628
- },
629
- "REGION.POINTER_ENTER": {
630
- actions: ["pauseToasts"]
631
- }
632
- }
633
- },
634
- overlap: {
635
- entry: ["collapseToasts"],
636
- on: {
637
- "REGION.STACK": {
638
- target: "stack"
639
- },
640
- "REGION.POINTER_ENTER": {
641
- target: "stack",
642
- actions: ["pauseToasts"]
643
- },
644
- "REGION.FOCUS": {
645
- target: "stack",
646
- actions: ["setLastFocusedEl", "pauseToasts"]
647
- }
648
- }
649
- }
650
- }
651
- },
652
- {
653
- guards: {
654
- isWithinRange: (ctx2) => ctx2.toasts.length < ctx2.max,
655
- isOverlapping: (ctx2) => !!ctx2.overlap
656
- },
657
- activities: {
658
- trackHotKeyPress(ctx2, _evt, { send }) {
659
- const handleKeyDown = (event) => {
660
- const isHotkeyPressed = ctx2.hotkey.every((key) => event[key] || event.code === key);
661
- if (!isHotkeyPressed)
662
- return;
663
- send({ type: "DOC.HOTKEY" });
664
- };
665
- return addDomEvent(document, "keydown", handleKeyDown, { capture: true });
666
- },
667
- trackDocumentVisibility(ctx2, _evt, { send }) {
668
- if (!ctx2.pauseOnPageIdle)
669
- return;
670
- const doc = dom.getDoc(ctx2);
671
- return addDomEvent(doc, "visibilitychange", () => {
672
- send(doc.visibilityState === "hidden" ? "PAUSE_ALL" : "RESUME_ALL");
673
- });
674
- }
675
- },
676
- actions: {
677
- setDismissableBranch(ctx2) {
678
- const currentToasts = getToastsByPlacement(ctx2.toasts, ctx2.placement);
679
- const hasToasts = currentToasts.length > 0;
680
- if (!hasToasts) {
681
- ctx2._cleanup?.();
682
- return;
683
- }
684
- if (hasToasts && ctx2._cleanup) {
685
- return;
686
- }
687
- const groupEl = () => dom.getRegionEl(ctx2, ctx2.placement);
688
- ctx2._cleanup = trackDismissableBranch(groupEl, { defer: true });
689
- },
690
- clearDismissableBranch(ctx2) {
691
- ctx2._cleanup?.();
692
- },
693
- focusRegionEl(ctx2) {
694
- queueMicrotask(() => {
695
- dom.getRegionEl(ctx2, ctx2.placement)?.focus();
696
- });
697
- },
698
- expandToasts(ctx2) {
699
- each(ctx2, (toast) => {
700
- toast.state.context.stacked = true;
701
- });
702
- },
703
- collapseToasts(ctx2) {
704
- each(ctx2, (toast) => {
705
- toast.state.context.stacked = false;
706
- });
707
- },
708
- collapsedIfEmpty(ctx2, _evt, { send }) {
709
- if (!ctx2.overlap || ctx2.toasts.length > 1)
710
- return;
711
- send("REGION.OVERLAP");
712
- },
713
- pauseToast(_ctx, evt, { self }) {
714
- self.sendChild("PAUSE", evt.id);
715
- },
716
- pauseToasts(ctx2) {
717
- ctx2.toasts.forEach((toast) => toast.send("PAUSE"));
718
- },
719
- resumeToast(_ctx, evt, { self }) {
720
- self.sendChild("RESUME", evt.id);
721
- },
722
- resumeToasts(ctx2) {
723
- ctx2.toasts.forEach((toast) => toast.send("RESUME"));
724
- },
725
- measureToasts(ctx2) {
726
- ctx2.toasts.forEach((toast) => toast.send("MEASURE"));
727
- },
728
- createToast(ctx2, evt, { self, getState }) {
729
- const options = {
730
- placement: ctx2.placement,
731
- duration: ctx2.duration,
732
- removeDelay: ctx2.removeDelay,
733
- ...evt.toast,
734
- dir: ctx2.dir,
735
- getRootNode: ctx2.getRootNode,
736
- stacked: getState().matches("stack")
737
- };
738
- const toast = createToastMachine(options);
739
- const actor = self.spawn(toast);
740
- ctx2.toasts = [actor, ...ctx2.toasts];
741
- },
742
- updateToast(_ctx, evt, { self }) {
743
- self.sendChild({ type: "UPDATE", toast: evt.toast }, evt.id);
744
- },
745
- dismissToast(_ctx, evt, { self }) {
746
- self.sendChild("DISMISS", evt.id);
747
- },
748
- dismissToasts(ctx2) {
749
- ctx2.toasts.forEach((toast) => toast.send("DISMISS"));
750
- },
751
- removeToast(ctx2, evt, { self }) {
752
- self.stopChild(evt.id);
753
- ctx2.toasts = ctx2.toasts.filter((toast) => toast.id !== evt.id);
754
- ctx2.heights = ctx2.heights.filter((height) => height.id !== evt.id);
755
- },
756
- removeToasts(ctx2, _evt, { self }) {
757
- ctx2.toasts.forEach((toast) => self.stopChild(toast.id));
758
- ctx2.toasts = [];
759
- ctx2.heights = [];
760
- },
761
- syncHeights(ctx2, evt) {
762
- const existing = ctx2.heights.find((height) => height.id === evt.id);
763
- if (existing) {
764
- existing.height = evt.height;
765
- existing.placement = evt.placement;
766
- } else {
767
- const newHeight = { id: evt.id, height: evt.height, placement: evt.placement };
768
- ctx2.heights = [newHeight, ...ctx2.heights];
769
- }
770
- },
771
- syncToastIndex(ctx2) {
772
- each(ctx2, (toast, index, toasts) => {
773
- toast.state.context.index = index;
774
- toast.state.context.frontmost = index === 0;
775
- toast.state.context.zIndex = toasts.length - index;
776
- });
777
- },
778
- syncToastOffset(ctx2, evt) {
779
- const placement = evt.placement ?? ctx2.placement;
780
- each({ ...ctx2, placement }, (toast) => {
781
- const heightIndex = Math.max(
782
- ctx2.heights.findIndex((height) => height.id === toast.id),
783
- 0
784
- );
785
- const toastsHeightBefore = ctx2.heights.reduce((prev, curr, reducerIndex) => {
786
- if (reducerIndex >= heightIndex)
787
- return prev;
788
- return prev + curr.height;
789
- }, 0);
790
- toast.state.context.offset = heightIndex * ctx2.gap + toastsHeightBefore;
791
- });
792
- },
793
- setLastFocusedEl(ctx2, evt) {
794
- if (ctx2.isFocusWithin || !evt.target)
795
- return;
796
- ctx2.isFocusWithin = true;
797
- ctx2.lastFocusedEl = ref(evt.target);
798
- },
799
- restoreLastFocusedEl(ctx2) {
800
- ctx2.isFocusWithin = false;
801
- if (!ctx2.lastFocusedEl)
802
- return;
803
- ctx2.lastFocusedEl.focus({ preventScroll: true });
804
- ctx2.lastFocusedEl = null;
805
- },
806
- clearLastFocusedEl(ctx2) {
807
- if (!ctx2.lastFocusedEl)
808
- return;
809
- ctx2.lastFocusedEl.focus({ preventScroll: true });
810
- ctx2.lastFocusedEl = null;
811
- ctx2.isFocusWithin = false;
812
- }
813
- }
814
- }
815
- );
816
- }
817
- function each(ctx, fn) {
818
- const currentToasts = getToastsByPlacement(ctx.toasts, ctx.placement);
819
- currentToasts.forEach(fn);
820
- }
821
-
822
- // src/toast.connect.ts
823
- import { dataAttr } from "@zag-js/dom-query";
824
- function connect(state, send, normalize) {
825
- const visible = state.hasTag("visible");
826
- const paused = state.hasTag("paused");
827
- const placement = state.context.placement;
828
- const type = state.context.type;
829
- const [side, align = "center"] = placement.split("-");
830
- return {
831
- type,
832
- title: state.context.title,
833
- description: state.context.description,
834
- placement,
835
- visible,
836
- paused,
837
- pause() {
838
- send("PAUSE");
839
- },
840
- resume() {
841
- send("RESUME");
842
- },
843
- dismiss() {
844
- send("DISMISS");
845
- },
846
- rootProps: normalize.element({
847
- ...parts.root.attrs,
848
- dir: state.context.dir,
849
- id: dom.getRootId(state.context),
850
- "data-state": visible ? "open" : "closed",
851
- "data-type": type,
852
- "data-placement": placement,
853
- "data-align": align,
854
- "data-side": side,
855
- "data-mounted": dataAttr(state.context.mounted),
856
- "data-paused": dataAttr(paused),
857
- "data-first": dataAttr(state.context.frontmost),
858
- "data-sibling": dataAttr(!state.context.frontmost),
859
- "data-stack": dataAttr(state.context.stacked),
860
- "data-overlap": dataAttr(!state.context.stacked),
861
- role: "status",
862
- "aria-atomic": "true",
863
- tabIndex: 0,
864
- style: getPlacementStyle(state.context, visible),
865
- onKeyDown(event) {
866
- if (event.defaultPrevented)
867
- return;
868
- if (event.key == "Escape") {
869
- send("DISMISS");
870
- event.preventDefault();
871
- }
872
- }
873
- }),
874
- /* Leave a ghost div to avoid setting hover to false when transitioning out */
875
- ghostBeforeProps: normalize.element({
876
- "data-ghost": "before",
877
- style: getGhostBeforeStyle(state.context, visible)
878
- }),
879
- /* Needed to avoid setting hover to false when in between toasts */
880
- ghostAfterProps: normalize.element({
881
- "data-ghost": "after",
882
- style: getGhostAfterStyle(state.context, visible)
883
- }),
884
- titleProps: normalize.element({
885
- ...parts.title.attrs,
886
- id: dom.getTitleId(state.context)
887
- }),
888
- descriptionProps: normalize.element({
889
- ...parts.description.attrs,
890
- id: dom.getDescriptionId(state.context)
891
- }),
892
- actionTriggerProps: normalize.button({
893
- ...parts.actionTrigger.attrs,
894
- type: "button",
895
- onClick(event) {
896
- if (event.defaultPrevented)
897
- return;
898
- send("DISMISS");
899
- }
900
- }),
901
- closeTriggerProps: normalize.button({
902
- id: dom.getCloseTriggerId(state.context),
903
- ...parts.closeTrigger.attrs,
904
- type: "button",
905
- "aria-label": "Dismiss notification",
906
- onClick(event) {
907
- if (event.defaultPrevented)
908
- return;
909
- send("DISMISS");
910
- }
911
- })
912
- };
913
- }
914
-
915
- // src/index.ts
916
- var group = {
917
- connect: groupConnect,
918
- machine: groupMachine
919
- };
920
- export {
921
- anatomy,
922
- connect,
923
- createToastMachine as createMachine,
924
- group
925
- };
1
+ import{isMachine,subscribe}from"@zag-js/core";import{contains}from"@zag-js/dom-query";import{runIfFn,uuid}from"@zag-js/utils";import{createAnatomy}from"@zag-js/anatomy";var anatomy=createAnatomy("toast").parts("group","root","title","description","actionTrigger","closeTrigger");var parts=anatomy.build();import{createScope}from"@zag-js/dom-query";var dom=createScope({getRegionId:placement=>`toast-group:${placement}`,getRegionEl:(ctx,placement)=>dom.getById(ctx,`toast-group:${placement}`),getRootId:ctx=>`toast:${ctx.id}`,getRootEl:ctx=>dom.getById(ctx,dom.getRootId(ctx)),getTitleId:ctx=>`toast:${ctx.id}:title`,getDescriptionId:ctx=>`toast:${ctx.id}:description`,getCloseTriggerId:ctx=>`toast${ctx.id}:close`});import{MAX_Z_INDEX}from"@zag-js/dom-query";function getToastsByPlacement(toasts,placement){return toasts.filter(toast=>toast.state.context.placement===placement)}var defaultTimeouts={info:5e3,error:5e3,success:2e3,loading:Infinity,DEFAULT:5e3};function getToastDuration(duration,type){return duration??defaultTimeouts[type]??defaultTimeouts.DEFAULT}function getGroupPlacementStyle(ctx,placement){const offset=ctx.offsets;const computedOffset=typeof offset==="string"?{left:offset,right:offset,bottom:offset,top:offset}:offset;const rtl=ctx.dir==="rtl";const computedPlacement=placement.replace("-start",rtl?"-right":"-left").replace("-end",rtl?"-left":"-right");const isRighty=computedPlacement.includes("right");const isLefty=computedPlacement.includes("left");const styles={position:"fixed",pointerEvents:ctx.count>0?void 0:"none",display:"flex",flexDirection:"column","--gap":`${ctx.gap}px`,"--first-height":`${ctx.heights[0]?.height||0}px`,zIndex:MAX_Z_INDEX};let alignItems="center";if(isRighty)alignItems="flex-end";if(isLefty)alignItems="flex-start";styles.alignItems=alignItems;if(computedPlacement.includes("top")){const offset2=computedOffset.top;styles.top=`max(env(safe-area-inset-top, 0px), ${offset2})`}if(computedPlacement.includes("bottom")){const offset2=computedOffset.bottom;styles.bottom=`max(env(safe-area-inset-bottom, 0px), ${offset2})`}if(!computedPlacement.includes("left")){const offset2=computedOffset.right;styles.insetInlineEnd=`calc(env(safe-area-inset-right, 0px) + ${offset2})`}if(!computedPlacement.includes("right")){const offset2=computedOffset.left;styles.insetInlineStart=`calc(env(safe-area-inset-left, 0px) + ${offset2})`}return styles}function getPlacementStyle(ctx,visible){const[side]=ctx.placement.split("-");const sibling=!ctx.frontmost;const overlap=!ctx.stacked;const styles={position:"absolute",pointerEvents:"auto","--opacity":"0","--remove-delay":`${ctx.removeDelay}ms`,"--duration":`${ctx.type==="loading"?Number.MAX_SAFE_INTEGER:ctx.duration}ms`,"--initial-height":`${ctx.height}px`,"--offset":`${ctx.offset}px`,"--index":ctx.index,"--z-index":ctx.zIndex,"--lift-amount":"calc(var(--lift) * var(--gap))","--y":"100%","--x":"0"};const assign=overrides=>Object.assign(styles,overrides);if(side==="top"){assign({top:"0","--sign":"-1","--y":"-100%","--lift":"1"})}else if(side==="bottom"){assign({bottom:"0","--sign":"1","--y":"100%","--lift":"-1"})}if(ctx.mounted){assign({"--y":"0","--opacity":"1"});if(ctx.stacked){assign({"--y":"calc(var(--lift) * var(--offset))","--height":"var(--initial-height)"})}}if(!visible){assign({"--opacity":"0",pointerEvents:"none"})}if(sibling&&overlap){assign({"--base-scale":"var(--index) * 0.05 + 1","--y":"calc(var(--lift-amount) * var(--index))","--scale":"calc(-1 * var(--base-scale))","--height":"var(--first-height)"});if(!visible){assign({"--y":"calc(var(--sign) * 40%)"})}}if(sibling&&ctx.stacked&&!visible){assign({"--y":"calc(var(--lift) * var(--offset) + var(--lift) * -100%)"})}if(ctx.frontmost&&!visible){assign({"--y":"calc(var(--lift) * -100%)"})}return styles}function getGhostBeforeStyle(ctx,visible){const styles={position:"absolute",inset:"0",scale:"1 2",pointerEvents:visible?"none":"auto"};const assign=overrides=>Object.assign(styles,overrides);if(ctx.frontmost&&!visible){assign({height:"calc(var(--initial-height) + 80%)"})}return styles}function getGhostAfterStyle(_ctx,_visible){return{position:"absolute",left:"0",height:"calc(var(--gap) + 2px)",bottom:"100%",width:"100%"}}function groupConnect(serviceOrState,send,normalize){function getState(){const result=isMachine(serviceOrState)?serviceOrState.getState():serviceOrState;return result}function getToastsByPlacementImpl(placement){return getToastsByPlacement(getState().context.toasts,placement)}function isVisible(id){const toasts=getState().context.toasts;if(!toasts.length)return false;return!!toasts.find(toast=>toast.id==id)}function create(options){const uid=`toast:${uuid()}`;const id=options.id?options.id:uid;if(isVisible(id))return id;send({type:"ADD_TOAST",toast:{...options,id}});return id}function update(id,options){if(!isVisible(id))return id;send({type:"UPDATE_TOAST",id,toast:options});return id}function upsert(options){const{id}=options;const visible=id?isVisible(id):false;if(visible&&id!=null){return update(id,options)}else{return create(options)}}function dismiss(id){if(id==null){send("DISMISS_ALL")}else if(isVisible(id)){send({type:"DISMISS_TOAST",id})}}return{getCount(){return getState().context.count},getPlacements(){const toasts=getState().context.toasts;const placements=toasts.map(toast=>toast.state.context.placement);return Array.from(new Set(placements))},getToastsByPlacement:getToastsByPlacementImpl,isVisible,create,update,upsert,dismiss,remove(id){if(id==null){send("REMOVE_ALL")}else if(isVisible(id)){send({type:"REMOVE_TOAST",id})}},dismissByPlacement(placement){const toasts=getToastsByPlacementImpl(placement);toasts.forEach(toast=>dismiss(toast.id))},loading(options){return upsert({...options,type:"loading"})},success(options){return upsert({...options,type:"success"})},error(options){return upsert({...options,type:"error"})},promise(promise,options,shared={}){const id=upsert({...shared,...options.loading,type:"loading"});runIfFn(promise).then(response=>{const successOptions=runIfFn(options.success,response);upsert({...shared,...successOptions,id,type:"success"})}).catch(error=>{const errorOptions=runIfFn(options.error,error);upsert({...shared,...errorOptions,id,type:"error"})}).finally(()=>{options.finally?.()});return id},pause(id){if(id==null){send("PAUSE_ALL")}else if(isVisible(id)){send({type:"PAUSE_TOAST",id})}},resume(id){if(id==null){send("RESUME_ALL")}else if(isVisible(id)){send({type:"RESUME_TOAST",id})}},getGroupProps(options){const{placement,label="Notifications"}=options;const state=getState();const hotkeyLabel=state.context.hotkey.join("+").replace(/Key/g,"").replace(/Digit/g,"");const[side,align="center"]=placement.split("-");return normalize.element({...parts.group.attrs,dir:state.context.dir,tabIndex:-1,"aria-label":`${placement} ${label} ${hotkeyLabel}`,id:dom.getRegionId(placement),"data-placement":placement,"data-side":side,"data-align":align,"aria-live":"polite",role:"region",style:getGroupPlacementStyle(state.context,placement),onMouseMove(){send({type:"REGION.POINTER_ENTER",placement})},onMouseLeave(){send({type:"REGION.POINTER_LEAVE",placement})},onFocus(event){send({type:"REGION.FOCUS",target:event.relatedTarget})},onBlur(event){if(state.context.isFocusWithin&&!contains(event.currentTarget,event.relatedTarget)){send({type:"REGION.BLUR"})}}})},subscribe(fn){const state=getState();return subscribe(state.context.toasts,()=>{const toasts=getToastsByPlacementImpl(state.context.placement);const contexts=toasts.map(toast=>toast.getState().context);fn(contexts)})}}}import{createMachine as createMachine2,ref}from"@zag-js/core";import{trackDismissableBranch}from"@zag-js/dismissable";import{addDomEvent}from"@zag-js/dom-event";import{compact as compact2}from"@zag-js/utils";import{createMachine,guards}from"@zag-js/core";import{queryAll,raf}from"@zag-js/dom-query";import{compact,warn}from"@zag-js/utils";var{not,and,or}=guards;function createToastMachine(options){const{type="info",duration,id="1",placement="bottom",removeDelay=200,...restProps}=options;const ctx=compact(restProps);const computedDuration=getToastDuration(duration,type);return createMachine({id,context:{id,type,remaining:computedDuration,duration:computedDuration,removeDelay,createdAt:Date.now(),placement,...ctx,height:0,offset:0,frontmost:false,mounted:false,index:-1,zIndex:0},initial:type==="loading"?"visible:persist":"visible",on:{UPDATE:[{guard:and("hasTypeChanged","isChangingToLoading"),target:"visible:persist",actions:["setContext"]},{guard:or("hasDurationChanged","hasTypeChanged"),target:"visible:updating",actions:["setContext"]},{actions:["setContext"]}],MEASURE:{actions:["measureHeight"]}},entry:["invokeOnVisible"],activities:["trackHeight"],states:{"visible:updating":{tags:["visible","updating"],after:{0:"visible"}},"visible:persist":{tags:["visible","paused"],on:{RESUME:{guard:not("isLoadingType"),target:"visible",actions:["setCreatedAt"]},DISMISS:"dismissing"}},visible:{tags:["visible"],after:{VISIBLE_DURATION:"dismissing"},on:{DISMISS:"dismissing",PAUSE:{target:"visible:persist",actions:"setRemainingDuration"}}},dismissing:{entry:"invokeOnDismiss",after:{REMOVE_DELAY:{target:"unmounted",actions:"notifyParentToRemove"}}},unmounted:{entry:"invokeOnUnmount",type:"final"}}},{activities:{trackHeight(ctx2,_evt,{self}){let cleanup;raf(()=>{const rootEl=dom.getRootEl(ctx2);if(!rootEl)return;ctx2.mounted=true;const ghosts=queryAll(rootEl,"[data-ghost]");warn(ghosts.length!==2,"[toast] No ghost element found in toast. Render the `ghostBefore` and `ghostAfter` elements");const syncHeight=()=>{const originalHeight=rootEl.style.height;rootEl.style.height="auto";const newHeight=rootEl.getBoundingClientRect().height;rootEl.style.height=originalHeight;ctx2.height=newHeight;self.sendParent({type:"UPDATE_HEIGHT",id:self.id,height:newHeight,placement:ctx2.placement})};syncHeight();const win=dom.getWin(ctx2);const observer=new win.MutationObserver(syncHeight);observer.observe(rootEl,{childList:true,subtree:true,characterData:true});cleanup=()=>observer.disconnect()});return()=>cleanup?.()}},guards:{isChangingToLoading:(_,evt)=>evt.toast?.type==="loading",isLoadingType:ctx2=>ctx2.type==="loading",hasTypeChanged:(ctx2,evt)=>evt.toast?.type!=null&&evt.toast.type!==ctx2.type,hasDurationChanged:(ctx2,evt)=>evt.toast?.duration!=null&&evt.toast.duration!==ctx2.duration},delays:{VISIBLE_DURATION:ctx2=>ctx2.remaining,REMOVE_DELAY:ctx2=>ctx2.removeDelay},actions:{measureHeight(ctx2,_evt,{self}){raf(()=>{const rootEl=dom.getRootEl(ctx2);if(!rootEl)return;ctx2.mounted=true;const originalHeight=rootEl.style.height;rootEl.style.height="auto";const newHeight=rootEl.getBoundingClientRect().height;rootEl.style.height=originalHeight;ctx2.height=newHeight;self.sendParent({type:"UPDATE_HEIGHT",id:self.id,height:newHeight,placement:ctx2.placement})})},setRemainingDuration(ctx2){ctx2.remaining-=Date.now()-ctx2.createdAt},setCreatedAt(ctx2){ctx2.createdAt=Date.now()},notifyParentToRemove(_ctx,_evt,{self}){self.sendParent({type:"REMOVE_TOAST",id:self.id})},invokeOnDismiss(ctx2){ctx2.onStatusChange?.({status:"dismissing"})},invokeOnUnmount(ctx2){ctx2.onStatusChange?.({status:"unmounted"})},invokeOnVisible(ctx2){ctx2.onStatusChange?.({status:"visible"})},setContext(ctx2,evt){const duration2=evt.toast?.duration;const type2=evt.toast?.type??ctx2.type;const computedDuration2=getToastDuration(duration2,type2);Object.assign(ctx2,{...evt.toast,duration:computedDuration2,remaining:computedDuration2})}}})}function groupMachine(userContext){const ctx=compact2(userContext);return createMachine2({id:"toaster",initial:ctx.overlap?"overlap":"stack",context:{dir:"ltr",max:Number.MAX_SAFE_INTEGER,gap:16,pauseOnPageIdle:false,hotkey:["altKey","KeyT"],offsets:"1rem",placement:"bottom",removeDelay:200,...ctx,toasts:[],lastFocusedEl:null,isFocusWithin:false,heights:[]},computed:{count:ctx2=>ctx2.toasts.length},activities:["trackDocumentVisibility","trackHotKeyPress"],watch:{toasts:["collapsedIfEmpty","setDismissableBranch"]},exit:["removeToasts","clearDismissableBranch","clearLastFocusedEl"],on:{PAUSE_TOAST:{actions:["pauseToast"]},PAUSE_ALL:{actions:["pauseToasts"]},RESUME_TOAST:{actions:["resumeToast"]},RESUME_ALL:{actions:["resumeToasts"]},ADD_TOAST:{guard:"isWithinRange",actions:["createToast","syncToastIndex"]},UPDATE_TOAST:{actions:["updateToast"]},DISMISS_TOAST:{actions:["dismissToast"]},DISMISS_ALL:{actions:["dismissToasts"]},REMOVE_TOAST:{actions:["removeToast","syncToastIndex","syncToastOffset"]},REMOVE_ALL:{actions:["removeToasts"]},UPDATE_HEIGHT:{actions:["syncHeights","syncToastOffset"]},"DOC.HOTKEY":{actions:["focusRegionEl"]},"REGION.BLUR":[{guard:"isOverlapping",target:"overlap",actions:["resumeToasts","restoreLastFocusedEl"]},{actions:["resumeToasts","restoreLastFocusedEl"]}]},states:{stack:{entry:["expandToasts"],on:{"REGION.POINTER_LEAVE":[{guard:"isOverlapping",target:"overlap",actions:["resumeToasts"]},{actions:["resumeToasts"]}],"REGION.OVERLAP":{target:"overlap"},"REGION.FOCUS":{actions:["setLastFocusedEl","pauseToasts"]},"REGION.POINTER_ENTER":{actions:["pauseToasts"]}}},overlap:{entry:["collapseToasts"],on:{"REGION.STACK":{target:"stack"},"REGION.POINTER_ENTER":{target:"stack",actions:["pauseToasts"]},"REGION.FOCUS":{target:"stack",actions:["setLastFocusedEl","pauseToasts"]}}}}},{guards:{isWithinRange:ctx2=>ctx2.toasts.length<ctx2.max,isOverlapping:ctx2=>!!ctx2.overlap},activities:{trackHotKeyPress(ctx2,_evt,{send}){const handleKeyDown=event=>{const isHotkeyPressed=ctx2.hotkey.every(key=>event[key]||event.code===key);if(!isHotkeyPressed)return;send({type:"DOC.HOTKEY"})};return addDomEvent(document,"keydown",handleKeyDown,{capture:true})},trackDocumentVisibility(ctx2,_evt,{send}){if(!ctx2.pauseOnPageIdle)return;const doc=dom.getDoc(ctx2);return addDomEvent(doc,"visibilitychange",()=>{send(doc.visibilityState==="hidden"?"PAUSE_ALL":"RESUME_ALL")})}},actions:{setDismissableBranch(ctx2){const currentToasts=getToastsByPlacement(ctx2.toasts,ctx2.placement);const hasToasts=currentToasts.length>0;if(!hasToasts){ctx2._cleanup?.();return}if(hasToasts&&ctx2._cleanup){return}const groupEl=()=>dom.getRegionEl(ctx2,ctx2.placement);ctx2._cleanup=trackDismissableBranch(groupEl,{defer:true})},clearDismissableBranch(ctx2){ctx2._cleanup?.()},focusRegionEl(ctx2){queueMicrotask(()=>{dom.getRegionEl(ctx2,ctx2.placement)?.focus()})},expandToasts(ctx2){each(ctx2,toast=>{toast.state.context.stacked=true})},collapseToasts(ctx2){each(ctx2,toast=>{toast.state.context.stacked=false})},collapsedIfEmpty(ctx2,_evt,{send}){if(!ctx2.overlap||ctx2.toasts.length>1)return;send("REGION.OVERLAP")},pauseToast(_ctx,evt,{self}){self.sendChild("PAUSE",evt.id)},pauseToasts(ctx2){ctx2.toasts.forEach(toast=>toast.send("PAUSE"))},resumeToast(_ctx,evt,{self}){self.sendChild("RESUME",evt.id)},resumeToasts(ctx2){ctx2.toasts.forEach(toast=>toast.send("RESUME"))},measureToasts(ctx2){ctx2.toasts.forEach(toast=>toast.send("MEASURE"))},createToast(ctx2,evt,{self,getState}){const options={placement:ctx2.placement,duration:ctx2.duration,removeDelay:ctx2.removeDelay,...evt.toast,dir:ctx2.dir,getRootNode:ctx2.getRootNode,stacked:getState().matches("stack")};const toast=createToastMachine(options);const actor=self.spawn(toast);ctx2.toasts=[actor,...ctx2.toasts]},updateToast(_ctx,evt,{self}){self.sendChild({type:"UPDATE",toast:evt.toast},evt.id)},dismissToast(_ctx,evt,{self}){self.sendChild("DISMISS",evt.id)},dismissToasts(ctx2){ctx2.toasts.forEach(toast=>toast.send("DISMISS"))},removeToast(ctx2,evt,{self}){self.stopChild(evt.id);ctx2.toasts=ctx2.toasts.filter(toast=>toast.id!==evt.id);ctx2.heights=ctx2.heights.filter(height=>height.id!==evt.id)},removeToasts(ctx2,_evt,{self}){ctx2.toasts.forEach(toast=>self.stopChild(toast.id));ctx2.toasts=[];ctx2.heights=[]},syncHeights(ctx2,evt){const existing=ctx2.heights.find(height=>height.id===evt.id);if(existing){existing.height=evt.height;existing.placement=evt.placement}else{const newHeight={id:evt.id,height:evt.height,placement:evt.placement};ctx2.heights=[newHeight,...ctx2.heights]}},syncToastIndex(ctx2){each(ctx2,(toast,index,toasts)=>{toast.state.context.index=index;toast.state.context.frontmost=index===0;toast.state.context.zIndex=toasts.length-index})},syncToastOffset(ctx2,evt){const placement=evt.placement??ctx2.placement;each({...ctx2,placement},toast=>{const heightIndex=Math.max(ctx2.heights.findIndex(height=>height.id===toast.id),0);const toastsHeightBefore=ctx2.heights.reduce((prev,curr,reducerIndex)=>{if(reducerIndex>=heightIndex)return prev;return prev+curr.height},0);toast.state.context.offset=heightIndex*ctx2.gap+toastsHeightBefore})},setLastFocusedEl(ctx2,evt){if(ctx2.isFocusWithin||!evt.target)return;ctx2.isFocusWithin=true;ctx2.lastFocusedEl=ref(evt.target)},restoreLastFocusedEl(ctx2){ctx2.isFocusWithin=false;if(!ctx2.lastFocusedEl)return;ctx2.lastFocusedEl.focus({preventScroll:true});ctx2.lastFocusedEl=null},clearLastFocusedEl(ctx2){if(!ctx2.lastFocusedEl)return;ctx2.lastFocusedEl.focus({preventScroll:true});ctx2.lastFocusedEl=null;ctx2.isFocusWithin=false}}})}function each(ctx,fn){const currentToasts=getToastsByPlacement(ctx.toasts,ctx.placement);currentToasts.forEach(fn)}import{dataAttr}from"@zag-js/dom-query";function connect(state,send,normalize){const visible=state.hasTag("visible");const paused=state.hasTag("paused");const placement=state.context.placement;const type=state.context.type;const[side,align="center"]=placement.split("-");return{type,title:state.context.title,description:state.context.description,placement,visible,paused,pause(){send("PAUSE")},resume(){send("RESUME")},dismiss(){send("DISMISS")},rootProps:normalize.element({...parts.root.attrs,dir:state.context.dir,id:dom.getRootId(state.context),"data-state":visible?"open":"closed","data-type":type,"data-placement":placement,"data-align":align,"data-side":side,"data-mounted":dataAttr(state.context.mounted),"data-paused":dataAttr(paused),"data-first":dataAttr(state.context.frontmost),"data-sibling":dataAttr(!state.context.frontmost),"data-stack":dataAttr(state.context.stacked),"data-overlap":dataAttr(!state.context.stacked),role:"status","aria-atomic":"true",tabIndex:0,style:getPlacementStyle(state.context,visible),onKeyDown(event){if(event.defaultPrevented)return;if(event.key=="Escape"){send("DISMISS");event.preventDefault()}}}),ghostBeforeProps:normalize.element({"data-ghost":"before",style:getGhostBeforeStyle(state.context,visible)}),ghostAfterProps:normalize.element({"data-ghost":"after",style:getGhostAfterStyle(state.context,visible)}),titleProps:normalize.element({...parts.title.attrs,id:dom.getTitleId(state.context)}),descriptionProps:normalize.element({...parts.description.attrs,id:dom.getDescriptionId(state.context)}),actionTriggerProps:normalize.button({...parts.actionTrigger.attrs,type:"button",onClick(event){if(event.defaultPrevented)return;send("DISMISS")}}),closeTriggerProps:normalize.button({id:dom.getCloseTriggerId(state.context),...parts.closeTrigger.attrs,type:"button","aria-label":"Dismiss notification",onClick(event){if(event.defaultPrevented)return;send("DISMISS")}})}}var group={connect:groupConnect,machine:groupMachine};export{anatomy,connect,createToastMachine as createMachine,group};
926
2
  //# sourceMappingURL=index.mjs.map