@fluixi-ui/toast 0.2.0-alpha.18 → 0.2.0-alpha.20

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.js CHANGED
@@ -1,390 +1,532 @@
1
- import { delegateEvents, splitProps, createComponent, createNativeElement, spread, mergeProps, insert, templateNode, holeEnd, holeScope, holeContent, handleRef } from "@fluixi/dom";
2
- import { createSignal, onCleanup, createEffect, createMemo } from "@fluixi/reactive/signal";
1
+ import { createComponent, createNativeElement, delegateEvents, handleRef, holeContent, holeEnd, holeScope, insert, mergeProps, splitProps, spread, templateNode } from "@fluixi/dom";
2
+ import { createEffect, createMemo, createSignal, onCleanup } from "@fluixi/reactive/signal";
3
3
  import { fxProps } from "@fluixi-ui/fx";
4
- import { onMount, useRef, Show, For } from "@fluixi/core";
5
- import { createSafeContext, composeEventHandlers, createId } from "@fluixi-ui/kit";
4
+ import { For, Show, onMount, useRef } from "@fluixi/core";
5
+ import { composeEventHandlers, createId, createSafeContext } from "@fluixi-ui/kit";
6
6
  import { Portal } from "@fluixi-ui/primitives";
7
- const _fxTmpl$0 = '<div data-toast-content=""><!--fx--><!--fx/--><!--fx--><!--fx/--></div>';
7
+ //#region src/toast.tsx
8
+ var _fxTmpl$0 = "<div data-toast-content=\"\"><!--fx--><!--fx/--><!--fx--><!--fx/--></div>";
8
9
  delegateEvents(["click", "keydown"]);
9
- const PLACEMENTS = [
10
- "top-left",
11
- "top-center",
12
- "top-right",
13
- "bottom-left",
14
- "bottom-center",
15
- "bottom-right"
10
+ var PLACEMENTS = [
11
+ "top-left",
12
+ "top-center",
13
+ "top-right",
14
+ "bottom-left",
15
+ "bottom-center",
16
+ "bottom-right"
16
17
  ];
18
+ /**
19
+ * Create an isolated toast store: the reactive engine behind a region. Owns the
20
+ * toast list and per-toast auto-dismiss timers (pausable for hover). Most apps
21
+ * use the default {@link toast} singleton; create a store for scoped or testable
22
+ * setups.
23
+ */
17
24
  function createToastStore(config = {}) {
18
- const [toasts, setToasts] = createSignal([]);
19
- const timers = /* @__PURE__ */ new Map();
20
- const defaultDuration = config.duration ?? 4e3;
21
- const defaultPlacement = config.defaultPlacement ?? "bottom-right";
22
- const maxVisible = config.maxVisible ?? 3;
23
- const clearTimer = (id) => {
24
- const timer = timers.get(id);
25
- if (timer?.handle) clearTimeout(timer.handle);
26
- };
27
- const schedule = (id, ms) => {
28
- if (!Number.isFinite(ms) || ms <= 0) return;
29
- const timer = { handle: void 0, remaining: ms, startedAt: Date.now() };
30
- timer.handle = setTimeout(() => dismiss(id), ms);
31
- timers.set(id, timer);
32
- };
33
- const dismiss = (id) => {
34
- clearTimer(id);
35
- timers.delete(id);
36
- const record = toasts().find((toast2) => toast2.id === id);
37
- setToasts((list) => list.filter((toast2) => toast2.id !== id));
38
- record?.onDismiss?.(record);
39
- };
40
- const add = (options) => {
41
- const id = createId("toast");
42
- const type = options.type ?? "default";
43
- const duration = options.duration ?? (type === "loading" ? 0 : defaultDuration);
44
- const record = {
45
- ...options,
46
- id,
47
- type,
48
- placement: options.placement ?? defaultPlacement,
49
- duration,
50
- dismissible: options.dismissible ?? true,
51
- createdAt: Date.now()
52
- };
53
- setToasts((list) => [...list, record]);
54
- schedule(id, duration);
55
- return id;
56
- };
57
- const update = (id, options) => {
58
- let next;
59
- setToasts(
60
- (list) => list.map((toast2) => {
61
- if (toast2.id !== id) return toast2;
62
- next = { ...toast2, ...options, id: toast2.id, createdAt: toast2.createdAt };
63
- return next;
64
- })
65
- );
66
- if (!next) return;
67
- clearTimer(id);
68
- timers.delete(id);
69
- schedule(id, next.duration);
70
- };
71
- const pause = () => {
72
- const now = Date.now();
73
- for (const timer of timers.values()) {
74
- if (!timer.handle) continue;
75
- clearTimeout(timer.handle);
76
- timer.remaining -= now - timer.startedAt;
77
- timer.handle = void 0;
78
- }
79
- };
80
- const resume = () => {
81
- const now = Date.now();
82
- for (const [id, timer] of timers) {
83
- if (timer.handle) continue;
84
- timer.startedAt = now;
85
- timer.handle = setTimeout(() => dismiss(id), Math.max(0, timer.remaining));
86
- }
87
- };
88
- const clear = () => {
89
- for (const id of timers.keys()) clearTimer(id);
90
- timers.clear();
91
- setToasts([]);
92
- };
93
- const promise = (p, messages, options = {}) => {
94
- const id = add({ ...options, type: "loading", title: messages.loading, duration: 0 });
95
- const resolveMessage = (message, value) => typeof message === "function" ? message(value) : message;
96
- p.then(
97
- (value) => update(id, {
98
- type: "success",
99
- title: resolveMessage(messages.success, value),
100
- duration: options.duration ?? defaultDuration
101
- }),
102
- (reason) => update(id, {
103
- type: "error",
104
- title: resolveMessage(messages.error, reason),
105
- duration: options.duration ?? defaultDuration
106
- })
107
- );
108
- return p;
109
- };
110
- return { toasts, add, update, dismiss, clear, promise, pause, resume, maxVisible };
25
+ const [toasts, setToasts] = createSignal([]);
26
+ const timers = /* @__PURE__ */ new Map();
27
+ const defaultDuration = config.duration ?? 4e3;
28
+ const defaultPlacement = config.defaultPlacement ?? "bottom-right";
29
+ const maxVisible = config.maxVisible ?? 3;
30
+ const clearTimer = (id) => {
31
+ const timer = timers.get(id);
32
+ if (timer?.handle) clearTimeout(timer.handle);
33
+ };
34
+ const schedule = (id, ms) => {
35
+ if (!Number.isFinite(ms) || ms <= 0) return;
36
+ const timer = {
37
+ handle: void 0,
38
+ remaining: ms,
39
+ startedAt: Date.now()
40
+ };
41
+ timer.handle = setTimeout(() => dismiss(id), ms);
42
+ timers.set(id, timer);
43
+ };
44
+ const dismiss = (id) => {
45
+ clearTimer(id);
46
+ timers.delete(id);
47
+ const record = toasts().find((toast) => toast.id === id);
48
+ setToasts((list) => list.filter((toast) => toast.id !== id));
49
+ record?.onDismiss?.(record);
50
+ };
51
+ const add = (options) => {
52
+ const id = createId("toast");
53
+ const type = options.type ?? "default";
54
+ const duration = options.duration ?? (type === "loading" ? 0 : defaultDuration);
55
+ const record = {
56
+ ...options,
57
+ id,
58
+ type,
59
+ placement: options.placement ?? defaultPlacement,
60
+ duration,
61
+ dismissible: options.dismissible ?? true,
62
+ createdAt: Date.now()
63
+ };
64
+ setToasts((list) => [...list, record]);
65
+ schedule(id, duration);
66
+ return id;
67
+ };
68
+ const update = (id, options) => {
69
+ let next;
70
+ setToasts((list) => list.map((toast) => {
71
+ if (toast.id !== id) return toast;
72
+ next = {
73
+ ...toast,
74
+ ...options,
75
+ id: toast.id,
76
+ createdAt: toast.createdAt
77
+ };
78
+ return next;
79
+ }));
80
+ if (!next) return;
81
+ clearTimer(id);
82
+ timers.delete(id);
83
+ schedule(id, next.duration);
84
+ };
85
+ const pause = () => {
86
+ const now = Date.now();
87
+ for (const timer of timers.values()) {
88
+ if (!timer.handle) continue;
89
+ clearTimeout(timer.handle);
90
+ timer.remaining -= now - timer.startedAt;
91
+ timer.handle = void 0;
92
+ }
93
+ };
94
+ const resume = () => {
95
+ const now = Date.now();
96
+ for (const [id, timer] of timers) {
97
+ if (timer.handle) continue;
98
+ timer.startedAt = now;
99
+ timer.handle = setTimeout(() => dismiss(id), Math.max(0, timer.remaining));
100
+ }
101
+ };
102
+ const clear = () => {
103
+ for (const id of timers.keys()) clearTimer(id);
104
+ timers.clear();
105
+ setToasts([]);
106
+ };
107
+ const promise = (p, messages, options = {}) => {
108
+ const id = add({
109
+ ...options,
110
+ type: "loading",
111
+ title: messages.loading,
112
+ duration: 0
113
+ });
114
+ const resolveMessage = (message, value) => typeof message === "function" ? message(value) : message;
115
+ p.then((value) => update(id, {
116
+ type: "success",
117
+ title: resolveMessage(messages.success, value),
118
+ duration: options.duration ?? defaultDuration
119
+ }), (reason) => update(id, {
120
+ type: "error",
121
+ title: resolveMessage(messages.error, reason),
122
+ duration: options.duration ?? defaultDuration
123
+ }));
124
+ return p;
125
+ };
126
+ return {
127
+ toasts,
128
+ add,
129
+ update,
130
+ dismiss,
131
+ clear,
132
+ promise,
133
+ pause,
134
+ resume,
135
+ maxVisible
136
+ };
111
137
  }
112
- const defaultStore = createToastStore();
138
+ var defaultStore = createToastStore();
113
139
  function shortcut(type) {
114
- return (message, options = {}) => defaultStore.add({ ...options, title: message, type });
140
+ return (message, options = {}) => defaultStore.add({
141
+ ...options,
142
+ title: message,
143
+ type
144
+ });
115
145
  }
116
- const toast = Object.assign(
117
- (options) => defaultStore.add(options),
118
- {
119
- success: shortcut("success"),
120
- error: shortcut("error"),
121
- warning: shortcut("warning"),
122
- info: shortcut("info"),
123
- loading: shortcut("loading"),
124
- promise: defaultStore.promise,
125
- update: defaultStore.update,
126
- dismiss: defaultStore.dismiss,
127
- clear: defaultStore.clear,
128
- store: defaultStore
129
- }
130
- );
131
- const [ToastProvider, useToastContext] = createSafeContext("Toast");
146
+ /**
147
+ * The default toast API — fire a notification from anywhere.
148
+ *
149
+ * @example
150
+ * ```tsx
151
+ * import { toast, Toaster } from '@fluixi-ui/toast';
152
+ *
153
+ * // once, near the app root:
154
+ * <Toaster />
155
+ *
156
+ * // anywhere:
157
+ * toast.success('Saved');
158
+ * toast.error('Upload failed', { placement: 'top-center' });
159
+ * const id = toast.loading('Uploading…');
160
+ * toast.update(id, { type: 'success', title: 'Uploaded', duration: 4000 });
161
+ * ```
162
+ */
163
+ var toast = Object.assign((options) => defaultStore.add(options), {
164
+ success: shortcut("success"),
165
+ error: shortcut("error"),
166
+ warning: shortcut("warning"),
167
+ info: shortcut("info"),
168
+ loading: shortcut("loading"),
169
+ promise: defaultStore.promise,
170
+ update: defaultStore.update,
171
+ dismiss: defaultStore.dismiss,
172
+ clear: defaultStore.clear,
173
+ store: defaultStore
174
+ });
175
+ var [ToastProvider, useToastContext] = createSafeContext("Toast");
176
+ /**
177
+ * Renders a store's toasts into fixed corner stacks (one per placement in use).
178
+ * Mount once near the app root. Hovering a stack pauses its auto-dismiss timers.
179
+ */
132
180
  function Toaster(props) {
133
- const [local, others] = splitProps(props, ["store", "label", "fx", "style"]);
134
- const store = local.store ?? defaultStore;
135
- const byPlacement = (placement) => (
136
- // Newest last; keep only the most recent `maxVisible` in view.
137
- store.toasts().filter((toast2) => toast2.placement === placement).slice(-store.maxVisible)
138
- );
139
- onMount(() => {
140
- const onKeyDown = (event) => {
141
- if (event.key !== "F6") return;
142
- const first = document.querySelector("[data-toast]");
143
- if (first) {
144
- event.preventDefault();
145
- first.focus();
146
- }
147
- };
148
- document.addEventListener("keydown", onKeyDown);
149
- onCleanup(() => document.removeEventListener("keydown", onKeyDown));
150
- });
151
- const onRegionKeyDown = (event) => {
152
- const active = document.activeElement;
153
- const region = active?.closest("[data-toast-viewport]");
154
- if (!region) return;
155
- const items = [...region.querySelectorAll("[data-toast]")];
156
- const index = items.indexOf(active);
157
- if (index === -1) return;
158
- if (event.key === "ArrowDown" || event.key === "ArrowUp") {
159
- event.preventDefault();
160
- const step = event.key === "ArrowDown" ? 1 : -1;
161
- items[Math.min(Math.max(index + step, 0), items.length - 1)]?.focus();
162
- } else if (event.key === "Escape") {
163
- event.preventDefault();
164
- const record = byPlacement(region.dataset.placement)[index];
165
- if (record) store.dismiss(record.id);
166
- const remaining = region.querySelectorAll("[data-toast]");
167
- remaining[Math.min(index, remaining.length - 1)]?.focus();
168
- }
169
- };
170
- const ref = useRef(null);
171
- createEffect(() => {
172
- if (store.toasts().length === 0 && ref.current) {
173
- ref.current.remove();
174
- }
175
- });
176
- return createMemo(() => createComponent(Show, { get when() {
177
- return store.toasts().length > 0;
178
- }, get fallback() {
179
- return null;
180
- }, get children() {
181
- return createMemo(() => createComponent(Portal, { get ref() {
182
- return ref;
183
- }, get children() {
184
- return createMemo(() => createComponent(For, { get each() {
185
- return () => PLACEMENTS;
186
- }, get children() {
187
- return (placement) => createMemo(() => createComponent(Show, { get when() {
188
- return () => byPlacement(placement).length > 0;
189
- }, get children() {
190
- return (() => {
191
- const _el$ = createNativeElement("ol");
192
- spread({ element: _el$, props: mergeProps(fxProps(
193
- () => local.fx,
194
- () => local.style
195
- ), others, { "data-toast-viewport": "", "data-placement": placement, role: "region", "aria-label": () => local.label ?? "Notifications", tabindex: -1, onPointerEnter: () => store.pause(), onPointerLeave: () => store.resume(), onKeyDown: onRegionKeyDown }) });
196
- insert(_el$, createMemo(() => createComponent(For, { get each() {
197
- return () => byPlacement(placement);
198
- }, get by() {
199
- return (record) => record.id;
200
- }, get children() {
201
- return (record) => createMemo(() => createComponent(ToastItem, { get record() {
202
- return record;
203
- }, get store() {
204
- return store;
205
- } }));
206
- } })), null);
207
- return _el$;
208
- })();
209
- } }));
210
- } }));
211
- } }));
212
- } }));
181
+ const [local, others] = splitProps(props, [
182
+ "store",
183
+ "label",
184
+ "fx",
185
+ "style"
186
+ ]);
187
+ const store = local.store ?? defaultStore;
188
+ const byPlacement = (placement) => store.toasts().filter((toast) => toast.placement === placement).slice(-store.maxVisible);
189
+ onMount(() => {
190
+ const onKeyDown = (event) => {
191
+ if (event.key !== "F6") return;
192
+ const first = document.querySelector("[data-toast]");
193
+ if (first) {
194
+ event.preventDefault();
195
+ first.focus();
196
+ }
197
+ };
198
+ document.addEventListener("keydown", onKeyDown);
199
+ onCleanup(() => document.removeEventListener("keydown", onKeyDown));
200
+ });
201
+ const onRegionKeyDown = (event) => {
202
+ const active = document.activeElement;
203
+ const region = active?.closest("[data-toast-viewport]");
204
+ if (!region) return;
205
+ const items = [...region.querySelectorAll("[data-toast]")];
206
+ const index = items.indexOf(active);
207
+ if (index === -1) return;
208
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
209
+ event.preventDefault();
210
+ const step = event.key === "ArrowDown" ? 1 : -1;
211
+ items[Math.min(Math.max(index + step, 0), items.length - 1)]?.focus();
212
+ } else if (event.key === "Escape") {
213
+ event.preventDefault();
214
+ const record = byPlacement(region.dataset.placement)[index];
215
+ if (record) store.dismiss(record.id);
216
+ const remaining = region.querySelectorAll("[data-toast]");
217
+ remaining[Math.min(index, remaining.length - 1)]?.focus();
218
+ }
219
+ };
220
+ const ref = useRef(null);
221
+ createEffect(() => {
222
+ if (store.toasts().length === 0 && ref.current) ref.current.remove();
223
+ });
224
+ return createMemo(() => createComponent(Show, {
225
+ get when() {
226
+ return store.toasts().length > 0;
227
+ },
228
+ get fallback() {
229
+ return null;
230
+ },
231
+ get children() {
232
+ return createMemo(() => createComponent(Portal, {
233
+ get ref() {
234
+ return ref;
235
+ },
236
+ get children() {
237
+ return createMemo(() => createComponent(For, {
238
+ get each() {
239
+ return () => PLACEMENTS;
240
+ },
241
+ get children() {
242
+ return (placement) => createMemo(() => createComponent(Show, {
243
+ get when() {
244
+ return () => byPlacement(placement).length > 0;
245
+ },
246
+ get children() {
247
+ return (() => {
248
+ const _el$ = createNativeElement("ol");
249
+ spread({
250
+ element: _el$,
251
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
252
+ "data-toast-viewport": "",
253
+ "data-placement": placement,
254
+ role: "region",
255
+ "aria-label": () => local.label ?? "Notifications",
256
+ tabindex: -1,
257
+ onPointerEnter: () => store.pause(),
258
+ onPointerLeave: () => store.resume(),
259
+ onKeyDown: onRegionKeyDown
260
+ })
261
+ });
262
+ insert(_el$, createMemo(() => createComponent(For, {
263
+ get each() {
264
+ return () => byPlacement(placement);
265
+ },
266
+ get by() {
267
+ return (record) => record.id;
268
+ },
269
+ get children() {
270
+ return (record) => createMemo(() => createComponent(ToastItem, {
271
+ get record() {
272
+ return record;
273
+ },
274
+ get store() {
275
+ return store;
276
+ }
277
+ }));
278
+ }
279
+ })), null);
280
+ return _el$;
281
+ })();
282
+ }
283
+ }));
284
+ }
285
+ }));
286
+ }
287
+ }));
288
+ }
289
+ }));
213
290
  }
291
+ /** One rendered toast: establishes context, then renders {@link Toast}. */
214
292
  function ToastItem(props) {
215
- return createMemo(() => createComponent(ToastProvider, { get value() {
216
- return { record: props.record, dismiss: () => props.store.dismiss(props.record().id) };
217
- }, get children() {
218
- return createMemo(() => createComponent(Toast, {}));
219
- } }));
293
+ return createMemo(() => createComponent(ToastProvider, {
294
+ get value() {
295
+ return {
296
+ record: props.record,
297
+ dismiss: () => props.store.dismiss(props.record().id)
298
+ };
299
+ },
300
+ get children() {
301
+ return createMemo(() => createComponent(Toast, {}));
302
+ }
303
+ }));
220
304
  }
305
+ /**
306
+ * A single toast. Body resolution: explicit `children`, else the record's custom
307
+ * `render`, else the default title/description/close.
308
+ */
221
309
  function Toast(props) {
222
- const ctx = useToastContext();
223
- const [local, others] = splitProps(props, ["children", "ref", "fx", "style"]);
224
- const record = ctx.record;
225
- const placement = record().placement;
226
- const dir = placement.endsWith("left") ? -1 : placement.endsWith("right") ? 1 : 0;
227
- const THRESHOLD = 60;
228
- let el;
229
- let startX = 0;
230
- let dragging = false;
231
- const onPointerDown = (event) => {
232
- if (event.button !== 0 || !el) return;
233
- if (event.target.closest("button,a,input,textarea,select")) return;
234
- dragging = true;
235
- startX = event.clientX;
236
- el.setPointerCapture?.(event.pointerId);
237
- el.setAttribute("data-swiping", "");
238
- };
239
- const constrain = (dx) => dir > 0 ? Math.max(0, dx) : dir < 0 ? Math.min(0, dx) : dx;
240
- const onPointerMove = (event) => {
241
- if (!dragging || !el) return;
242
- const dx = constrain(event.clientX - startX);
243
- el.style.setProperty("--flx-ui-toast-swipe", `${dx}px`);
244
- el.style.opacity = `${Math.max(0.35, 1 - Math.abs(dx) / 200)}`;
245
- };
246
- const onPointerUp = (event) => {
247
- if (!dragging || !el) return;
248
- dragging = false;
249
- el.removeAttribute("data-swiping");
250
- const dx = constrain(event.clientX - startX);
251
- if (Math.abs(dx) >= THRESHOLD) {
252
- el.setAttribute("data-swiped-out", "");
253
- el.style.setProperty("--flx-ui-toast-swipe", `${(dx < 0 ? -1 : 1) * 480}px`);
254
- el.style.opacity = "0";
255
- setTimeout(() => ctx.dismiss(), 150);
256
- } else {
257
- el.style.removeProperty("--flx-ui-toast-swipe");
258
- el.style.removeProperty("opacity");
259
- }
260
- };
261
- const setRef = (node) => {
262
- el = node;
263
- const onEntered = () => {
264
- node.setAttribute("data-entered", "");
265
- node.removeEventListener("animationend", onEntered);
266
- };
267
- node.addEventListener("animationend", onEntered);
268
- onCleanup(() => node.removeEventListener("animationend", onEntered));
269
- handleRef(local.ref, node);
270
- };
271
- return (() => {
272
- const _el$ = createNativeElement("li");
273
- spread({ element: _el$, props: mergeProps(fxProps(
274
- () => local.fx,
275
- () => local.style
276
- ), others, { ref: setRef, "data-toast": "", "data-type": () => record().type, role: () => record().type === "error" ? "alert" : "status", "aria-live": () => record().type === "error" ? "assertive" : "polite", "aria-atomic": "true", tabindex: -1, onPointerDown, onPointerMove, onPointerUp }) });
277
- insert(_el$, createMemo(() => createComponent(Show, { get when() {
278
- return () => local.children ?? record().render;
279
- }, get fallback() {
280
- return createMemo(() => createComponent(ToastDefaultBody, {}));
281
- }, get children() {
282
- return () => local.children ?? record().render(record());
283
- } })), null);
284
- return _el$;
285
- })();
310
+ const ctx = useToastContext();
311
+ const [local, others] = splitProps(props, [
312
+ "children",
313
+ "ref",
314
+ "fx",
315
+ "style"
316
+ ]);
317
+ const record = ctx.record;
318
+ const placement = record().placement;
319
+ const dir = placement.endsWith("left") ? -1 : placement.endsWith("right") ? 1 : 0;
320
+ const THRESHOLD = 60;
321
+ let el;
322
+ let startX = 0;
323
+ let dragging = false;
324
+ const onPointerDown = (event) => {
325
+ if (event.button !== 0 || !el) return;
326
+ if (event.target.closest("button,a,input,textarea,select")) return;
327
+ dragging = true;
328
+ startX = event.clientX;
329
+ el.setPointerCapture?.(event.pointerId);
330
+ el.setAttribute("data-swiping", "");
331
+ };
332
+ const constrain = (dx) => dir > 0 ? Math.max(0, dx) : dir < 0 ? Math.min(0, dx) : dx;
333
+ const onPointerMove = (event) => {
334
+ if (!dragging || !el) return;
335
+ const dx = constrain(event.clientX - startX);
336
+ el.style.setProperty("--flx-ui-toast-swipe", `${dx}px`);
337
+ el.style.opacity = `${Math.max(.35, 1 - Math.abs(dx) / 200)}`;
338
+ };
339
+ const onPointerUp = (event) => {
340
+ if (!dragging || !el) return;
341
+ dragging = false;
342
+ el.removeAttribute("data-swiping");
343
+ const dx = constrain(event.clientX - startX);
344
+ if (Math.abs(dx) >= THRESHOLD) {
345
+ el.setAttribute("data-swiped-out", "");
346
+ el.style.setProperty("--flx-ui-toast-swipe", `${(dx < 0 ? -1 : 1) * 480}px`);
347
+ el.style.opacity = "0";
348
+ setTimeout(() => ctx.dismiss(), 150);
349
+ } else {
350
+ el.style.removeProperty("--flx-ui-toast-swipe");
351
+ el.style.removeProperty("opacity");
352
+ }
353
+ };
354
+ const setRef = (node) => {
355
+ el = node;
356
+ const onEntered = () => {
357
+ node.setAttribute("data-entered", "");
358
+ node.removeEventListener("animationend", onEntered);
359
+ };
360
+ node.addEventListener("animationend", onEntered);
361
+ onCleanup(() => node.removeEventListener("animationend", onEntered));
362
+ handleRef(local.ref, node);
363
+ };
364
+ return (() => {
365
+ const _el$ = createNativeElement("li");
366
+ spread({
367
+ element: _el$,
368
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
369
+ ref: setRef,
370
+ "data-toast": "",
371
+ "data-type": () => record().type,
372
+ role: () => record().type === "error" ? "alert" : "status",
373
+ "aria-live": () => record().type === "error" ? "assertive" : "polite",
374
+ "aria-atomic": "true",
375
+ tabindex: -1,
376
+ onPointerDown,
377
+ onPointerMove,
378
+ onPointerUp
379
+ })
380
+ });
381
+ insert(_el$, createMemo(() => createComponent(Show, {
382
+ get when() {
383
+ return () => local.children ?? record().render;
384
+ },
385
+ get fallback() {
386
+ return createMemo(() => createComponent(ToastDefaultBody, {}));
387
+ },
388
+ get children() {
389
+ return () => local.children ?? record().render(record());
390
+ }
391
+ })), null);
392
+ return _el$;
393
+ })();
286
394
  }
287
395
  function ToastDefaultBody() {
288
- const ctx = useToastContext();
289
- const record = ctx.record;
290
- return [(() => {
291
- const _el$ = templateNode(_fxTmpl$0, "div", true);
292
- const _n$0 = _el$.firstChild;
293
- const _n$1 = holeEnd(_n$0);
294
- const _n$2 = _n$1.nextSibling;
295
- const _n$3 = holeEnd(_n$2);
296
- insert(_el$, holeScope(_n$0, () => createMemo(() => createComponent(Show, { get when() {
297
- return () => record().title;
298
- }, get children() {
299
- return createMemo(() => createComponent(ToastTitle, { get children() {
300
- return () => record().title;
301
- } }));
302
- } }))), _n$1, holeContent(_n$0, _n$1));
303
- insert(_el$, holeScope(_n$2, () => createMemo(() => createComponent(Show, { get when() {
304
- return () => record().description;
305
- }, get children() {
306
- return createMemo(() => createComponent(ToastDescription, { get children() {
307
- return () => record().description;
308
- } }));
309
- } }))), _n$3, holeContent(_n$2, _n$3));
310
- return _el$;
311
- })(), createMemo(() => createComponent(Show, { get when() {
312
- return () => record().dismissible;
313
- }, get children() {
314
- return createMemo(() => createComponent(ToastClose, {}));
315
- } }))];
396
+ const record = useToastContext().record;
397
+ return [(() => {
398
+ const _el$ = templateNode(_fxTmpl$0, "div", true);
399
+ const _n$0 = _el$.firstChild;
400
+ const _n$1 = holeEnd(_n$0);
401
+ const _n$2 = _n$1.nextSibling;
402
+ const _n$3 = holeEnd(_n$2);
403
+ insert(_el$, holeScope(_n$0, () => createMemo(() => createComponent(Show, {
404
+ get when() {
405
+ return () => record().title;
406
+ },
407
+ get children() {
408
+ return createMemo(() => createComponent(ToastTitle, { get children() {
409
+ return () => record().title;
410
+ } }));
411
+ }
412
+ }))), _n$1, holeContent(_n$0, _n$1));
413
+ insert(_el$, holeScope(_n$2, () => createMemo(() => createComponent(Show, {
414
+ get when() {
415
+ return () => record().description;
416
+ },
417
+ get children() {
418
+ return createMemo(() => createComponent(ToastDescription, { get children() {
419
+ return () => record().description;
420
+ } }));
421
+ }
422
+ }))), _n$3, holeContent(_n$2, _n$3));
423
+ return _el$;
424
+ })(), createMemo(() => createComponent(Show, {
425
+ get when() {
426
+ return () => record().dismissible;
427
+ },
428
+ get children() {
429
+ return createMemo(() => createComponent(ToastClose, {}));
430
+ }
431
+ }))];
316
432
  }
433
+ /** The toast's headline. */
317
434
  function ToastTitle(props) {
318
- const [local, others] = splitProps(props, ["children", "fx", "style"]);
319
- return (() => {
320
- const _el$ = createNativeElement("div");
321
- spread({ element: _el$, props: mergeProps(fxProps(
322
- () => local.fx,
323
- () => local.style
324
- ), others, { "data-toast-title": "" }) });
325
- insert(_el$, local.children);
326
- return _el$;
327
- })();
435
+ const [local, others] = splitProps(props, [
436
+ "children",
437
+ "fx",
438
+ "style"
439
+ ]);
440
+ return (() => {
441
+ const _el$ = createNativeElement("div");
442
+ spread({
443
+ element: _el$,
444
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, { "data-toast-title": "" })
445
+ });
446
+ insert(_el$, local.children, null);
447
+ return _el$;
448
+ })();
328
449
  }
450
+ /** Supporting detail under the title. */
329
451
  function ToastDescription(props) {
330
- const [local, others] = splitProps(props, ["children", "fx", "style"]);
331
- return (() => {
332
- const _el$ = createNativeElement("div");
333
- spread({ element: _el$, props: mergeProps(fxProps(
334
- () => local.fx,
335
- () => local.style
336
- ), others, { "data-toast-description": "" }) });
337
- insert(_el$, local.children);
338
- return _el$;
339
- })();
452
+ const [local, others] = splitProps(props, [
453
+ "children",
454
+ "fx",
455
+ "style"
456
+ ]);
457
+ return (() => {
458
+ const _el$ = createNativeElement("div");
459
+ spread({
460
+ element: _el$,
461
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, { "data-toast-description": "" })
462
+ });
463
+ insert(_el$, local.children, null);
464
+ return _el$;
465
+ })();
340
466
  }
467
+ /** Dismisses the toast. */
341
468
  function ToastClose(props) {
342
- const ctx = useToastContext();
343
- const [local, others] = splitProps(props, ["onClick", "children", "ref", "fx", "style"]);
344
- return (() => {
345
- const _el$ = createNativeElement("button");
346
- spread({ element: _el$, props: mergeProps(fxProps(
347
- () => local.fx,
348
- () => local.style
349
- ), others, { ref: (node) => handleRef(local.ref, node), type: "button", "data-toast-close": "", "aria-label": "Dismiss", onClick: composeEventHandlers([
350
- local.onClick,
351
- () => ctx.dismiss()
352
- ]) }) });
353
- insert(_el$, createMemo(() => createComponent(Show, { get when() {
354
- return () => local.children;
355
- }, get fallback() {
356
- return "✕";
357
- }, get children() {
358
- return local.children;
359
- } })), null);
360
- return _el$;
361
- })();
469
+ const ctx = useToastContext();
470
+ const [local, others] = splitProps(props, [
471
+ "onClick",
472
+ "children",
473
+ "ref",
474
+ "fx",
475
+ "style"
476
+ ]);
477
+ return (() => {
478
+ const _el$ = createNativeElement("button");
479
+ spread({
480
+ element: _el$,
481
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
482
+ ref: (node) => handleRef(local.ref, node),
483
+ type: "button",
484
+ "data-toast-close": "",
485
+ "aria-label": "Dismiss",
486
+ onClick: composeEventHandlers([local.onClick, () => ctx.dismiss()])
487
+ })
488
+ });
489
+ insert(_el$, createMemo(() => createComponent(Show, {
490
+ get when() {
491
+ return () => local.children;
492
+ },
493
+ get fallback() {
494
+ return "✕";
495
+ },
496
+ get children() {
497
+ return local.children;
498
+ }
499
+ })), null);
500
+ return _el$;
501
+ })();
362
502
  }
503
+ /** An action button inside a toast (e.g. "Undo"). */
363
504
  function ToastAction(props) {
364
- const ctx = useToastContext();
365
- const [local, others] = splitProps(props, ["onClick", "dismissOnClick", "children", "ref", "fx", "style"]);
366
- return (() => {
367
- const _el$ = createNativeElement("button");
368
- spread({ element: _el$, props: mergeProps(fxProps(
369
- () => local.fx,
370
- () => local.style
371
- ), others, { ref: (node) => handleRef(local.ref, node), type: "button", "data-toast-action": "", onClick: composeEventHandlers([
372
- local.onClick,
373
- () => {
374
- if (local.dismissOnClick !== false) ctx.dismiss();
375
- }
376
- ]) }) });
377
- insert(_el$, local.children);
378
- return _el$;
379
- })();
505
+ const ctx = useToastContext();
506
+ const [local, others] = splitProps(props, [
507
+ "onClick",
508
+ "dismissOnClick",
509
+ "children",
510
+ "ref",
511
+ "fx",
512
+ "style"
513
+ ]);
514
+ return (() => {
515
+ const _el$ = createNativeElement("button");
516
+ spread({
517
+ element: _el$,
518
+ props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
519
+ ref: (node) => handleRef(local.ref, node),
520
+ type: "button",
521
+ "data-toast-action": "",
522
+ onClick: composeEventHandlers([local.onClick, () => {
523
+ if (local.dismissOnClick !== false) ctx.dismiss();
524
+ }])
525
+ })
526
+ });
527
+ insert(_el$, local.children, null);
528
+ return _el$;
529
+ })();
380
530
  }
381
- export {
382
- Toast,
383
- ToastAction,
384
- ToastClose,
385
- ToastDescription,
386
- ToastTitle,
387
- Toaster,
388
- createToastStore,
389
- toast
390
- };
531
+ //#endregion
532
+ export { Toast, ToastAction, ToastClose, ToastDescription, ToastTitle, Toaster, createToastStore, toast };