customizable-toast-notification 3.15.0 β†’ 3.17.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/README.md CHANGED
@@ -1,19 +1,46 @@
1
1
  # 🍞 Customizable Toast Notifications
2
2
 
3
- ![npm](https://img.shields.io/npm/v/customizable-toast-notification)
4
- ![npm downloads](https://img.shields.io/npm/dm/customizable-toast-notification)
3
+ [![npm](https://img.shields.io/npm/v/customizable-toast-notification)](https://www.npmjs.com/package/customizable-toast-notification)
4
+ [![npm downloads](https://img.shields.io/npm/dm/customizable-toast-notification)](https://www.npmjs.com/package/customizable-toast-notification)
5
5
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+ [![Zero Runtime Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](package.json)
6
7
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/customizable-toast-notification)](https://bundlephobia.com/package/customizable-toast-notification)
8
+ [![TypeScript Strict](https://img.shields.io/badge/TypeScript-Strict%20Types-blue?logo=typescript)](dist/index.d.ts)
9
+ [![CodeQL Security](https://img.shields.io/badge/CodeQL-Protected-success?logo=github)](.github/workflows/codeql.yml)
10
+ [![Open in StackBlitz](https://img.shields.io/badge/StackBlitz-Live%20Sandbox-blue?logo=stackblitz)](https://stackblitz.com/edit/customizable-toast-notification-demo?file=index.html)
7
11
 
8
- **[β–Ά Try the live demo](https://sammy-cool.github.io/customizable-toast-notification/)** β€” click a button, watch a real toast fire, sanitized HTML included.
12
+ **[β–Ά Try the interactive live playground](https://sammy-cool.github.io/customizable-toast-notification/)** β€” test damped spring physics, 5 zero-asset Web Audio synthesizer presets, dynamic action undo countdowns, and iOS-style card deck stacking in real time.
9
13
 
10
- Toast notifications that work the same everywhere β€” plain JavaScript, Vue, Svelte, Angular, or a plain multi-page app β€” not just React. Built with sanitized-by-default HTML rendering, zero runtime dependencies, and 129 real cross-browser end-to-end tests.
14
+ ```
15
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
16
+ β”‚ customizable-toast-notification β”‚
17
+ β”‚ Zero Dependencies β€’ Universal Multi-Framework β€’ Pure Native β”‚
18
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
19
+ β”‚
20
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
21
+ β–Ό β–Ό β–Ό β–Ό
22
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
23
+ β”‚ Web Audio β”‚ β”‚ Spring Physicsβ”‚ β”‚ Action Undo β”‚ β”‚ Card Deck β”‚
24
+ β”‚ 5 Synth β”‚ β”‚ Damped β”‚ β”‚ Dynamic Live β”‚ β”‚ iOS-Style β”‚
25
+ β”‚ Presets + β”‚ β”‚ Harmonic β”‚ β”‚ Countdown β”‚ β”‚ Pinch-to- β”‚
26
+ β”‚ Oscilloscope β”‚ β”‚ Oscillator β”‚ β”‚ Badge (Xs) β”‚ β”‚ Expand Stack β”‚
27
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
28
+ β”‚ β”‚ β”‚ β”‚
29
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
30
+ β–Ό
31
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
32
+ β”‚ Framework Adapters & TypeSafe AI Smart Triage β”‚
33
+ β”‚ React β€’ Vue β€’ Svelte β€’ Angular β€’ SolidJS β€’ Jev β”‚
34
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
35
+ ```
36
+
37
+ Toast notifications that work the same everywhere β€” plain JavaScript, Vue, Svelte, Angular, SolidJS, or a multi-page app. Built with sanitized-by-default HTML rendering, zero runtime dependencies, and 177 automated unit & logic tests plus Playwright cross-browser specifications.
11
38
 
12
39
  ## ✨ Key Features
13
40
 
14
41
  - 🌐 **Actually Framework Agnostic** - Not a React library with "vanilla JS support" bolted on β€” the same API works identically in React, Vue, Angular, Svelte, htmx, or plain HTML with no build step at all
15
42
  - πŸ›‘οΈ **Sanitized by Default** - `allowHtml` content is sanitized before render (DOMPurify if it's on the page, a verified-equivalent fallback if not) β€” safe to use with content you don't fully control
16
- - βœ… **Rigorously Tested** - 129 real Playwright end-to-end tests across Chromium, Firefox, and WebKit, plus a fast unit suite β€” not just "it worked on my machine"
43
+ - βœ… **Rigorously Tested** - 177 real logic & unit tests plus Playwright end-to-end specifications across Chromium, Firefox, and WebKit β€” not just "it worked on my machine"
17
44
  - 🚫 **Zero Runtime Dependencies** - Nothing pulled in when your users load your app
18
45
  - πŸ”§ **Real TypeScript Types** - Full type definitions with real autocomplete and type-checking, not a placeholder `any`
19
46
  - 🎨 **Highly Customizable** - Colors, positions, animations, progress bars, and styling
@@ -45,21 +72,40 @@ yarn add customizable-toast-notification
45
72
  ### ES Modules
46
73
 
47
74
  ```js
48
- import {
49
- createToast,
50
- setDefaultColors,
51
- setDefaultMessages,
52
- } from "customizable-toast-notification";
53
-
54
- // Simple usage
55
- createToast({
56
- message: "Hello World!",
75
+ // Default import (recommended) or named import:
76
+ import toast, { createToast } from "customizable-toast-notification";
77
+
78
+ // 1. Shorthand methods (Quickest & cleanest)
79
+ toast.success("Saved successfully!");
80
+ toast.error("Failed to connect to server");
81
+ toast.warning("Unsaved changes detected");
82
+ toast.info("Tip: Press Esc to dismiss anytime");
83
+ toast.custom("<b>Formatted</b> notification with HTML!");
84
+
85
+ // 2. Persistent loading state
86
+ const loading = await toast.loading("Uploading files...");
87
+ // ... later update in-place
88
+ await loading.update({ type: "success", message: "Files uploaded!", showLoader: false });
89
+
90
+ // 3. Direct message string
91
+ toast("Simple notification");
92
+
93
+ // 4. Programmatic dismiss
94
+ toast.dismiss(loading.id); // dismiss by ID or handle
95
+ toast.dismissAll(); // dismiss all notifications
96
+
97
+ // 5. Full configuration options
98
+ toast({
99
+ message: "Customized toast!",
57
100
  type: "success",
58
101
  duration: 3000,
102
+ position: "bottom-right",
103
+ spring: "gentle",
104
+ sound: true,
59
105
  });
60
106
  ```
61
107
 
62
- ### CDN/Browser (UMD Build) / Quick Try with jsDelivr
108
+ ### CDN / Browser (UMD Build) / Quick Try with jsDelivr
63
109
 
64
110
  Global Variable Name: `customizableToast`
65
111
 
@@ -67,8 +113,8 @@ Global Variable Name: `customizableToast`
67
113
  <!-- Always latest version -->
68
114
  <script src="https://cdn.jsdelivr.net/npm/customizable-toast-notification/dist/index.umd.js"></script>
69
115
 
70
- <!-- OR pin to a specific version (recommended for stability) -->
71
- <script src="https://cdn.jsdelivr.net/npm/customizable-toast-notification@3.12.3/dist/index.umd.js"></script>
116
+ <!-- OR pin to a specific version -->
117
+ <script src="https://cdn.jsdelivr.net/npm/customizable-toast-notification@3.16.0/dist/index.umd.js"></script>
72
118
 
73
119
  <script>
74
120
  // Access the global UMD export
@@ -108,13 +154,28 @@ const handle = await createToast({
108
154
  // Update progress in-place:
109
155
  await handle.update({ progress: 65, message: "Uploading assets... 65%" });
110
156
 
111
- // Transition state seamlessly:
157
+ // Stream multi-action CTA buttons dynamically:
158
+ await handle.update({
159
+ message: "Upload requires authorization:",
160
+ cta: [
161
+ { label: "Approve", onClick: () => console.log("Approved!") },
162
+ { label: "Cancel", autoClose: true, onClick: () => console.log("Cancelled") },
163
+ ],
164
+ });
165
+
166
+ // Transition to completion with dynamic countdown Undo badge:
112
167
  await handle.update({
113
168
  type: "success",
114
169
  message: "Upload complete!",
115
170
  showLoader: false,
116
- duration: 3000,
171
+ cta: null, // cleanly strip CTA buttons
172
+ duration: 6000,
117
173
  sound: "success",
174
+ undo: {
175
+ label: "Undo",
176
+ showCountdown: true, // "Undo (6s... 1s)"
177
+ onUndo: () => console.log("Undone!"),
178
+ },
118
179
  });
119
180
 
120
181
  // Or dismiss manually at any point:
@@ -122,7 +183,8 @@ await handle.dismiss();
122
183
  ```
123
184
 
124
185
  `handle.dismiss()` and `handle.update()` are always safe to call, even if the toast already
125
- auto-dismissed on its own β€” they no-op gracefully rather than throwing.
186
+ auto-dismissed on its own β€” they no-op gracefully rather than throwing. You can update `message`,
187
+ `progress`, `type`, `showLoader`, `loader`, `cta` (single object, array, or `null`), and `undo` in-place.
126
188
 
127
189
  #### Options
128
190
 
@@ -153,14 +215,19 @@ auto-dismissed on its own β€” they no-op gracefully rather than throwing.
153
215
  | `fontLineHeight` | `string` | `"1.4"` | Font line height |
154
216
  | `showLoader` | `boolean` | `false` | Show spinner loader before the message |
155
217
  | `loader` | `object` | `null` | Custom loader config (`size`, `color`, `text`) |
218
+ | `icon` | `boolean \| string \| HTMLElement` | `true` for typed, `null` | Status icon: `true` (built-in SVG), `false` (hide), emoji (`"πŸŽ‰"`), SVG string, or DOM node |
156
219
  | `fontDirection` | `string` | `"auto"` | Font direction: `"auto"`, `"ltr"`, `"rtl"` |
157
220
  | `fontPadding` | `string` | `undefined` | Custom padding for message container (e.g. `"4px 8px"`) |
158
221
  | `className` | `string` | `undefined` | Custom CSS class name(s) for animations / styling |
159
222
  | `stacked` | `boolean` | `false` | Enable iOS-style card deck stacking for multiple toasts |
160
223
  | `sound` | `boolean \| string`| `false` | Zero-asset audio chime (`true`, `'success'`, `'error'`, `'warning'`, `'pop'`) |
224
+ | `soundPreset` | `string` | `"modern"` | Audio synth theme: `"modern"`, `"retro"`, `"futuristic"`, `"subtle"`, `"bell"` |
161
225
  | `swipeToDismiss` | `boolean` | `true` | Mobile touch swipe-to-dismiss gesture with physics |
162
226
  | `progress` | `number` | `undefined` | Explicit progress bar percentage (0 to 100) |
163
- | `cta` | `object` | `null` | Call-to-action configuration (see [CTA](#call-to-action)) |
227
+ | `usePool` | `boolean` | `false` | Virtual element pooling for DOM recycling in high-frequency rendering |
228
+ | `cta` | `object \| array` | `null` | Call-to-action configuration (see [CTA](#call-to-action)) |
229
+ | `undo` | `function \| object`| `null` | Action Undo button with live dynamic countdown badge (see [Undo](#️-action-undo-with-live-countdown)) |
230
+ | `spring` | `boolean \| string \| object`| `null` | Configurable spring physics animations (see [Spring Physics](#-configurable-spring-physics-animation-engine)) |
164
231
 
165
232
  #### Position Options
166
233
 
@@ -168,8 +235,9 @@ auto-dismissed on its own β€” they no-op gracefully rather than throwing.
168
235
  // Corner positions
169
236
  - "top-left", "top-right", "bottom-left", "bottom-right"
170
237
 
171
- // Edge positions
238
+ // Edge positions & center aliases
172
239
  - "top-center", "bottom-center", "left-center", "right-center"
240
+ - "center-top", "center-bottom", "center-left", "center-right"
173
241
 
174
242
  // Full width
175
243
  - "top-full-width", "bottom-full-width"
@@ -220,6 +288,22 @@ createToast({
220
288
  },
221
289
  },
222
290
  });
291
+
292
+ // Multi-Action CTAs (Dual actions e.g. Accept / Decline)
293
+ createToast({
294
+ message: "Project invite from Priya Patel",
295
+ cta: [
296
+ {
297
+ label: "Accept",
298
+ onClick: async () => await acceptInvitation(),
299
+ },
300
+ {
301
+ label: "Decline",
302
+ autoClose: true,
303
+ onClick: async () => await declineInvitation(),
304
+ },
305
+ ],
306
+ });
223
307
  ```
224
308
 
225
309
  Any toast with a `cta` automatically gets `pauseOnHover: true` unless you override it.
@@ -237,6 +321,75 @@ Any toast with a `cta` automatically gets `pauseOnHover: true` unless you overri
237
321
  | `autoClose` | `boolean` | `true` | Close toast after CTA click |
238
322
  | `ariaLabel` | `string` | `label` | Accessibility label |
239
323
 
324
+ ### ↩️ Action Undo with Live Countdown
325
+
326
+ Allow users to immediately reverse actions (e.g. "Item deleted", "Message archived") with a dynamic, decaying countdown badge:
327
+
328
+ ```js
329
+ createToast({
330
+ message: "Conversation moved to trash",
331
+ type: "warning",
332
+ duration: 5000,
333
+ undo: {
334
+ label: "Undo",
335
+ showCountdown: true, // displays "Undo (5s)... (4s)..."
336
+ onUndo: async (e, toast) => {
337
+ await restoreConversation();
338
+ console.log("Restored!");
339
+ },
340
+ },
341
+ });
342
+
343
+ // Or concise callback shorthand:
344
+ createToast({
345
+ message: "Draft deleted",
346
+ undo: () => restoreDraft(),
347
+ });
348
+ ```
349
+
350
+ | Parameter | Type | Default | Description |
351
+ | --------- | ---- | ------- | ----------- |
352
+ | `label` | `string` | `"Undo"` | Button text label |
353
+ | `showCountdown` | `boolean` | `true` | Decays remaining duration in seconds in real-time |
354
+ | `onUndo` | `function` | `undefined` | Callback fired on click; supports async promises before auto-closing toast |
355
+
356
+ ### πŸŒ€ Configurable Spring Physics Animation Engine
357
+
358
+ Replaces standard transitions with damped harmonic oscillator physics:
359
+
360
+ ```js
361
+ // Use built-in presets: 'default', 'gentle', 'wobbly', 'stiff', 'bouncy'
362
+ createToast({
363
+ message: "Synced to cloud",
364
+ spring: "bouncy",
365
+ });
366
+
367
+ // Or customize exact physical constants:
368
+ createToast({
369
+ message: "Physics simulated notification",
370
+ spring: {
371
+ stiffness: 180, // Spring tension (k)
372
+ damping: 12, // Friction resistance (c)
373
+ mass: 1.2, // Inertial mass (m)
374
+ },
375
+ });
376
+ ```
377
+
378
+ | Preset | Stiffness ($k$) | Damping ($c$) | Mass ($m$) | Behavior |
379
+ | ------ | --------------- | ------------- | ---------- | -------- |
380
+ | `default` | 100 | 10 | 1 | Natural subtle bounce |
381
+ | `gentle` | 120 | 14 | 1 | Smooth with minimal overshoot |
382
+ | `wobbly` | 180 | 12 | 1 | Playful oscillation |
383
+ | `stiff` | 210 | 20 | 1 | Crisp, rapid settling |
384
+ | `bouncy` | 300 | 15 | 1.2 | High energy with dynamic bounce |
385
+
386
+ Register custom global presets or resolve spring curves directly:
387
+ ```js
388
+ import { registerSpringPreset, getSpringTransition } from "customizable-toast-notification";
389
+
390
+ registerSpringPreset("snappy", { stiffness: 250, damping: 22, mass: 1 });
391
+ ```
392
+
240
393
  ### Loader Options
241
394
 
242
395
  Add an animated SVG spinner directly alongside the message:
@@ -403,6 +556,188 @@ The loading toast doesn't use `duration` from `options` β€” it stays until
403
556
  the promise settles, then is replaced by a success or error toast that
404
557
  does respect the normal duration/auto-dismiss behavior.
405
558
 
559
+ ## βš™οΈ Global Configuration
560
+
561
+ Configure library-wide defaults using `setConfig()` and check current settings with `getConfig()`:
562
+
563
+ ```js
564
+ import { setConfig, getConfig, shouldReduceMotion } from "customizable-toast-notification";
565
+
566
+ // Configure global defaults
567
+ setConfig({
568
+ maxVisible: 5, // Max simultaneously visible toasts (default: 3)
569
+ zIndex: 10000, // Base z-index for containers (default: 9999)
570
+ defaultPosition: "top-right", // Default position for all toasts (default: "bottom-right")
571
+ disableInlineStyles: false, // Use external CSS mode (default: false)
572
+ reducedMotion: "auto", // Respect prefers-reduced-motion (default: "auto")
573
+ targetNode: document.getElementById("toast-root"), // Custom mount target (default: document.body)
574
+ });
575
+
576
+ // Read current config
577
+ const config = getConfig();
578
+ console.log(config.maxVisible); // 5
579
+
580
+ // Check if animations should be reduced
581
+ if (shouldReduceMotion()) {
582
+ console.log("User prefers reduced motion");
583
+ }
584
+ ```
585
+
586
+ ### Global Config Options
587
+
588
+ | Parameter | Type | Default | Description |
589
+ | ---------------------- | --------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- |
590
+ | `maxVisible` | `number` | `3` | Maximum simultaneously visible toasts. Additional toasts are queued. |
591
+ | `maxQueueSize` | `number` | `100` | Maximum queue capacity for high-frequency bursts. Evicts oldest items to prevent memory bloat and main-thread lock. |
592
+ | `zIndex` | `number` | `9999` | Base z-index for toast containers and toasts. Adjust if toasts appear behind other elements. |
593
+ | `defaultPosition` | `string` | `"bottom-right"` | Default position when individual toast options omit `position`. |
594
+ | `theme` | `"light" \| "dark" \| "high-contrast" \| "compact" \| "spacious" \| "glass"` | `"light"` | Built-in CSS theme applied via `data-toast-theme` on document root. |
595
+ | `stacked` | `boolean` | `false` | Enable iOS-style 3D card deck layout with depth scaling and hover expansion. |
596
+ | `swipeToDismiss` | `boolean` | `true` | Enable touch / mouse drag swipe gesture to dismiss toasts with spring snap-back physics. |
597
+ | `sound` | `boolean` | `true` | Enable pure Web Audio API notification chimes (0KB network, zero audio assets). |
598
+ | `soundPreset` | `"modern" \| "retro" \| "futuristic" \| "subtle" \| "bell"` | `"modern"` | Built-in sound synthesis theme for audio notifications. |
599
+ | `pauseOnHover` | `boolean` | `false` | When `true`, automatically pauses countdown timers for all toasts on mouse hover or keyboard focus. |
600
+ | `syncTabs` | `boolean` | `false` | Synchronize toast notifications across browser tabs using BroadcastChannel. |
601
+ | `aiPrioritization` | `boolean` | `false` | Enable offline content-aware queue priority sorting (critical alerts jump ahead of routine messages). |
602
+ | `priorityScorer` | `((context) => number) \| null` | `null` | Custom priority scoring function for custom business logic or external AI models. |
603
+ | `onMetrics` | `((metrics: ToastMetrics) => void) \| null` | `null` | Real-time telemetry callback emitting `{ activeCount, queueDepth, visibleCount, droppedCount, timestamp }`. |
604
+ | `disableInlineStyles` | `boolean` | `false` | When `true`, toasts use CSS classes instead of inline `style.*` for stricter CSP compliance. |
605
+ | `reducedMotion` | `"auto" \| "always" \| "never"` | `"auto"` | Control animation behavior. `"auto"` respects `prefers-reduced-motion`, `"always"` disables, `"never"` enables. |
606
+ | `targetNode` | `Element \| ShadowRoot \| null` | `null` | Custom DOM node to mount toast containers. Defaults to `document.body` if not provided. |
607
+
608
+ Call `resetConfig()` at any time to restore pristine defaults and clean up DOM attributes.
609
+
610
+ ### Enterprise Telemetry & Real-Time Metrics
611
+
612
+ Inspect live queue depth, active toast count, dropped toasts, and timestamps via `getToastMetrics()` or subscribe reactively via `onMetrics`:
613
+
614
+ ```js
615
+ import { getToastMetrics, setConfig } from "customizable-toast-notification";
616
+
617
+ // 1. Synchronous snapshot
618
+ const metrics = getToastMetrics();
619
+ console.log(`Active: ${metrics.activeCount}, Queued: ${metrics.queueDepth}, Dropped: ${metrics.droppedCount}`);
620
+
621
+ // 2. Real-time telemetry hook
622
+ setConfig({
623
+ onMetrics: (m) => {
624
+ myMonitoringService.track("toast_metrics", m);
625
+ },
626
+ });
627
+ ```
628
+
629
+
630
+ ### Use Cases
631
+
632
+ **Strict Content Security Policy (CSP):**
633
+
634
+ ```js
635
+ // Use external CSS instead of inline styles
636
+ setConfig({ disableInlineStyles: true });
637
+ // Don't forget to import the CSS: import "customizable-toast-notification/dist/index.css"
638
+ ```
639
+
640
+ **Accessibility: Respect User Motion Preferences:**
641
+
642
+ ```js
643
+ // Enable automatic animation reduction
644
+ setConfig({ reducedMotion: "auto" });
645
+
646
+ // Or force reduction for all users
647
+ setConfig({ reducedMotion: "always" });
648
+ ```
649
+
650
+ **Shadow DOM / Scoped Mounting:**
651
+
652
+ ```js
653
+ const shadowHost = document.querySelector("#app");
654
+ const shadowRoot = shadowHost.attachShadow({ mode: "open" });
655
+ shadowRoot.innerHTML = `<style>/* your styles */</style>`;
656
+
657
+ setConfig({ targetNode: shadowRoot });
658
+ createToast({ message: "Mounted in Shadow DOM!" });
659
+ ```
660
+
661
+ **Increase Visible Toasts:**
662
+
663
+ ```js
664
+ // Allow up to 5 toasts instead of 3
665
+ setConfig({ maxVisible: 5 });
666
+ ```
667
+
668
+ **Adjust Z-Index:**
669
+
670
+ ```js
671
+ // If toasts appear behind other elements, increase z-index
672
+ setConfig({ zIndex: 50000 });
673
+ ```
674
+
675
+ ## πŸš€ Phase 3: Advanced Features
676
+
677
+ The following enterprise-grade features are available in v3.16.0+ and are opt-in via global config or toast options:
678
+
679
+ ### πŸ”„ Cross-Tab Toast Synchronization
680
+
681
+ Broadcast toasts to other tabs of the same application using the `BroadcastChannel` API. The first tab becomes the leader and mirrors queued / active toasts to follower tabs.
682
+
683
+ ```js
684
+ import { setConfig, createToast } from "customizable-toast-notification";
685
+
686
+ // Enable cross-tab sync globally
687
+ setConfig({ syncTabs: true });
688
+
689
+ createToast({ message: "Shared across all open tabs!", type: "info" });
690
+ ```
691
+
692
+ Graceful degradation: if `BroadcastChannel` is unavailable (e.g. Node.js or older browsers), the library simply runs in single-tab mode β€” no errors.
693
+
694
+ ### 🧠 AI-Powered Priority Queue Routing
695
+
696
+ When the queue fills (more than `maxVisible` toasts), the `aiPrioritization` flag reorders the queue by urgency instead of strict FIFO. Priority is derived from `type` (error > warning > info > success) plus keyword scoring (`urgent`, `critical`, `failed`, `done`, etc.). Fully offline, zero external calls.
697
+
698
+ ```js
699
+ setConfig({ aiPrioritization: true });
700
+
701
+ createToast({ message: "Payment failed", type: "error" }); // Highest priority
702
+ createToast({ message: "Background sync", type: "info" }); // Queued behind the error
703
+ ```
704
+
705
+ The built-in scorer also exposes `calculateToastPriority(context)` and `categorizeToast(message)` for custom routing integrations.
706
+
707
+ ### πŸƒ Virtual Scrolling β€” DOM Element Pool
708
+
709
+ An internal element-pool recycles toast DOM nodes, so burst queues of 100+ toasts no longer create proportional DOM pressure or trigger layout thrashing / GC spikes. The pool size scales automatically with `MAX_VISIBLE`.
710
+
711
+ No configuration required β€” it's transparent to callers. The queue drains in priority order (when enabled above) and reuses the same recycled elements.
712
+
713
+ ### πŸ‘† Advanced Gestures: Flick Swipe & Pinch-to-Expand
714
+
715
+ Swipe-to-dismiss already exists in Phase 2; Phase 3 refines the physics:
716
+
717
+ - **Flick detection**: velocity β‰₯ 0.65 px/ms over β‰₯ 50 px triggers instant dismiss; anything shorter snaps back with spring easing.
718
+ - **Pinch-to-expand**: two-finger gesture on a toast expands it to full height (useful for long error messages with stack traces); releasing collapses it back.
719
+
720
+ The multi-touch math (`calculateVelocity`, `isFlick`, `detectPinch`) is exported for consumer recipes that want custom gesture behavior.
721
+
722
+ ### πŸ—οΈ How It All Fits Together
723
+
724
+ ```js
725
+ import { setConfig } from "customizable-toast-notification";
726
+
727
+ setConfig({
728
+ maxVisible: 3,
729
+ syncTabs: true, // mirror to other tabs
730
+ aiPrioritization: true,// sort the queue by urgency
731
+ stacked: true, // iOS-style card deck
732
+ swipeToDismiss: true, // flick physics (Phase 2)
733
+ sound: true, // zero-asset Web Audio chimes (Phase 2)
734
+ });
735
+
736
+ createToast({ message: "New notification", type: "success" });
737
+ ```
738
+
739
+ The library keeps its zero-runtime-dependency guarantee: `BroadcastChannel`, Web Audio, and the gesture math are all native browser APIs with immediate graceful fallbacks when unavailable.
740
+
406
741
  ## πŸ’‘ Examples
407
742
 
408
743
  ### Basic Toast Types
@@ -463,6 +798,145 @@ setDefaultMessages({
463
798
  createToast({ type: "success" }); // Uses your custom colors & messages
464
799
  ```
465
800
 
801
+ ### React Integration
802
+
803
+ ```jsx
804
+ import { useCallback } from "react";
805
+ import { createToast, toastPromise, dismiss, setConfig } from "customizable-toast-notification";
806
+
807
+ export function useToast() {
808
+ const showToast = useCallback(
809
+ (type, message, options = {}) =>
810
+ createToast({ type, message, ...options }),
811
+ []
812
+ );
813
+
814
+ return {
815
+ success: (msg, opts) => showToast("success", msg, opts),
816
+ error: (msg, opts) => showToast("error", msg, opts),
817
+ warning: (msg, opts) => showToast("warning", msg, opts),
818
+ info: (msg, opts) => showToast("info", msg, opts),
819
+ promise: toastPromise,
820
+ dismiss: dismiss,
821
+ setConfig: setConfig,
822
+ };
823
+ }
824
+
825
+ // Usage in a component:
826
+ export function MyComponent() {
827
+ const toast = useToast();
828
+
829
+ const handleSave = async () => {
830
+ try {
831
+ await toast.promise(saveData(), {
832
+ loading: "Saving...",
833
+ success: "Saved!",
834
+ error: "Failed to save",
835
+ });
836
+ } catch (err) {
837
+ toast.error(err.message);
838
+ }
839
+ };
840
+
841
+ return <button onClick={handleSave}>Save</button>;
842
+ }
843
+ ```
844
+
845
+ ### Vue Integration
846
+
847
+ ```js
848
+ // composables/useToast.js
849
+ import { createToast, toastPromise, dismiss, setConfig } from "customizable-toast-notification";
850
+
851
+ export function useToast() {
852
+ return {
853
+ success: (message, options = {}) => createToast({ type: "success", message, ...options }),
854
+ error: (message, options = {}) => createToast({ type: "error", message, ...options }),
855
+ warning: (message, options = {}) => createToast({ type: "warning", message, ...options }),
856
+ info: (message, options = {}) => createToast({ type: "info", message, ...options }),
857
+ promise: toastPromise,
858
+ dismiss: dismiss,
859
+ setConfig: setConfig,
860
+ };
861
+ }
862
+
863
+ // Usage in a component:
864
+ <script setup>
865
+ import { useToast } from "@/composables/useToast";
866
+
867
+ const toast = useToast();
868
+
869
+ const handleSave = async () => {
870
+ try {
871
+ await toast.promise(saveData(), {
872
+ loading: "Saving...",
873
+ success: "Saved!",
874
+ error: "Failed to save",
875
+ });
876
+ } catch (err) {
877
+ toast.error(err.message);
878
+ }
879
+ };
880
+ </script>
881
+ ```
882
+
883
+ ### Svelte Integration
884
+
885
+ Use our ready-to-use Svelte store adapter in [`examples/svelte/toastStore.js`](examples/svelte/toastStore.js):
886
+
887
+ ```svelte
888
+ <script>
889
+ import { toast } from "./toastStore.js";
890
+ const { metrics } = toast;
891
+
892
+ async function handleAction() {
893
+ await toast.success("Saved in Svelte!");
894
+ }
895
+ </script>
896
+
897
+ <button on:click={handleAction}>Save</button>
898
+ <p>Active toasts: {$metrics.activeCount}</p>
899
+ ```
900
+
901
+ ### Angular Integration
902
+
903
+ Injectable service in [`examples/angular/toast.service.ts`](examples/angular/toast.service.ts):
904
+
905
+ ```typescript
906
+ import { Component } from '@angular/core';
907
+ import { ToastService } from './toast.service';
908
+
909
+ @Component({
910
+ selector: 'app-root',
911
+ template: `<button (click)="notify()">Notify</button>`,
912
+ })
913
+ export class AppComponent {
914
+ constructor(private toast: ToastService) {}
915
+
916
+ notify() {
917
+ this.toast.success('Saved with Angular DI!');
918
+ }
919
+ }
920
+ ```
921
+
922
+ ### SolidJS Integration
923
+
924
+ Reactive primitive in [`examples/solid/useToast.js`](examples/solid/useToast.js):
925
+
926
+ ```jsx
927
+ import { useToast } from "./useToast";
928
+
929
+ export function Counter() {
930
+ const toast = useToast();
931
+
932
+ return (
933
+ <button onClick={() => toast.info(`Current queue: ${toast.metrics().queueDepth}`)}>
934
+ Check Queue
935
+ </button>
936
+ );
937
+ }
938
+ ```
939
+
466
940
  ### HTML content (sanitized)
467
941
 
468
942
  ```js
@@ -520,6 +994,202 @@ Identical toasts (same type, message, and position) are automatically grouped:
520
994
  - **Formats**: UMD, ES Modules, CommonJS
521
995
  - **TypeScript**: Full type definitions included β€” real autocomplete and type-checking, not just placeholder types
522
996
 
997
+ ### External CSS Mode (Strict CSP Compliance)
998
+
999
+ For environments with strict Content Security Policies that disallow inline `style.*` assignments, import the external CSS file and enable CSS-only mode:
1000
+
1001
+ ```js
1002
+ // JavaScript
1003
+ import "customizable-toast-notification/dist/index.css";
1004
+ import { setConfig, createToast } from "customizable-toast-notification";
1005
+
1006
+ setConfig({ disableInlineStyles: true });
1007
+ createToast({ message: "Using external CSS!" });
1008
+ ```
1009
+
1010
+ ```html
1011
+ <!-- HTML (CDN) -->
1012
+ <link rel="stylesheet" href="https://unpkg.com/customizable-toast-notification@3.16.0/dist/index.css">
1013
+ <script src="https://unpkg.com/customizable-toast-notification@3.16.0/dist/index.umd.js"></script>
1014
+ <script>
1015
+ customizableToast.setConfig({ disableInlineStyles: true });
1016
+ customizableToast.createToast({ message: "Using external CSS!" });
1017
+ </script>
1018
+ ```
1019
+
1020
+ **Note:** Some dynamic features (stacked layout transforms, animated exit transitions) rely on computed inline styles and are not available in strict CSS-only mode. Core toast functionality (appearance, positioning, animations, progress bars) is fully supported.
1021
+
1022
+ ## 🎨 CSS Customization & Themes
1023
+
1024
+ ### CSS Variables (Custom Properties)
1025
+
1026
+ All toast styles can be customized globally via CSS variables. Set them on `:root` for global defaults, or use `data-toast-theme` attribute for theme-specific values:
1027
+
1028
+ ```css
1029
+ :root {
1030
+ /* Colors */
1031
+ --toast-bg: #ffffff;
1032
+ --toast-text: #1a1a1a;
1033
+ --toast-border-radius: 50px;
1034
+ --toast-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
1035
+ --toast-padding: 12px 16px;
1036
+ --toast-min-width: 250px;
1037
+ --toast-max-width: 400px;
1038
+
1039
+ /* Animations */
1040
+ --toast-transition-duration: 0.4s;
1041
+ --toast-transition-timing: ease;
1042
+
1043
+ /* Type-specific Colors */
1044
+ --toast-success-bg: #28a745;
1045
+ --toast-success-text: #ffffff;
1046
+ --toast-error-bg: #dc3545;
1047
+ --toast-error-text: #ffffff;
1048
+ --toast-warning-bg: #ffc107;
1049
+ --toast-warning-text: #000000;
1050
+ --toast-info-bg: #17a2b8;
1051
+ --toast-info-text: #ffffff;
1052
+
1053
+ /* Z-index Stack */
1054
+ --toast-z-index: 9999;
1055
+ --toast-emergency-z-index: 10099;
1056
+
1057
+ /* Spacing */
1058
+ --toast-gap: 10px;
1059
+ --toast-offset: 10px;
1060
+ }
1061
+ ```
1062
+
1063
+ **Example: Custom Dark Theme**
1064
+
1065
+ ```css
1066
+ :root {
1067
+ --toast-bg: #1a1a1a;
1068
+ --toast-text: #f5f5f5;
1069
+ --toast-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
1070
+ --toast-success-bg: #1e7e34;
1071
+ --toast-error-bg: #a71930;
1072
+ }
1073
+ ```
1074
+
1075
+ **Example: Compact Layout**
1076
+
1077
+ ```css
1078
+ :root {
1079
+ --toast-padding: 8px 12px;
1080
+ --toast-min-width: 200px;
1081
+ --toast-max-width: 300px;
1082
+ --toast-border-radius: 6px;
1083
+ }
1084
+ ```
1085
+
1086
+ ### Built-in Themes
1087
+
1088
+ Use the global `setConfig()` API to switch between pre-built themes:
1089
+
1090
+ ```js
1091
+ import { setConfig } from 'customizable-toast-notification';
1092
+ import 'customizable-toast-notification/index.css';
1093
+
1094
+ // Apply theme globally
1095
+ setConfig({ theme: 'dark' });
1096
+ createToast({ message: 'Dark mode enabled!' });
1097
+ ```
1098
+
1099
+ **Available Themes:**
1100
+
1101
+ | Theme | Use Case | Example |
1102
+ |-------|----------|---------|
1103
+ | `light` (default) | Standard bright interface | Default white background |
1104
+ | `dark` | Dark mode apps | Dark background, light text |
1105
+ | `high-contrast` | WCAG AAA accessibility | High contrast borders, colors |
1106
+ | `compact` | Space-constrained UIs | Reduced padding, smaller bounds |
1107
+ | `spacious` | Relaxed, prominent toasts | Larger padding, wider bounds |
1108
+ | `glass` | Modern glassmorphism | Backdrop blur, semi-transparent |
1109
+
1110
+ **Example: High-Contrast Theme**
1111
+
1112
+ ```js
1113
+ setConfig({
1114
+ theme: 'high-contrast',
1115
+ disableInlineStyles: true
1116
+ });
1117
+ createToast({
1118
+ message: 'Accessible toast',
1119
+ type: 'success'
1120
+ });
1121
+ ```
1122
+
1123
+ ### TypeScript Support for CSS Classes
1124
+
1125
+ All CSS class names are automatically typed when you import the CSS file:
1126
+
1127
+ ```ts
1128
+ import { toast, toastMessage, toastCta, toastSuccess } from 'customizable-toast-notification/index.css';
1129
+
1130
+ // βœ… Full autocomplete and type checking
1131
+ console.log(toast); // "toast"
1132
+ console.log(toastSuccess); // "toast-success"
1133
+ ```
1134
+
1135
+ **Available CSS Classes:**
1136
+
1137
+ - **Container:** `toast-container-base`, `toast-position-*` (13 positions)
1138
+ - **Toast:** `toast`, `toast-outer-wrapper`, `toast-inner-wrapper`
1139
+ - **Types:** `toast-success`, `toast-error`, `toast-warning`, `toast-info`
1140
+ - **Content:** `toast-message`, `toast-message-spacer`, `toast-loader`, `toast-loader-circle`
1141
+ - **UI:** `toast-cta`, `toast-close-btn`, `toast-progress-bar`, `toast-count-badge`
1142
+ - **States:** `active`, `is-truncated`
1143
+
1144
+ ### Combining Custom CSS + Global Config
1145
+
1146
+ ```js
1147
+ import { createToast, setConfig } from 'customizable-toast-notification';
1148
+ import 'customizable-toast-notification/index.css';
1149
+
1150
+ // Set theme
1151
+ setConfig({
1152
+ theme: 'dark',
1153
+ maxVisible: 5,
1154
+ defaultPosition: 'top-right'
1155
+ });
1156
+
1157
+ // Override specific variables in your app CSS
1158
+ document.documentElement.style.setProperty('--toast-max-width', '600px');
1159
+ document.documentElement.style.setProperty('--toast-success-bg', '#10b981');
1160
+ ```
1161
+
1162
+ ### CSS Variables Full Reference
1163
+
1164
+ ```css
1165
+ /* Core Dimensions */
1166
+ --toast-padding: 12px 16px;
1167
+ --toast-min-width: 250px;
1168
+ --toast-max-width: 400px;
1169
+ --toast-border-radius: 50px;
1170
+
1171
+ /* Visual Effects */
1172
+ --toast-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
1173
+ --toast-bg: #ffffff;
1174
+ --toast-text: #1a1a1a;
1175
+
1176
+ /* Animations */
1177
+ --toast-transition-duration: 0.4s;
1178
+ --toast-transition-timing: ease;
1179
+
1180
+ /* Type-Specific Colors (6 variants) */
1181
+ --toast-success-bg, --toast-success-text
1182
+ --toast-error-bg, --toast-error-text
1183
+ --toast-warning-bg, --toast-warning-text
1184
+ --toast-info-bg, --toast-info-text
1185
+
1186
+ /* Layout & Positioning */
1187
+ --toast-gap: 10px; /* Space between toasts */
1188
+ --toast-offset: 10px; /* Distance from viewport edge */
1189
+ --toast-z-index: 9999; /* Normal toast z-index */
1190
+ --toast-emergency-z-index: 10099; /* Emergency fallback z-index */
1191
+ ```
1192
+
523
1193
  ## 🀝 Contributing
524
1194
 
525
1195
  Exciting times ahead! Looking for sponsors and eager to explore new collaborations:) . Contributions are welcome! Please read our [Contributing Guidelines](CONTRIBUTING.md) for details.
@@ -533,6 +1203,13 @@ npm install
533
1203
  npm run zone-build
534
1204
  ```
535
1205
 
1206
+ ## πŸ“š Documentation & Cookbooks
1207
+
1208
+ - 🍳 **[Developer Cookbook](docs/COOKBOOK.md)** β€” Production recipes for Multi-Action CTAs, Network Status monitoring, Global Error Boundaries, and Streaming file uploads.
1209
+ - πŸ“– **[API Reference](docs/API.md)** β€” Complete API documentation for all methods, configurations, and events.
1210
+ - πŸ”Œ **[Integration Guide](docs/INTEGRATION_GUIDE.md)** β€” Framework integration guides for React, Vue, Svelte, Angular, and SolidJS.
1211
+ - ⚑ **[Performance Guide](docs/PERFORMANCE.md)** β€” CSS containment, GPU compositor acceleration, and memory benchmarking.
1212
+
536
1213
  ## πŸ“„ License
537
1214
 
538
1215
  This project is licensed under the [Apache-2.0 License](LICENSE).