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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/store.ts +16 -10
  3. package/src/util.ts +33 -0
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "url": "https://github.com/adrianjanocko/toastflow.git",
9
9
  "directory": "packages/core"
10
10
  },
11
- "version": "1.0.5",
11
+ "version": "1.0.7",
12
12
  "main": "src/index.ts",
13
13
  "module": "src/index.ts",
14
14
  "types": "src/index.ts",
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 = crypto.randomUUID();
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 (next.duration === 0 || !Number.isFinite(next.duration)) {
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
+ }