@zag-js/toast 1.44.0 → 1.46.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/toast-group.machine.js +15 -3
- package/dist/toast-group.machine.mjs +15 -3
- package/dist/toast.connect.js +5 -4
- package/dist/toast.connect.mjs +5 -4
- package/dist/toast.dom.d.mts +3 -1
- package/dist/toast.dom.d.ts +3 -1
- package/dist/toast.dom.js +6 -0
- package/dist/toast.dom.mjs +4 -0
- package/dist/toast.machine.js +36 -13
- package/dist/toast.machine.mjs +36 -13
- package/dist/toast.store.js +99 -63
- package/dist/toast.store.mjs +100 -64
- package/dist/toast.types.d.mts +11 -4
- package/dist/toast.types.d.ts +11 -4
- package/package.json +7 -7
|
@@ -89,6 +89,12 @@ var groupMachine = createMachine({
|
|
|
89
89
|
},
|
|
90
90
|
exit: ["clearDismissableBranch", "clearLastFocusedEl", "clearMouseEventTimer"],
|
|
91
91
|
on: {
|
|
92
|
+
PAUSE_ALL: {
|
|
93
|
+
actions: ["pauseToasts"]
|
|
94
|
+
},
|
|
95
|
+
RESUME_ALL: {
|
|
96
|
+
actions: ["resumeToasts"]
|
|
97
|
+
},
|
|
92
98
|
"DOC.HOTKEY": {
|
|
93
99
|
actions: ["focusRegionEl"]
|
|
94
100
|
},
|
|
@@ -192,6 +198,7 @@ var groupMachine = createMachine({
|
|
|
192
198
|
const { pauseOnPageIdle } = prop("store").attrs;
|
|
193
199
|
if (!pauseOnPageIdle) return;
|
|
194
200
|
const doc = scope.getDoc();
|
|
201
|
+
if (doc.visibilityState === "hidden") send({ type: "PAUSE_ALL" });
|
|
195
202
|
return (0, import_dom_query.addDomEvent)(doc, "visibilitychange", () => {
|
|
196
203
|
const isHidden = doc.visibilityState === "hidden";
|
|
197
204
|
send({ type: isHidden ? "PAUSE_ALL" : "RESUME_ALL" });
|
|
@@ -205,6 +212,7 @@ var groupMachine = createMachine({
|
|
|
205
212
|
const hasToasts = toasts.length > 0;
|
|
206
213
|
if (!hasToasts) {
|
|
207
214
|
refs.get("dismissableCleanup")?.();
|
|
215
|
+
refs.set("dismissableCleanup", void 0);
|
|
208
216
|
return;
|
|
209
217
|
}
|
|
210
218
|
if (hasToasts && refs.get("dismissableCleanup")) {
|
|
@@ -216,6 +224,7 @@ var groupMachine = createMachine({
|
|
|
216
224
|
},
|
|
217
225
|
clearDismissableBranch({ refs }) {
|
|
218
226
|
refs.get("dismissableCleanup")?.();
|
|
227
|
+
refs.set("dismissableCleanup", void 0);
|
|
219
228
|
},
|
|
220
229
|
focusRegionEl({ scope, computed }) {
|
|
221
230
|
queueMicrotask(() => {
|
|
@@ -225,7 +234,10 @@ var groupMachine = createMachine({
|
|
|
225
234
|
pauseToasts({ prop }) {
|
|
226
235
|
prop("store").pause();
|
|
227
236
|
},
|
|
228
|
-
resumeToasts({ prop }) {
|
|
237
|
+
resumeToasts({ prop, refs, scope, event }) {
|
|
238
|
+
if (event.type === "REGION.BLUR") refs.set("isFocusWithin", false);
|
|
239
|
+
const idle = prop("store").attrs.pauseOnPageIdle && scope.getDoc().visibilityState === "hidden";
|
|
240
|
+
if (idle || refs.get("isPointerWithin") || refs.get("isFocusWithin")) return;
|
|
229
241
|
prop("store").resume();
|
|
230
242
|
},
|
|
231
243
|
expandToasts({ prop }) {
|
|
@@ -248,9 +260,9 @@ var groupMachine = createMachine({
|
|
|
248
260
|
send({ type: "REGION.OVERLAP" });
|
|
249
261
|
},
|
|
250
262
|
setLastFocusedEl({ refs, event }) {
|
|
251
|
-
if (refs.get("isFocusWithin")
|
|
263
|
+
if (refs.get("isFocusWithin")) return;
|
|
252
264
|
refs.set("isFocusWithin", true);
|
|
253
|
-
refs.set("lastFocusedEl", event.target);
|
|
265
|
+
refs.set("lastFocusedEl", event.target ?? null);
|
|
254
266
|
},
|
|
255
267
|
restoreFocusIfPointerOut({ refs }) {
|
|
256
268
|
if (!refs.get("lastFocusedEl") || refs.get("isPointerWithin")) return;
|
|
@@ -55,6 +55,12 @@ var groupMachine = createMachine({
|
|
|
55
55
|
},
|
|
56
56
|
exit: ["clearDismissableBranch", "clearLastFocusedEl", "clearMouseEventTimer"],
|
|
57
57
|
on: {
|
|
58
|
+
PAUSE_ALL: {
|
|
59
|
+
actions: ["pauseToasts"]
|
|
60
|
+
},
|
|
61
|
+
RESUME_ALL: {
|
|
62
|
+
actions: ["resumeToasts"]
|
|
63
|
+
},
|
|
58
64
|
"DOC.HOTKEY": {
|
|
59
65
|
actions: ["focusRegionEl"]
|
|
60
66
|
},
|
|
@@ -158,6 +164,7 @@ var groupMachine = createMachine({
|
|
|
158
164
|
const { pauseOnPageIdle } = prop("store").attrs;
|
|
159
165
|
if (!pauseOnPageIdle) return;
|
|
160
166
|
const doc = scope.getDoc();
|
|
167
|
+
if (doc.visibilityState === "hidden") send({ type: "PAUSE_ALL" });
|
|
161
168
|
return addDomEvent(doc, "visibilitychange", () => {
|
|
162
169
|
const isHidden = doc.visibilityState === "hidden";
|
|
163
170
|
send({ type: isHidden ? "PAUSE_ALL" : "RESUME_ALL" });
|
|
@@ -171,6 +178,7 @@ var groupMachine = createMachine({
|
|
|
171
178
|
const hasToasts = toasts.length > 0;
|
|
172
179
|
if (!hasToasts) {
|
|
173
180
|
refs.get("dismissableCleanup")?.();
|
|
181
|
+
refs.set("dismissableCleanup", void 0);
|
|
174
182
|
return;
|
|
175
183
|
}
|
|
176
184
|
if (hasToasts && refs.get("dismissableCleanup")) {
|
|
@@ -182,6 +190,7 @@ var groupMachine = createMachine({
|
|
|
182
190
|
},
|
|
183
191
|
clearDismissableBranch({ refs }) {
|
|
184
192
|
refs.get("dismissableCleanup")?.();
|
|
193
|
+
refs.set("dismissableCleanup", void 0);
|
|
185
194
|
},
|
|
186
195
|
focusRegionEl({ scope, computed }) {
|
|
187
196
|
queueMicrotask(() => {
|
|
@@ -191,7 +200,10 @@ var groupMachine = createMachine({
|
|
|
191
200
|
pauseToasts({ prop }) {
|
|
192
201
|
prop("store").pause();
|
|
193
202
|
},
|
|
194
|
-
resumeToasts({ prop }) {
|
|
203
|
+
resumeToasts({ prop, refs, scope, event }) {
|
|
204
|
+
if (event.type === "REGION.BLUR") refs.set("isFocusWithin", false);
|
|
205
|
+
const idle = prop("store").attrs.pauseOnPageIdle && scope.getDoc().visibilityState === "hidden";
|
|
206
|
+
if (idle || refs.get("isPointerWithin") || refs.get("isFocusWithin")) return;
|
|
195
207
|
prop("store").resume();
|
|
196
208
|
},
|
|
197
209
|
expandToasts({ prop }) {
|
|
@@ -214,9 +226,9 @@ var groupMachine = createMachine({
|
|
|
214
226
|
send({ type: "REGION.OVERLAP" });
|
|
215
227
|
},
|
|
216
228
|
setLastFocusedEl({ refs, event }) {
|
|
217
|
-
if (refs.get("isFocusWithin")
|
|
229
|
+
if (refs.get("isFocusWithin")) return;
|
|
218
230
|
refs.set("isFocusWithin", true);
|
|
219
|
-
refs.set("lastFocusedEl", event.target);
|
|
231
|
+
refs.set("lastFocusedEl", event.target ?? null);
|
|
220
232
|
},
|
|
221
233
|
restoreFocusIfPointerOut({ refs }) {
|
|
222
234
|
if (!refs.get("lastFocusedEl") || refs.get("isPointerWithin")) return;
|
package/dist/toast.connect.js
CHANGED
|
@@ -47,6 +47,7 @@ function connect(service, normalize) {
|
|
|
47
47
|
const visible = state.hasTag("visible");
|
|
48
48
|
const paused = state.hasTag("paused");
|
|
49
49
|
const mounted = context.get("mounted");
|
|
50
|
+
const rendered = context.get("rendered");
|
|
50
51
|
const frontmost = computed("frontmost");
|
|
51
52
|
const placement = prop("parent").computed("placement");
|
|
52
53
|
const type = prop("type");
|
|
@@ -64,10 +65,10 @@ function connect(service, normalize) {
|
|
|
64
65
|
paused,
|
|
65
66
|
closable: !!prop("closable"),
|
|
66
67
|
pause() {
|
|
67
|
-
|
|
68
|
+
prop("parent").prop("store").pause(prop("id"));
|
|
68
69
|
},
|
|
69
70
|
resume() {
|
|
70
|
-
|
|
71
|
+
prop("parent").prop("store").resume(prop("id"));
|
|
71
72
|
},
|
|
72
73
|
dismiss() {
|
|
73
74
|
send({ type: "DISMISS", src: "programmatic" });
|
|
@@ -90,8 +91,8 @@ function connect(service, normalize) {
|
|
|
90
91
|
"data-overlap": (0, import_dom_query.dataAttr)(!stacked),
|
|
91
92
|
role: "status",
|
|
92
93
|
"aria-atomic": "true",
|
|
93
|
-
"aria-describedby": description ? dom.getDescriptionId(scope) : void 0,
|
|
94
|
-
"aria-labelledby": title ? dom.getTitleId(scope) : void 0,
|
|
94
|
+
"aria-describedby": description && rendered.description ? dom.getDescriptionId(scope) : void 0,
|
|
95
|
+
"aria-labelledby": title && rendered.title ? dom.getTitleId(scope) : void 0,
|
|
95
96
|
tabIndex: 0,
|
|
96
97
|
style: (0, import_toast2.getPlacementStyle)(service, visible),
|
|
97
98
|
onKeyDown(event) {
|
package/dist/toast.connect.mjs
CHANGED
|
@@ -13,6 +13,7 @@ function connect(service, normalize) {
|
|
|
13
13
|
const visible = state.hasTag("visible");
|
|
14
14
|
const paused = state.hasTag("paused");
|
|
15
15
|
const mounted = context.get("mounted");
|
|
16
|
+
const rendered = context.get("rendered");
|
|
16
17
|
const frontmost = computed("frontmost");
|
|
17
18
|
const placement = prop("parent").computed("placement");
|
|
18
19
|
const type = prop("type");
|
|
@@ -30,10 +31,10 @@ function connect(service, normalize) {
|
|
|
30
31
|
paused,
|
|
31
32
|
closable: !!prop("closable"),
|
|
32
33
|
pause() {
|
|
33
|
-
|
|
34
|
+
prop("parent").prop("store").pause(prop("id"));
|
|
34
35
|
},
|
|
35
36
|
resume() {
|
|
36
|
-
|
|
37
|
+
prop("parent").prop("store").resume(prop("id"));
|
|
37
38
|
},
|
|
38
39
|
dismiss() {
|
|
39
40
|
send({ type: "DISMISS", src: "programmatic" });
|
|
@@ -56,8 +57,8 @@ function connect(service, normalize) {
|
|
|
56
57
|
"data-overlap": dataAttr(!stacked),
|
|
57
58
|
role: "status",
|
|
58
59
|
"aria-atomic": "true",
|
|
59
|
-
"aria-describedby": description ? dom.getDescriptionId(scope) : void 0,
|
|
60
|
-
"aria-labelledby": title ? dom.getTitleId(scope) : void 0,
|
|
60
|
+
"aria-describedby": description && rendered.description ? dom.getDescriptionId(scope) : void 0,
|
|
61
|
+
"aria-labelledby": title && rendered.title ? dom.getTitleId(scope) : void 0,
|
|
61
62
|
tabIndex: 0,
|
|
62
63
|
style: getPlacementStyle(service, visible),
|
|
63
64
|
onKeyDown(event) {
|
package/dist/toast.dom.d.mts
CHANGED
|
@@ -9,6 +9,8 @@ declare const getRootId: (ctx: Scope) => string;
|
|
|
9
9
|
declare const getRootEl: (ctx: Scope) => HTMLElement | null;
|
|
10
10
|
declare const getTitleId: (ctx: Scope) => string;
|
|
11
11
|
declare const getDescriptionId: (ctx: Scope) => string;
|
|
12
|
+
declare const getTitleEl: (ctx: Scope) => HTMLElement | null;
|
|
13
|
+
declare const getDescriptionEl: (ctx: Scope) => HTMLElement | null;
|
|
12
14
|
declare const getCloseTriggerId: (ctx: Scope) => string;
|
|
13
15
|
|
|
14
|
-
export { getCloseTriggerId, getDescriptionId, getRegionEl, getRegionId, getRootEl, getRootId, getTitleId };
|
|
16
|
+
export { getCloseTriggerId, getDescriptionEl, getDescriptionId, getRegionEl, getRegionId, getRootEl, getRootId, getTitleEl, getTitleId };
|
package/dist/toast.dom.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ declare const getRootId: (ctx: Scope) => string;
|
|
|
9
9
|
declare const getRootEl: (ctx: Scope) => HTMLElement | null;
|
|
10
10
|
declare const getTitleId: (ctx: Scope) => string;
|
|
11
11
|
declare const getDescriptionId: (ctx: Scope) => string;
|
|
12
|
+
declare const getTitleEl: (ctx: Scope) => HTMLElement | null;
|
|
13
|
+
declare const getDescriptionEl: (ctx: Scope) => HTMLElement | null;
|
|
12
14
|
declare const getCloseTriggerId: (ctx: Scope) => string;
|
|
13
15
|
|
|
14
|
-
export { getCloseTriggerId, getDescriptionId, getRegionEl, getRegionId, getRootEl, getRootId, getTitleId };
|
|
16
|
+
export { getCloseTriggerId, getDescriptionEl, getDescriptionId, getRegionEl, getRegionId, getRootEl, getRootId, getTitleEl, getTitleId };
|
package/dist/toast.dom.js
CHANGED
|
@@ -21,11 +21,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var toast_dom_exports = {};
|
|
22
22
|
__export(toast_dom_exports, {
|
|
23
23
|
getCloseTriggerId: () => getCloseTriggerId,
|
|
24
|
+
getDescriptionEl: () => getDescriptionEl,
|
|
24
25
|
getDescriptionId: () => getDescriptionId,
|
|
25
26
|
getRegionEl: () => getRegionEl,
|
|
26
27
|
getRegionId: () => getRegionId,
|
|
27
28
|
getRootEl: () => getRootEl,
|
|
28
29
|
getRootId: () => getRootId,
|
|
30
|
+
getTitleEl: () => getTitleEl,
|
|
29
31
|
getTitleId: () => getTitleId
|
|
30
32
|
});
|
|
31
33
|
module.exports = __toCommonJS(toast_dom_exports);
|
|
@@ -35,14 +37,18 @@ var getRootId = (ctx) => `toast:${ctx.id}`;
|
|
|
35
37
|
var getRootEl = (ctx) => ctx.getById(getRootId(ctx));
|
|
36
38
|
var getTitleId = (ctx) => `toast:${ctx.id}:title`;
|
|
37
39
|
var getDescriptionId = (ctx) => `toast:${ctx.id}:description`;
|
|
40
|
+
var getTitleEl = (ctx) => ctx.getById(getTitleId(ctx));
|
|
41
|
+
var getDescriptionEl = (ctx) => ctx.getById(getDescriptionId(ctx));
|
|
38
42
|
var getCloseTriggerId = (ctx) => `toast${ctx.id}:close`;
|
|
39
43
|
// Annotate the CommonJS export names for ESM import in node:
|
|
40
44
|
0 && (module.exports = {
|
|
41
45
|
getCloseTriggerId,
|
|
46
|
+
getDescriptionEl,
|
|
42
47
|
getDescriptionId,
|
|
43
48
|
getRegionEl,
|
|
44
49
|
getRegionId,
|
|
45
50
|
getRootEl,
|
|
46
51
|
getRootId,
|
|
52
|
+
getTitleEl,
|
|
47
53
|
getTitleId
|
|
48
54
|
});
|
package/dist/toast.dom.mjs
CHANGED
|
@@ -5,13 +5,17 @@ var getRootId = (ctx) => `toast:${ctx.id}`;
|
|
|
5
5
|
var getRootEl = (ctx) => ctx.getById(getRootId(ctx));
|
|
6
6
|
var getTitleId = (ctx) => `toast:${ctx.id}:title`;
|
|
7
7
|
var getDescriptionId = (ctx) => `toast:${ctx.id}:description`;
|
|
8
|
+
var getTitleEl = (ctx) => ctx.getById(getTitleId(ctx));
|
|
9
|
+
var getDescriptionEl = (ctx) => ctx.getById(getDescriptionId(ctx));
|
|
8
10
|
var getCloseTriggerId = (ctx) => `toast${ctx.id}:close`;
|
|
9
11
|
export {
|
|
10
12
|
getCloseTriggerId,
|
|
13
|
+
getDescriptionEl,
|
|
11
14
|
getDescriptionId,
|
|
12
15
|
getRegionEl,
|
|
13
16
|
getRegionId,
|
|
14
17
|
getRootEl,
|
|
15
18
|
getRootId,
|
|
19
|
+
getTitleEl,
|
|
16
20
|
getTitleId
|
|
17
21
|
};
|
package/dist/toast.machine.js
CHANGED
|
@@ -38,7 +38,7 @@ var import_dom_query = require("@zag-js/dom-query");
|
|
|
38
38
|
var import_utils = require("@zag-js/utils");
|
|
39
39
|
var dom = __toESM(require("./toast.dom.js"));
|
|
40
40
|
var import_toast = require("./toast.utils.js");
|
|
41
|
-
var { not } = (0, import_core.createGuards)();
|
|
41
|
+
var { not, and } = (0, import_core.createGuards)();
|
|
42
42
|
var machine = (0, import_core.createMachine)({
|
|
43
43
|
props({ props }) {
|
|
44
44
|
(0, import_utils.ensureProps)(props, ["id", "type", "parent", "removeDelay"], "toast");
|
|
@@ -49,7 +49,8 @@ var machine = (0, import_core.createMachine)({
|
|
|
49
49
|
};
|
|
50
50
|
},
|
|
51
51
|
initialState({ prop }) {
|
|
52
|
-
|
|
52
|
+
if (prop("message") === "DISMISS") return "dismissing";
|
|
53
|
+
const persist = prop("type") === "loading" || prop("duration") === Infinity || prop("paused");
|
|
53
54
|
return persist ? "visible:persist" : "visible";
|
|
54
55
|
},
|
|
55
56
|
context({ prop, bindable }) {
|
|
@@ -65,6 +66,9 @@ var machine = (0, import_core.createMachine)({
|
|
|
65
66
|
})),
|
|
66
67
|
initialHeight: bindable(() => ({
|
|
67
68
|
defaultValue: 0
|
|
69
|
+
})),
|
|
70
|
+
rendered: bindable(() => ({
|
|
71
|
+
defaultValue: { title: true, description: true }
|
|
68
72
|
}))
|
|
69
73
|
};
|
|
70
74
|
},
|
|
@@ -105,6 +109,9 @@ var machine = (0, import_core.createMachine)({
|
|
|
105
109
|
const message = prop("message");
|
|
106
110
|
if (message) send({ type: message, src: "programmatic" });
|
|
107
111
|
});
|
|
112
|
+
track([() => prop("paused")], () => {
|
|
113
|
+
send({ type: prop("paused") ? "PAUSE" : "RESUME" });
|
|
114
|
+
});
|
|
108
115
|
track([() => prop("type"), () => prop("duration")], () => {
|
|
109
116
|
send({ type: "UPDATE" });
|
|
110
117
|
});
|
|
@@ -112,11 +119,12 @@ var machine = (0, import_core.createMachine)({
|
|
|
112
119
|
on: {
|
|
113
120
|
UPDATE: [
|
|
114
121
|
{
|
|
115
|
-
guard: "
|
|
122
|
+
guard: and("isVisible", "shouldPause"),
|
|
116
123
|
target: "visible:persist",
|
|
117
124
|
actions: ["resetCloseTimer"]
|
|
118
125
|
},
|
|
119
126
|
{
|
|
127
|
+
guard: "isVisible",
|
|
120
128
|
target: "visible:updating",
|
|
121
129
|
actions: ["resetCloseTimer"]
|
|
122
130
|
}
|
|
@@ -126,12 +134,18 @@ var machine = (0, import_core.createMachine)({
|
|
|
126
134
|
}
|
|
127
135
|
},
|
|
128
136
|
entry: ["setMounted", "measureHeight", "invokeOnVisible"],
|
|
129
|
-
effects: ["
|
|
137
|
+
effects: ["trackContent"],
|
|
130
138
|
states: {
|
|
131
139
|
"visible:updating": {
|
|
132
140
|
tags: ["visible", "updating"],
|
|
133
141
|
effects: ["waitForNextTick"],
|
|
134
142
|
on: {
|
|
143
|
+
DISMISS: {
|
|
144
|
+
target: "dismissing"
|
|
145
|
+
},
|
|
146
|
+
PAUSE: {
|
|
147
|
+
target: "visible:persist"
|
|
148
|
+
},
|
|
135
149
|
SHOW: {
|
|
136
150
|
target: "visible"
|
|
137
151
|
}
|
|
@@ -141,7 +155,7 @@ var machine = (0, import_core.createMachine)({
|
|
|
141
155
|
tags: ["visible", "paused"],
|
|
142
156
|
on: {
|
|
143
157
|
RESUME: {
|
|
144
|
-
guard: not("
|
|
158
|
+
guard: not("shouldPause"),
|
|
145
159
|
target: "visible",
|
|
146
160
|
actions: ["setCloseTimer"]
|
|
147
161
|
},
|
|
@@ -195,9 +209,8 @@ var machine = (0, import_core.createMachine)({
|
|
|
195
209
|
send({ type: "SHOW", src: "timer" });
|
|
196
210
|
}, 0);
|
|
197
211
|
},
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
(0, import_dom_query.raf)(() => {
|
|
212
|
+
trackContent({ scope, prop, context }) {
|
|
213
|
+
return (0, import_dom_query.raf)(() => {
|
|
201
214
|
const rootEl = dom.getRootEl(scope);
|
|
202
215
|
if (!rootEl) return;
|
|
203
216
|
const syncHeight = () => {
|
|
@@ -205,21 +218,30 @@ var machine = (0, import_core.createMachine)({
|
|
|
205
218
|
const item = { id: prop("id"), height };
|
|
206
219
|
setHeight(prop("parent"), item);
|
|
207
220
|
};
|
|
221
|
+
const syncRenderedElements = () => {
|
|
222
|
+
context.set("rendered", {
|
|
223
|
+
title: !!dom.getTitleEl(scope),
|
|
224
|
+
description: !!dom.getDescriptionEl(scope)
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
syncRenderedElements();
|
|
208
228
|
const win = scope.getWin();
|
|
209
|
-
const observer = new win.MutationObserver(
|
|
229
|
+
const observer = new win.MutationObserver(() => {
|
|
230
|
+
syncHeight();
|
|
231
|
+
syncRenderedElements();
|
|
232
|
+
});
|
|
210
233
|
observer.observe(rootEl, {
|
|
211
234
|
childList: true,
|
|
212
235
|
subtree: true,
|
|
213
236
|
characterData: true
|
|
214
237
|
});
|
|
215
|
-
|
|
238
|
+
return () => observer.disconnect();
|
|
216
239
|
});
|
|
217
|
-
return () => cleanup?.();
|
|
218
240
|
}
|
|
219
241
|
},
|
|
220
242
|
guards: {
|
|
221
|
-
|
|
222
|
-
|
|
243
|
+
isVisible: ({ state }) => state.hasTag("visible"),
|
|
244
|
+
shouldPause: ({ computed, prop }) => computed("shouldPersist") || !!prop("paused")
|
|
223
245
|
},
|
|
224
246
|
actions: {
|
|
225
247
|
setMounted({ context }) {
|
|
@@ -257,6 +279,7 @@ var machine = (0, import_core.createMachine)({
|
|
|
257
279
|
parent.send({ type: "TOAST.REMOVE", id: prop("id") });
|
|
258
280
|
},
|
|
259
281
|
invokeOnDismiss({ prop, event }) {
|
|
282
|
+
prop("parent").prop("store").dismiss(prop("id"));
|
|
260
283
|
prop("onStatusChange")?.({ status: "dismissing", src: event.src });
|
|
261
284
|
},
|
|
262
285
|
invokeOnUnmount({ prop }) {
|
package/dist/toast.machine.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { raf } from "@zag-js/dom-query";
|
|
|
4
4
|
import { ensureProps, setRafTimeout } from "@zag-js/utils";
|
|
5
5
|
import * as dom from "./toast.dom.mjs";
|
|
6
6
|
import { getToastDuration } from "./toast.utils.mjs";
|
|
7
|
-
var { not } = createGuards();
|
|
7
|
+
var { not, and } = createGuards();
|
|
8
8
|
var machine = createMachine({
|
|
9
9
|
props({ props }) {
|
|
10
10
|
ensureProps(props, ["id", "type", "parent", "removeDelay"], "toast");
|
|
@@ -15,7 +15,8 @@ var machine = createMachine({
|
|
|
15
15
|
};
|
|
16
16
|
},
|
|
17
17
|
initialState({ prop }) {
|
|
18
|
-
|
|
18
|
+
if (prop("message") === "DISMISS") return "dismissing";
|
|
19
|
+
const persist = prop("type") === "loading" || prop("duration") === Infinity || prop("paused");
|
|
19
20
|
return persist ? "visible:persist" : "visible";
|
|
20
21
|
},
|
|
21
22
|
context({ prop, bindable }) {
|
|
@@ -31,6 +32,9 @@ var machine = createMachine({
|
|
|
31
32
|
})),
|
|
32
33
|
initialHeight: bindable(() => ({
|
|
33
34
|
defaultValue: 0
|
|
35
|
+
})),
|
|
36
|
+
rendered: bindable(() => ({
|
|
37
|
+
defaultValue: { title: true, description: true }
|
|
34
38
|
}))
|
|
35
39
|
};
|
|
36
40
|
},
|
|
@@ -71,6 +75,9 @@ var machine = createMachine({
|
|
|
71
75
|
const message = prop("message");
|
|
72
76
|
if (message) send({ type: message, src: "programmatic" });
|
|
73
77
|
});
|
|
78
|
+
track([() => prop("paused")], () => {
|
|
79
|
+
send({ type: prop("paused") ? "PAUSE" : "RESUME" });
|
|
80
|
+
});
|
|
74
81
|
track([() => prop("type"), () => prop("duration")], () => {
|
|
75
82
|
send({ type: "UPDATE" });
|
|
76
83
|
});
|
|
@@ -78,11 +85,12 @@ var machine = createMachine({
|
|
|
78
85
|
on: {
|
|
79
86
|
UPDATE: [
|
|
80
87
|
{
|
|
81
|
-
guard: "
|
|
88
|
+
guard: and("isVisible", "shouldPause"),
|
|
82
89
|
target: "visible:persist",
|
|
83
90
|
actions: ["resetCloseTimer"]
|
|
84
91
|
},
|
|
85
92
|
{
|
|
93
|
+
guard: "isVisible",
|
|
86
94
|
target: "visible:updating",
|
|
87
95
|
actions: ["resetCloseTimer"]
|
|
88
96
|
}
|
|
@@ -92,12 +100,18 @@ var machine = createMachine({
|
|
|
92
100
|
}
|
|
93
101
|
},
|
|
94
102
|
entry: ["setMounted", "measureHeight", "invokeOnVisible"],
|
|
95
|
-
effects: ["
|
|
103
|
+
effects: ["trackContent"],
|
|
96
104
|
states: {
|
|
97
105
|
"visible:updating": {
|
|
98
106
|
tags: ["visible", "updating"],
|
|
99
107
|
effects: ["waitForNextTick"],
|
|
100
108
|
on: {
|
|
109
|
+
DISMISS: {
|
|
110
|
+
target: "dismissing"
|
|
111
|
+
},
|
|
112
|
+
PAUSE: {
|
|
113
|
+
target: "visible:persist"
|
|
114
|
+
},
|
|
101
115
|
SHOW: {
|
|
102
116
|
target: "visible"
|
|
103
117
|
}
|
|
@@ -107,7 +121,7 @@ var machine = createMachine({
|
|
|
107
121
|
tags: ["visible", "paused"],
|
|
108
122
|
on: {
|
|
109
123
|
RESUME: {
|
|
110
|
-
guard: not("
|
|
124
|
+
guard: not("shouldPause"),
|
|
111
125
|
target: "visible",
|
|
112
126
|
actions: ["setCloseTimer"]
|
|
113
127
|
},
|
|
@@ -161,9 +175,8 @@ var machine = createMachine({
|
|
|
161
175
|
send({ type: "SHOW", src: "timer" });
|
|
162
176
|
}, 0);
|
|
163
177
|
},
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
raf(() => {
|
|
178
|
+
trackContent({ scope, prop, context }) {
|
|
179
|
+
return raf(() => {
|
|
167
180
|
const rootEl = dom.getRootEl(scope);
|
|
168
181
|
if (!rootEl) return;
|
|
169
182
|
const syncHeight = () => {
|
|
@@ -171,21 +184,30 @@ var machine = createMachine({
|
|
|
171
184
|
const item = { id: prop("id"), height };
|
|
172
185
|
setHeight(prop("parent"), item);
|
|
173
186
|
};
|
|
187
|
+
const syncRenderedElements = () => {
|
|
188
|
+
context.set("rendered", {
|
|
189
|
+
title: !!dom.getTitleEl(scope),
|
|
190
|
+
description: !!dom.getDescriptionEl(scope)
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
syncRenderedElements();
|
|
174
194
|
const win = scope.getWin();
|
|
175
|
-
const observer = new win.MutationObserver(
|
|
195
|
+
const observer = new win.MutationObserver(() => {
|
|
196
|
+
syncHeight();
|
|
197
|
+
syncRenderedElements();
|
|
198
|
+
});
|
|
176
199
|
observer.observe(rootEl, {
|
|
177
200
|
childList: true,
|
|
178
201
|
subtree: true,
|
|
179
202
|
characterData: true
|
|
180
203
|
});
|
|
181
|
-
|
|
204
|
+
return () => observer.disconnect();
|
|
182
205
|
});
|
|
183
|
-
return () => cleanup?.();
|
|
184
206
|
}
|
|
185
207
|
},
|
|
186
208
|
guards: {
|
|
187
|
-
|
|
188
|
-
|
|
209
|
+
isVisible: ({ state }) => state.hasTag("visible"),
|
|
210
|
+
shouldPause: ({ computed, prop }) => computed("shouldPersist") || !!prop("paused")
|
|
189
211
|
},
|
|
190
212
|
actions: {
|
|
191
213
|
setMounted({ context }) {
|
|
@@ -223,6 +245,7 @@ var machine = createMachine({
|
|
|
223
245
|
parent.send({ type: "TOAST.REMOVE", id: prop("id") });
|
|
224
246
|
},
|
|
225
247
|
invokeOnDismiss({ prop, event }) {
|
|
248
|
+
prop("parent").prop("store").dismiss(prop("id"));
|
|
226
249
|
prop("onStatusChange")?.({ status: "dismissing", src: event.src });
|
|
227
250
|
},
|
|
228
251
|
invokeOnUnmount({ prop }) {
|
package/dist/toast.store.js
CHANGED
|
@@ -36,7 +36,8 @@ var priorities = {
|
|
|
36
36
|
};
|
|
37
37
|
var DEFAULT_TYPE = "info";
|
|
38
38
|
var getPriorityForType = (type, hasAction) => {
|
|
39
|
-
const
|
|
39
|
+
const key = type ?? DEFAULT_TYPE;
|
|
40
|
+
const [actionable, nonActionable] = (0, import_utils.hasProp)(priorities, key) ? priorities[key] : priorities[DEFAULT_TYPE];
|
|
40
41
|
return hasAction ? actionable : nonActionable;
|
|
41
42
|
};
|
|
42
43
|
var sortToastsByPriority = (toastArray) => {
|
|
@@ -61,15 +62,34 @@ function createToastStore(props = {}) {
|
|
|
61
62
|
let toasts = [];
|
|
62
63
|
let dismissedToasts = /* @__PURE__ */ new Set();
|
|
63
64
|
let toastQueue = [];
|
|
65
|
+
const closingToasts = /* @__PURE__ */ new Set();
|
|
66
|
+
const promiseTokens = /* @__PURE__ */ new Map();
|
|
67
|
+
let paused = false;
|
|
64
68
|
const subscribe = (subscriber) => {
|
|
65
69
|
subscribers.push(subscriber);
|
|
70
|
+
let active = true;
|
|
66
71
|
return () => {
|
|
72
|
+
if (!active) return;
|
|
73
|
+
active = false;
|
|
67
74
|
const index = subscribers.indexOf(subscriber);
|
|
68
|
-
subscribers.splice(index, 1);
|
|
75
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
69
76
|
};
|
|
70
77
|
};
|
|
71
|
-
const
|
|
72
|
-
|
|
78
|
+
const notifications = [];
|
|
79
|
+
let publishing = false;
|
|
80
|
+
const publish = (...data) => {
|
|
81
|
+
notifications.push(...data);
|
|
82
|
+
if (publishing) return data;
|
|
83
|
+
publishing = true;
|
|
84
|
+
try {
|
|
85
|
+
while (notifications.length) {
|
|
86
|
+
const next = notifications.shift();
|
|
87
|
+
subscribers.slice().forEach((subscriber) => subscriber(next));
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
publishing = false;
|
|
91
|
+
notifications.length = 0;
|
|
92
|
+
}
|
|
73
93
|
return data;
|
|
74
94
|
};
|
|
75
95
|
const addToast = (data) => {
|
|
@@ -77,30 +97,34 @@ function createToastStore(props = {}) {
|
|
|
77
97
|
toastQueue.push(data);
|
|
78
98
|
return;
|
|
79
99
|
}
|
|
80
|
-
publish(data);
|
|
81
100
|
toasts.unshift(data);
|
|
101
|
+
publish(data);
|
|
82
102
|
};
|
|
83
103
|
const processQueue = () => {
|
|
84
104
|
toastQueue = sortToastsByPriority(toastQueue);
|
|
85
105
|
while (toastQueue.length > 0 && toasts.length < attrs.max) {
|
|
86
106
|
const nextToast = toastQueue.shift();
|
|
87
107
|
if (nextToast) {
|
|
88
|
-
|
|
89
|
-
toasts.unshift(
|
|
108
|
+
const toast = { ...nextToast, paused: paused || nextToast.paused };
|
|
109
|
+
toasts.unshift(toast);
|
|
110
|
+
publish(toast);
|
|
90
111
|
}
|
|
91
112
|
}
|
|
92
113
|
};
|
|
93
114
|
const create = (data) => {
|
|
94
115
|
const id = data.id ?? `toast:${(0, import_utils.uuid)()}`;
|
|
95
|
-
const exists = toasts.find((toast) => toast.id === id);
|
|
96
|
-
if (
|
|
116
|
+
const exists = toasts.find((toast) => toast.id === id) ?? toastQueue.find((toast) => toast.id === id);
|
|
117
|
+
if (closingToasts.has(id)) return id;
|
|
118
|
+
if ((0, import_utils.hasProp)(data, "promise") && data.promise !== exists?.promise) promiseTokens.delete(id);
|
|
119
|
+
dismissedToasts.delete(id);
|
|
97
120
|
if (exists) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
121
|
+
const next = { ...exists, ...data, id };
|
|
122
|
+
if (toasts.some((toast) => toast.id === id)) {
|
|
123
|
+
toasts = toasts.map((toast) => toast.id === id ? next : toast);
|
|
124
|
+
publish(next);
|
|
125
|
+
} else {
|
|
126
|
+
toastQueue = toastQueue.map((toast) => toast.id === id ? next : toast);
|
|
127
|
+
}
|
|
104
128
|
} else {
|
|
105
129
|
const newToast = {
|
|
106
130
|
id,
|
|
@@ -109,7 +133,8 @@ function createToastStore(props = {}) {
|
|
|
109
133
|
type: DEFAULT_TYPE,
|
|
110
134
|
...data,
|
|
111
135
|
stacked: !attrs.overlap,
|
|
112
|
-
gap: attrs.gap
|
|
136
|
+
gap: attrs.gap,
|
|
137
|
+
paused
|
|
113
138
|
};
|
|
114
139
|
const priority = newToast.priority ?? getPriorityForType(newToast.type, !!newToast.action);
|
|
115
140
|
addToast({ ...newToast, priority });
|
|
@@ -117,18 +142,19 @@ function createToastStore(props = {}) {
|
|
|
117
142
|
return id;
|
|
118
143
|
};
|
|
119
144
|
const remove = (id) => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
145
|
+
const removed = id == null ? [...toasts, ...toastQueue] : [...toasts, ...toastQueue].filter((toast) => toast.id === id);
|
|
146
|
+
const visible = id == null ? toasts : toasts.filter((toast) => toast.id === id);
|
|
147
|
+
removed.forEach((toast) => {
|
|
148
|
+
dismissedToasts.add(toast.id);
|
|
149
|
+
closingToasts.delete(toast.id);
|
|
150
|
+
promiseTokens.delete(toast.id);
|
|
151
|
+
});
|
|
152
|
+
if (id != null) dismissedToasts.add(id);
|
|
153
|
+
toasts = id == null ? [] : toasts.filter((toast) => toast.id !== id);
|
|
154
|
+
toastQueue = id == null ? [] : toastQueue.filter((toast) => toast.id !== id);
|
|
155
|
+
if (id != null && !visible.length) publish({ id, dismiss: true });
|
|
156
|
+
publish(...visible.map((toast) => ({ id: toast.id, dismiss: true })));
|
|
157
|
+
processQueue();
|
|
132
158
|
return id;
|
|
133
159
|
};
|
|
134
160
|
const error = (data) => {
|
|
@@ -163,6 +189,10 @@ function createToastStore(props = {}) {
|
|
|
163
189
|
promise: promise2,
|
|
164
190
|
type: "loading"
|
|
165
191
|
});
|
|
192
|
+
const token = /* @__PURE__ */ Symbol();
|
|
193
|
+
const current = toasts.find((toast) => toast.id === id) ?? toastQueue.find((toast) => toast.id === id);
|
|
194
|
+
if (current?.promise === promise2 && !closingToasts.has(id)) promiseTokens.set(id, token);
|
|
195
|
+
const isCurrent = () => promiseTokens.get(id) === token && !closingToasts.has(id);
|
|
166
196
|
let removable = true;
|
|
167
197
|
let result;
|
|
168
198
|
const prom = (0, import_utils.runIfFn)(promise2).then(async (response) => {
|
|
@@ -170,23 +200,24 @@ function createToastStore(props = {}) {
|
|
|
170
200
|
if (isHttpResponse(response) && !response.ok) {
|
|
171
201
|
removable = false;
|
|
172
202
|
const errorOptions = (0, import_utils.runIfFn)(options.error, `HTTP Error! status: ${response.status}`);
|
|
173
|
-
create({ ...shared, ...errorOptions, id, type: "error" });
|
|
203
|
+
if (isCurrent()) create({ ...shared, ...errorOptions, id, type: "error" });
|
|
174
204
|
} else if (options.success !== void 0) {
|
|
175
205
|
removable = false;
|
|
176
206
|
const successOptions = (0, import_utils.runIfFn)(options.success, response);
|
|
177
|
-
create({ ...shared, ...successOptions, id, type: successOptions.type ?? "success" });
|
|
207
|
+
if (isCurrent()) create({ ...shared, ...successOptions, id, type: successOptions.type ?? "success" });
|
|
178
208
|
}
|
|
179
209
|
}).catch(async (error2) => {
|
|
180
210
|
result = ["reject", error2];
|
|
181
211
|
if (options.error !== void 0) {
|
|
182
212
|
removable = false;
|
|
183
213
|
const errorOptions = (0, import_utils.runIfFn)(options.error, error2);
|
|
184
|
-
create({ ...shared, ...errorOptions, id, type: "error" });
|
|
214
|
+
if (isCurrent()) create({ ...shared, ...errorOptions, id, type: "error" });
|
|
185
215
|
}
|
|
186
216
|
}).finally(() => {
|
|
187
|
-
if (removable) {
|
|
217
|
+
if (removable && isCurrent()) {
|
|
188
218
|
remove(id);
|
|
189
219
|
}
|
|
220
|
+
if (promiseTokens.get(id) === token) promiseTokens.delete(id);
|
|
190
221
|
options.finally?.();
|
|
191
222
|
});
|
|
192
223
|
const unwrap = () => new Promise(
|
|
@@ -195,37 +226,46 @@ function createToastStore(props = {}) {
|
|
|
195
226
|
return { id, unwrap };
|
|
196
227
|
};
|
|
197
228
|
const update = (id, data) => {
|
|
198
|
-
|
|
229
|
+
if (closingToasts.has(id)) return id;
|
|
230
|
+
if (typeof data !== "function") return create({ ...data, id });
|
|
231
|
+
const current = toasts.find((toast) => toast.id === id) ?? toastQueue.find((toast) => toast.id === id);
|
|
232
|
+
if (!current) return id;
|
|
233
|
+
const next = { ...data({ ...current }), id };
|
|
234
|
+
if (closingToasts.has(id)) return id;
|
|
235
|
+
if (toasts.some((toast) => toast.id === id)) return create(next);
|
|
236
|
+
if (!toastQueue.some((toast) => toast.id === id)) return id;
|
|
237
|
+
return create(next);
|
|
238
|
+
};
|
|
239
|
+
const changeToasts = (data, id) => {
|
|
240
|
+
const changed = [];
|
|
241
|
+
toasts = toasts.map((toast) => {
|
|
242
|
+
if (id != null && toast.id !== id || closingToasts.has(toast.id)) return toast;
|
|
243
|
+
const next = { ...toast, ...data };
|
|
244
|
+
changed.push(next);
|
|
245
|
+
return next;
|
|
246
|
+
});
|
|
247
|
+
toastQueue = toastQueue.map((toast) => id == null || toast.id === id ? { ...toast, ...data } : toast);
|
|
248
|
+
publish(...changed);
|
|
199
249
|
};
|
|
200
250
|
const pause = (id) => {
|
|
201
|
-
if (id
|
|
202
|
-
|
|
203
|
-
if (toast.id === id) return publish({ ...toast, message: "PAUSE" });
|
|
204
|
-
return toast;
|
|
205
|
-
});
|
|
206
|
-
} else {
|
|
207
|
-
toasts = toasts.map((toast) => publish({ ...toast, message: "PAUSE" }));
|
|
208
|
-
}
|
|
251
|
+
if (id == null) paused = true;
|
|
252
|
+
changeToasts({ paused: true }, id);
|
|
209
253
|
};
|
|
210
254
|
const resume = (id) => {
|
|
211
|
-
if (id
|
|
212
|
-
|
|
213
|
-
if (toast.id === id) return publish({ ...toast, message: "RESUME" });
|
|
214
|
-
return toast;
|
|
215
|
-
});
|
|
216
|
-
} else {
|
|
217
|
-
toasts = toasts.map((toast) => publish({ ...toast, message: "RESUME" }));
|
|
218
|
-
}
|
|
255
|
+
if (id == null) paused = false;
|
|
256
|
+
changeToasts({ paused: false }, id);
|
|
219
257
|
};
|
|
220
258
|
const dismiss = (id) => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
259
|
+
const queued = toastQueue.filter((toast) => id == null || toast.id === id);
|
|
260
|
+
toastQueue = toastQueue.filter((toast) => id != null && toast.id !== id);
|
|
261
|
+
queued.forEach((toast) => {
|
|
262
|
+
dismissedToasts.add(toast.id);
|
|
263
|
+
promiseTokens.delete(toast.id);
|
|
264
|
+
});
|
|
265
|
+
const changed = toasts.filter((toast) => (id == null || toast.id === id) && !closingToasts.has(toast.id));
|
|
266
|
+
changed.forEach((toast) => closingToasts.add(toast.id));
|
|
267
|
+
toasts = toasts.map((toast) => closingToasts.has(toast.id) ? { ...toast, message: "DISMISS" } : toast);
|
|
268
|
+
publish(...changed.map((toast) => ({ ...toast, message: "DISMISS" })));
|
|
229
269
|
};
|
|
230
270
|
const isVisible = (id) => {
|
|
231
271
|
return !dismissedToasts.has(id) && !!toasts.find((toast) => toast.id === id);
|
|
@@ -233,12 +273,8 @@ function createToastStore(props = {}) {
|
|
|
233
273
|
const isDismissed = (id) => {
|
|
234
274
|
return dismissedToasts.has(id);
|
|
235
275
|
};
|
|
236
|
-
const expand = () => {
|
|
237
|
-
|
|
238
|
-
};
|
|
239
|
-
const collapse = () => {
|
|
240
|
-
toasts = toasts.map((toast) => publish({ ...toast, stacked: false }));
|
|
241
|
-
};
|
|
276
|
+
const expand = () => changeToasts({ stacked: true });
|
|
277
|
+
const collapse = () => changeToasts({ stacked: false });
|
|
242
278
|
return {
|
|
243
279
|
attrs,
|
|
244
280
|
subscribe,
|
package/dist/toast.store.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/toast.store.ts
|
|
2
|
-
import { compact, runIfFn, uuid, warn } from "@zag-js/utils";
|
|
2
|
+
import { compact, hasProp, runIfFn, uuid, warn } from "@zag-js/utils";
|
|
3
3
|
var withDefaults = (options, defaults) => {
|
|
4
4
|
return { ...defaults, ...compact(options) };
|
|
5
5
|
};
|
|
@@ -12,7 +12,8 @@ var priorities = {
|
|
|
12
12
|
};
|
|
13
13
|
var DEFAULT_TYPE = "info";
|
|
14
14
|
var getPriorityForType = (type, hasAction) => {
|
|
15
|
-
const
|
|
15
|
+
const key = type ?? DEFAULT_TYPE;
|
|
16
|
+
const [actionable, nonActionable] = hasProp(priorities, key) ? priorities[key] : priorities[DEFAULT_TYPE];
|
|
16
17
|
return hasAction ? actionable : nonActionable;
|
|
17
18
|
};
|
|
18
19
|
var sortToastsByPriority = (toastArray) => {
|
|
@@ -37,15 +38,34 @@ function createToastStore(props = {}) {
|
|
|
37
38
|
let toasts = [];
|
|
38
39
|
let dismissedToasts = /* @__PURE__ */ new Set();
|
|
39
40
|
let toastQueue = [];
|
|
41
|
+
const closingToasts = /* @__PURE__ */ new Set();
|
|
42
|
+
const promiseTokens = /* @__PURE__ */ new Map();
|
|
43
|
+
let paused = false;
|
|
40
44
|
const subscribe = (subscriber) => {
|
|
41
45
|
subscribers.push(subscriber);
|
|
46
|
+
let active = true;
|
|
42
47
|
return () => {
|
|
48
|
+
if (!active) return;
|
|
49
|
+
active = false;
|
|
43
50
|
const index = subscribers.indexOf(subscriber);
|
|
44
|
-
subscribers.splice(index, 1);
|
|
51
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
45
52
|
};
|
|
46
53
|
};
|
|
47
|
-
const
|
|
48
|
-
|
|
54
|
+
const notifications = [];
|
|
55
|
+
let publishing = false;
|
|
56
|
+
const publish = (...data) => {
|
|
57
|
+
notifications.push(...data);
|
|
58
|
+
if (publishing) return data;
|
|
59
|
+
publishing = true;
|
|
60
|
+
try {
|
|
61
|
+
while (notifications.length) {
|
|
62
|
+
const next = notifications.shift();
|
|
63
|
+
subscribers.slice().forEach((subscriber) => subscriber(next));
|
|
64
|
+
}
|
|
65
|
+
} finally {
|
|
66
|
+
publishing = false;
|
|
67
|
+
notifications.length = 0;
|
|
68
|
+
}
|
|
49
69
|
return data;
|
|
50
70
|
};
|
|
51
71
|
const addToast = (data) => {
|
|
@@ -53,30 +73,34 @@ function createToastStore(props = {}) {
|
|
|
53
73
|
toastQueue.push(data);
|
|
54
74
|
return;
|
|
55
75
|
}
|
|
56
|
-
publish(data);
|
|
57
76
|
toasts.unshift(data);
|
|
77
|
+
publish(data);
|
|
58
78
|
};
|
|
59
79
|
const processQueue = () => {
|
|
60
80
|
toastQueue = sortToastsByPriority(toastQueue);
|
|
61
81
|
while (toastQueue.length > 0 && toasts.length < attrs.max) {
|
|
62
82
|
const nextToast = toastQueue.shift();
|
|
63
83
|
if (nextToast) {
|
|
64
|
-
|
|
65
|
-
toasts.unshift(
|
|
84
|
+
const toast = { ...nextToast, paused: paused || nextToast.paused };
|
|
85
|
+
toasts.unshift(toast);
|
|
86
|
+
publish(toast);
|
|
66
87
|
}
|
|
67
88
|
}
|
|
68
89
|
};
|
|
69
90
|
const create = (data) => {
|
|
70
91
|
const id = data.id ?? `toast:${uuid()}`;
|
|
71
|
-
const exists = toasts.find((toast) => toast.id === id);
|
|
72
|
-
if (
|
|
92
|
+
const exists = toasts.find((toast) => toast.id === id) ?? toastQueue.find((toast) => toast.id === id);
|
|
93
|
+
if (closingToasts.has(id)) return id;
|
|
94
|
+
if (hasProp(data, "promise") && data.promise !== exists?.promise) promiseTokens.delete(id);
|
|
95
|
+
dismissedToasts.delete(id);
|
|
73
96
|
if (exists) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
const next = { ...exists, ...data, id };
|
|
98
|
+
if (toasts.some((toast) => toast.id === id)) {
|
|
99
|
+
toasts = toasts.map((toast) => toast.id === id ? next : toast);
|
|
100
|
+
publish(next);
|
|
101
|
+
} else {
|
|
102
|
+
toastQueue = toastQueue.map((toast) => toast.id === id ? next : toast);
|
|
103
|
+
}
|
|
80
104
|
} else {
|
|
81
105
|
const newToast = {
|
|
82
106
|
id,
|
|
@@ -85,7 +109,8 @@ function createToastStore(props = {}) {
|
|
|
85
109
|
type: DEFAULT_TYPE,
|
|
86
110
|
...data,
|
|
87
111
|
stacked: !attrs.overlap,
|
|
88
|
-
gap: attrs.gap
|
|
112
|
+
gap: attrs.gap,
|
|
113
|
+
paused
|
|
89
114
|
};
|
|
90
115
|
const priority = newToast.priority ?? getPriorityForType(newToast.type, !!newToast.action);
|
|
91
116
|
addToast({ ...newToast, priority });
|
|
@@ -93,18 +118,19 @@ function createToastStore(props = {}) {
|
|
|
93
118
|
return id;
|
|
94
119
|
};
|
|
95
120
|
const remove = (id) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
121
|
+
const removed = id == null ? [...toasts, ...toastQueue] : [...toasts, ...toastQueue].filter((toast) => toast.id === id);
|
|
122
|
+
const visible = id == null ? toasts : toasts.filter((toast) => toast.id === id);
|
|
123
|
+
removed.forEach((toast) => {
|
|
124
|
+
dismissedToasts.add(toast.id);
|
|
125
|
+
closingToasts.delete(toast.id);
|
|
126
|
+
promiseTokens.delete(toast.id);
|
|
127
|
+
});
|
|
128
|
+
if (id != null) dismissedToasts.add(id);
|
|
129
|
+
toasts = id == null ? [] : toasts.filter((toast) => toast.id !== id);
|
|
130
|
+
toastQueue = id == null ? [] : toastQueue.filter((toast) => toast.id !== id);
|
|
131
|
+
if (id != null && !visible.length) publish({ id, dismiss: true });
|
|
132
|
+
publish(...visible.map((toast) => ({ id: toast.id, dismiss: true })));
|
|
133
|
+
processQueue();
|
|
108
134
|
return id;
|
|
109
135
|
};
|
|
110
136
|
const error = (data) => {
|
|
@@ -139,6 +165,10 @@ function createToastStore(props = {}) {
|
|
|
139
165
|
promise: promise2,
|
|
140
166
|
type: "loading"
|
|
141
167
|
});
|
|
168
|
+
const token = /* @__PURE__ */ Symbol();
|
|
169
|
+
const current = toasts.find((toast) => toast.id === id) ?? toastQueue.find((toast) => toast.id === id);
|
|
170
|
+
if (current?.promise === promise2 && !closingToasts.has(id)) promiseTokens.set(id, token);
|
|
171
|
+
const isCurrent = () => promiseTokens.get(id) === token && !closingToasts.has(id);
|
|
142
172
|
let removable = true;
|
|
143
173
|
let result;
|
|
144
174
|
const prom = runIfFn(promise2).then(async (response) => {
|
|
@@ -146,23 +176,24 @@ function createToastStore(props = {}) {
|
|
|
146
176
|
if (isHttpResponse(response) && !response.ok) {
|
|
147
177
|
removable = false;
|
|
148
178
|
const errorOptions = runIfFn(options.error, `HTTP Error! status: ${response.status}`);
|
|
149
|
-
create({ ...shared, ...errorOptions, id, type: "error" });
|
|
179
|
+
if (isCurrent()) create({ ...shared, ...errorOptions, id, type: "error" });
|
|
150
180
|
} else if (options.success !== void 0) {
|
|
151
181
|
removable = false;
|
|
152
182
|
const successOptions = runIfFn(options.success, response);
|
|
153
|
-
create({ ...shared, ...successOptions, id, type: successOptions.type ?? "success" });
|
|
183
|
+
if (isCurrent()) create({ ...shared, ...successOptions, id, type: successOptions.type ?? "success" });
|
|
154
184
|
}
|
|
155
185
|
}).catch(async (error2) => {
|
|
156
186
|
result = ["reject", error2];
|
|
157
187
|
if (options.error !== void 0) {
|
|
158
188
|
removable = false;
|
|
159
189
|
const errorOptions = runIfFn(options.error, error2);
|
|
160
|
-
create({ ...shared, ...errorOptions, id, type: "error" });
|
|
190
|
+
if (isCurrent()) create({ ...shared, ...errorOptions, id, type: "error" });
|
|
161
191
|
}
|
|
162
192
|
}).finally(() => {
|
|
163
|
-
if (removable) {
|
|
193
|
+
if (removable && isCurrent()) {
|
|
164
194
|
remove(id);
|
|
165
195
|
}
|
|
196
|
+
if (promiseTokens.get(id) === token) promiseTokens.delete(id);
|
|
166
197
|
options.finally?.();
|
|
167
198
|
});
|
|
168
199
|
const unwrap = () => new Promise(
|
|
@@ -171,37 +202,46 @@ function createToastStore(props = {}) {
|
|
|
171
202
|
return { id, unwrap };
|
|
172
203
|
};
|
|
173
204
|
const update = (id, data) => {
|
|
174
|
-
|
|
205
|
+
if (closingToasts.has(id)) return id;
|
|
206
|
+
if (typeof data !== "function") return create({ ...data, id });
|
|
207
|
+
const current = toasts.find((toast) => toast.id === id) ?? toastQueue.find((toast) => toast.id === id);
|
|
208
|
+
if (!current) return id;
|
|
209
|
+
const next = { ...data({ ...current }), id };
|
|
210
|
+
if (closingToasts.has(id)) return id;
|
|
211
|
+
if (toasts.some((toast) => toast.id === id)) return create(next);
|
|
212
|
+
if (!toastQueue.some((toast) => toast.id === id)) return id;
|
|
213
|
+
return create(next);
|
|
214
|
+
};
|
|
215
|
+
const changeToasts = (data, id) => {
|
|
216
|
+
const changed = [];
|
|
217
|
+
toasts = toasts.map((toast) => {
|
|
218
|
+
if (id != null && toast.id !== id || closingToasts.has(toast.id)) return toast;
|
|
219
|
+
const next = { ...toast, ...data };
|
|
220
|
+
changed.push(next);
|
|
221
|
+
return next;
|
|
222
|
+
});
|
|
223
|
+
toastQueue = toastQueue.map((toast) => id == null || toast.id === id ? { ...toast, ...data } : toast);
|
|
224
|
+
publish(...changed);
|
|
175
225
|
};
|
|
176
226
|
const pause = (id) => {
|
|
177
|
-
if (id
|
|
178
|
-
|
|
179
|
-
if (toast.id === id) return publish({ ...toast, message: "PAUSE" });
|
|
180
|
-
return toast;
|
|
181
|
-
});
|
|
182
|
-
} else {
|
|
183
|
-
toasts = toasts.map((toast) => publish({ ...toast, message: "PAUSE" }));
|
|
184
|
-
}
|
|
227
|
+
if (id == null) paused = true;
|
|
228
|
+
changeToasts({ paused: true }, id);
|
|
185
229
|
};
|
|
186
230
|
const resume = (id) => {
|
|
187
|
-
if (id
|
|
188
|
-
|
|
189
|
-
if (toast.id === id) return publish({ ...toast, message: "RESUME" });
|
|
190
|
-
return toast;
|
|
191
|
-
});
|
|
192
|
-
} else {
|
|
193
|
-
toasts = toasts.map((toast) => publish({ ...toast, message: "RESUME" }));
|
|
194
|
-
}
|
|
231
|
+
if (id == null) paused = false;
|
|
232
|
+
changeToasts({ paused: false }, id);
|
|
195
233
|
};
|
|
196
234
|
const dismiss = (id) => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
235
|
+
const queued = toastQueue.filter((toast) => id == null || toast.id === id);
|
|
236
|
+
toastQueue = toastQueue.filter((toast) => id != null && toast.id !== id);
|
|
237
|
+
queued.forEach((toast) => {
|
|
238
|
+
dismissedToasts.add(toast.id);
|
|
239
|
+
promiseTokens.delete(toast.id);
|
|
240
|
+
});
|
|
241
|
+
const changed = toasts.filter((toast) => (id == null || toast.id === id) && !closingToasts.has(toast.id));
|
|
242
|
+
changed.forEach((toast) => closingToasts.add(toast.id));
|
|
243
|
+
toasts = toasts.map((toast) => closingToasts.has(toast.id) ? { ...toast, message: "DISMISS" } : toast);
|
|
244
|
+
publish(...changed.map((toast) => ({ ...toast, message: "DISMISS" })));
|
|
205
245
|
};
|
|
206
246
|
const isVisible = (id) => {
|
|
207
247
|
return !dismissedToasts.has(id) && !!toasts.find((toast) => toast.id === id);
|
|
@@ -209,12 +249,8 @@ function createToastStore(props = {}) {
|
|
|
209
249
|
const isDismissed = (id) => {
|
|
210
250
|
return dismissedToasts.has(id);
|
|
211
251
|
};
|
|
212
|
-
const expand = () => {
|
|
213
|
-
|
|
214
|
-
};
|
|
215
|
-
const collapse = () => {
|
|
216
|
-
toasts = toasts.map((toast) => publish({ ...toast, stacked: false }));
|
|
217
|
-
};
|
|
252
|
+
const expand = () => changeToasts({ stacked: true });
|
|
253
|
+
const collapse = () => changeToasts({ stacked: false });
|
|
218
254
|
return {
|
|
219
255
|
attrs,
|
|
220
256
|
subscribe,
|
package/dist/toast.types.d.mts
CHANGED
|
@@ -115,6 +115,10 @@ type ToastSchema<O = any> = {
|
|
|
115
115
|
mounted: boolean;
|
|
116
116
|
initialHeight: number;
|
|
117
117
|
remainingTime: number;
|
|
118
|
+
rendered: {
|
|
119
|
+
title: boolean;
|
|
120
|
+
description: boolean;
|
|
121
|
+
};
|
|
118
122
|
};
|
|
119
123
|
computed: {
|
|
120
124
|
height: number;
|
|
@@ -181,7 +185,7 @@ interface ToastStoreProps {
|
|
|
181
185
|
removeDelay?: number | undefined;
|
|
182
186
|
/**
|
|
183
187
|
* Whether to pause toast when the user leaves the browser tab
|
|
184
|
-
* @default
|
|
188
|
+
* @default true
|
|
185
189
|
*/
|
|
186
190
|
pauseOnPageIdle?: boolean | undefined;
|
|
187
191
|
}
|
|
@@ -227,13 +231,16 @@ interface ToastStore<V = any> {
|
|
|
227
231
|
*/
|
|
228
232
|
subscribe: (subscriber: (...args: any[]) => void) => VoidFunction;
|
|
229
233
|
/**
|
|
230
|
-
* Create a
|
|
234
|
+
* Create a toast or update an existing toast with the same ID.
|
|
235
|
+
* Calls targeting closing toasts are ignored.
|
|
231
236
|
*/
|
|
232
237
|
create: (data: Options<V>) => string;
|
|
233
238
|
/**
|
|
234
|
-
* Update
|
|
239
|
+
* Update a toast with new properties or a function of its current properties.
|
|
240
|
+
* Updates to closing toasts are ignored.
|
|
241
|
+
* Functional updates are also ignored when the toast does not exist.
|
|
235
242
|
*/
|
|
236
|
-
update: (id: string, data: Partial<ToastProps<V
|
|
243
|
+
update: (id: string, data: MaybeFunction<Partial<ToastProps<V>>, Partial<ToastProps<V>>>) => string;
|
|
237
244
|
/**
|
|
238
245
|
* Remove a toast by its ID
|
|
239
246
|
*/
|
package/dist/toast.types.d.ts
CHANGED
|
@@ -115,6 +115,10 @@ type ToastSchema<O = any> = {
|
|
|
115
115
|
mounted: boolean;
|
|
116
116
|
initialHeight: number;
|
|
117
117
|
remainingTime: number;
|
|
118
|
+
rendered: {
|
|
119
|
+
title: boolean;
|
|
120
|
+
description: boolean;
|
|
121
|
+
};
|
|
118
122
|
};
|
|
119
123
|
computed: {
|
|
120
124
|
height: number;
|
|
@@ -181,7 +185,7 @@ interface ToastStoreProps {
|
|
|
181
185
|
removeDelay?: number | undefined;
|
|
182
186
|
/**
|
|
183
187
|
* Whether to pause toast when the user leaves the browser tab
|
|
184
|
-
* @default
|
|
188
|
+
* @default true
|
|
185
189
|
*/
|
|
186
190
|
pauseOnPageIdle?: boolean | undefined;
|
|
187
191
|
}
|
|
@@ -227,13 +231,16 @@ interface ToastStore<V = any> {
|
|
|
227
231
|
*/
|
|
228
232
|
subscribe: (subscriber: (...args: any[]) => void) => VoidFunction;
|
|
229
233
|
/**
|
|
230
|
-
* Create a
|
|
234
|
+
* Create a toast or update an existing toast with the same ID.
|
|
235
|
+
* Calls targeting closing toasts are ignored.
|
|
231
236
|
*/
|
|
232
237
|
create: (data: Options<V>) => string;
|
|
233
238
|
/**
|
|
234
|
-
* Update
|
|
239
|
+
* Update a toast with new properties or a function of its current properties.
|
|
240
|
+
* Updates to closing toasts are ignored.
|
|
241
|
+
* Functional updates are also ignored when the toast does not exist.
|
|
235
242
|
*/
|
|
236
|
-
update: (id: string, data: Partial<ToastProps<V
|
|
243
|
+
update: (id: string, data: MaybeFunction<Partial<ToastProps<V>>, Partial<ToastProps<V>>>) => string;
|
|
237
244
|
/**
|
|
238
245
|
* Remove a toast by its ID
|
|
239
246
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/toast",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.46.0",
|
|
4
4
|
"description": "Core logic for the toast widget implemented as a state machine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"url": "https://github.com/chakra-ui/zag/issues"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@zag-js/anatomy": "1.
|
|
33
|
-
"@zag-js/core": "1.
|
|
34
|
-
"@zag-js/dom-query": "1.
|
|
35
|
-
"@zag-js/dismissable": "1.
|
|
36
|
-
"@zag-js/utils": "1.
|
|
37
|
-
"@zag-js/types": "1.
|
|
32
|
+
"@zag-js/anatomy": "1.46.0",
|
|
33
|
+
"@zag-js/core": "1.46.0",
|
|
34
|
+
"@zag-js/dom-query": "1.46.0",
|
|
35
|
+
"@zag-js/dismissable": "1.46.0",
|
|
36
|
+
"@zag-js/utils": "1.46.0",
|
|
37
|
+
"@zag-js/types": "1.46.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"clean-package": "2.2.0"
|