toastflow-core 1.0.5 → 1.0.7
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/package.json +1 -1
- package/src/store.ts +16 -10
- package/src/util.ts +33 -0
package/package.json
CHANGED
package/src/store.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
ToastType,
|
|
16
16
|
ToastUpdateInput,
|
|
17
17
|
} from "./types";
|
|
18
|
+
import { generateUuid, isNumberFinite } from "./util";
|
|
18
19
|
|
|
19
20
|
type Listener = (state: ToastState) => void;
|
|
20
21
|
type EventListener = (event: ToastEvent) => void;
|
|
@@ -90,10 +91,12 @@ export function createToastStore(
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
// Return the current toast state.
|
|
93
95
|
function getState(): ToastState {
|
|
94
96
|
return state;
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
// Subscribe to store updates and immediately receive the current state.
|
|
97
100
|
function subscribe(listener: Listener): () => void {
|
|
98
101
|
listeners.add(listener);
|
|
99
102
|
listener(state);
|
|
@@ -102,6 +105,7 @@ export function createToastStore(
|
|
|
102
105
|
};
|
|
103
106
|
}
|
|
104
107
|
|
|
108
|
+
// Subscribe to toast lifecycle events only.
|
|
105
109
|
function subscribeEvents(listener: EventListener): () => void {
|
|
106
110
|
eventListeners.add(listener);
|
|
107
111
|
return () => {
|
|
@@ -109,6 +113,7 @@ export function createToastStore(
|
|
|
109
113
|
};
|
|
110
114
|
}
|
|
111
115
|
|
|
116
|
+
// Show a toast, handling duplicates and auto-dismiss scheduling.
|
|
112
117
|
function show(options: ToastShowInput): ToastId {
|
|
113
118
|
assertShowInput(options, "show");
|
|
114
119
|
|
|
@@ -150,7 +155,7 @@ export function createToastStore(
|
|
|
150
155
|
}
|
|
151
156
|
}
|
|
152
157
|
|
|
153
|
-
const id =
|
|
158
|
+
const id = generateUuid();
|
|
154
159
|
const createdAt = Date.now();
|
|
155
160
|
|
|
156
161
|
const toastInstance: ToastInstance = {
|
|
@@ -199,6 +204,7 @@ export function createToastStore(
|
|
|
199
204
|
return id;
|
|
200
205
|
}
|
|
201
206
|
|
|
207
|
+
// Wrap a promise with loading/success/error toast states.
|
|
202
208
|
function loading<T>(
|
|
203
209
|
input: ToastLoadingInput<T>,
|
|
204
210
|
config: ToastLoadingConfig<T>,
|
|
@@ -280,6 +286,7 @@ export function createToastStore(
|
|
|
280
286
|
return result;
|
|
281
287
|
}
|
|
282
288
|
|
|
289
|
+
// Update an existing toast and reset its timer.
|
|
283
290
|
function update(id: ToastId, options: ToastUpdateInput): void {
|
|
284
291
|
const existing = state.toasts.find((t) => t.id === id);
|
|
285
292
|
if (!existing) {
|
|
@@ -318,6 +325,7 @@ export function createToastStore(
|
|
|
318
325
|
notify();
|
|
319
326
|
}
|
|
320
327
|
|
|
328
|
+
// Hide a toast, run lifecycle callbacks, and remove it after the leave animation.
|
|
321
329
|
function dismiss(id: ToastId): void {
|
|
322
330
|
const toast = state.toasts.find((t) => t.id === id);
|
|
323
331
|
if (!toast) {
|
|
@@ -373,6 +381,7 @@ export function createToastStore(
|
|
|
373
381
|
}, HIDE_ANIMATION_DURATION);
|
|
374
382
|
}
|
|
375
383
|
|
|
384
|
+
// Clear all toasts in their current positions.
|
|
376
385
|
function dismissAll(): void {
|
|
377
386
|
if (!state.toasts.length) {
|
|
378
387
|
return;
|
|
@@ -431,10 +440,7 @@ export function createToastStore(
|
|
|
431
440
|
}
|
|
432
441
|
|
|
433
442
|
function scheduleAutoDismiss(toastInstance: ToastInstance) {
|
|
434
|
-
if (
|
|
435
|
-
!Number.isFinite(toastInstance.duration) ||
|
|
436
|
-
toastInstance.duration <= 0
|
|
437
|
-
) {
|
|
443
|
+
if (!isNumberFinite(toastInstance.duration)) {
|
|
438
444
|
timers.delete(toastInstance.id);
|
|
439
445
|
return;
|
|
440
446
|
}
|
|
@@ -462,6 +468,7 @@ export function createToastStore(
|
|
|
462
468
|
timers.delete(id);
|
|
463
469
|
}
|
|
464
470
|
|
|
471
|
+
// Pause a toast timer and capture the remaining time.
|
|
465
472
|
function pause(id: ToastId): void {
|
|
466
473
|
const timer = timers.get(id);
|
|
467
474
|
if (!timer || timer.paused) {
|
|
@@ -484,6 +491,7 @@ export function createToastStore(
|
|
|
484
491
|
});
|
|
485
492
|
}
|
|
486
493
|
|
|
494
|
+
// Resume a paused toast timer according to its pause strategy.
|
|
487
495
|
function resume(id: ToastId): void {
|
|
488
496
|
const timer = timers.get(id);
|
|
489
497
|
const toastInstance = state.toasts.find((t) => t.id === id);
|
|
@@ -493,10 +501,7 @@ export function createToastStore(
|
|
|
493
501
|
return;
|
|
494
502
|
}
|
|
495
503
|
|
|
496
|
-
if (
|
|
497
|
-
toastInstance.duration === 0 ||
|
|
498
|
-
!Number.isFinite(toastInstance.duration)
|
|
499
|
-
) {
|
|
504
|
+
if (!isNumberFinite(toastInstance.duration)) {
|
|
500
505
|
timers.delete(id);
|
|
501
506
|
return;
|
|
502
507
|
}
|
|
@@ -537,6 +542,7 @@ export function createToastStore(
|
|
|
537
542
|
});
|
|
538
543
|
}
|
|
539
544
|
|
|
545
|
+
// Return the resolved global configuration for this store.
|
|
540
546
|
function getConfig(): ToastConfig {
|
|
541
547
|
return {
|
|
542
548
|
...defaults,
|
|
@@ -638,7 +644,7 @@ function insertToast(
|
|
|
638
644
|
existing: ToastInstance[],
|
|
639
645
|
next: ToastInstance,
|
|
640
646
|
): ToastInstance[] {
|
|
641
|
-
if (
|
|
647
|
+
if (!isNumberFinite(next.duration)) {
|
|
642
648
|
next.progressBar = false;
|
|
643
649
|
}
|
|
644
650
|
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a UUID v4 using `crypto.randomUUID` when available; otherwise fall back
|
|
3
|
+
* to the classic template with random nibbles (uses `crypto.getRandomValues` when possible).
|
|
4
|
+
*/
|
|
5
|
+
export function generateUuid(): string {
|
|
6
|
+
const cryptoSource: Crypto | undefined =
|
|
7
|
+
typeof crypto !== "undefined" ? (crypto as Crypto) : undefined;
|
|
8
|
+
|
|
9
|
+
if (typeof cryptoSource?.randomUUID === "function") {
|
|
10
|
+
try {
|
|
11
|
+
return cryptoSource.randomUUID();
|
|
12
|
+
} catch {
|
|
13
|
+
// ignore and use fallback
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
18
|
+
const randomValues = cryptoSource?.getRandomValues?.(new Uint8Array(1));
|
|
19
|
+
const rand =
|
|
20
|
+
randomValues && randomValues.length > 0
|
|
21
|
+
? randomValues[0] & 0xf
|
|
22
|
+
: Math.floor(Math.random() * 16);
|
|
23
|
+
const value = c === "x" ? rand : (rand & 0x3) | 0x8;
|
|
24
|
+
return value.toString(16);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if a value is a finite number greater than zero.
|
|
30
|
+
*/
|
|
31
|
+
export function isNumberFinite(value: unknown): value is number {
|
|
32
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
33
|
+
}
|