customizable-toast-notification 3.14.0 β†’ 3.16.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,13 +1,40 @@
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 132 automated unit & end-to-end tests across Chromium, Firefox, and WebKit.
11
38
 
12
39
  ## ✨ Key Features
13
40
 
@@ -158,9 +185,13 @@ auto-dismissed on its own β€” they no-op gracefully rather than throwing.
158
185
  | `className` | `string` | `undefined` | Custom CSS class name(s) for animations / styling |
159
186
  | `stacked` | `boolean` | `false` | Enable iOS-style card deck stacking for multiple toasts |
160
187
  | `sound` | `boolean \| string`| `false` | Zero-asset audio chime (`true`, `'success'`, `'error'`, `'warning'`, `'pop'`) |
188
+ | `soundPreset` | `string` | `"modern"` | Audio synth theme: `"modern"`, `"retro"`, `"futuristic"`, `"subtle"`, `"bell"` |
161
189
  | `swipeToDismiss` | `boolean` | `true` | Mobile touch swipe-to-dismiss gesture with physics |
162
190
  | `progress` | `number` | `undefined` | Explicit progress bar percentage (0 to 100) |
191
+ | `usePool` | `boolean` | `false` | Virtual element pooling for DOM recycling in high-frequency rendering |
163
192
  | `cta` | `object` | `null` | Call-to-action configuration (see [CTA](#call-to-action)) |
193
+ | `undo` | `function \| object`| `null` | Action Undo button with live dynamic countdown badge (see [Undo](#️-action-undo-with-live-countdown)) |
194
+ | `spring` | `boolean \| string \| object`| `null` | Configurable spring physics animations (see [Spring Physics](#-configurable-spring-physics-animation-engine)) |
164
195
 
165
196
  #### Position Options
166
197
 
@@ -220,6 +251,22 @@ createToast({
220
251
  },
221
252
  },
222
253
  });
254
+
255
+ // Multi-Action CTAs (Dual actions e.g. Accept / Decline)
256
+ createToast({
257
+ message: "Project invite from Priya Patel",
258
+ cta: [
259
+ {
260
+ label: "Accept",
261
+ onClick: async () => await acceptInvitation(),
262
+ },
263
+ {
264
+ label: "Decline",
265
+ autoClose: true,
266
+ onClick: async () => await declineInvitation(),
267
+ },
268
+ ],
269
+ });
223
270
  ```
224
271
 
225
272
  Any toast with a `cta` automatically gets `pauseOnHover: true` unless you override it.
@@ -237,6 +284,75 @@ Any toast with a `cta` automatically gets `pauseOnHover: true` unless you overri
237
284
  | `autoClose` | `boolean` | `true` | Close toast after CTA click |
238
285
  | `ariaLabel` | `string` | `label` | Accessibility label |
239
286
 
287
+ ### ↩️ Action Undo with Live Countdown
288
+
289
+ Allow users to immediately reverse actions (e.g. "Item deleted", "Message archived") with a dynamic, decaying countdown badge:
290
+
291
+ ```js
292
+ createToast({
293
+ message: "Conversation moved to trash",
294
+ type: "warning",
295
+ duration: 5000,
296
+ undo: {
297
+ label: "Undo",
298
+ showCountdown: true, // displays "Undo (5s)... (4s)..."
299
+ onUndo: async (e, toast) => {
300
+ await restoreConversation();
301
+ console.log("Restored!");
302
+ },
303
+ },
304
+ });
305
+
306
+ // Or concise callback shorthand:
307
+ createToast({
308
+ message: "Draft deleted",
309
+ undo: () => restoreDraft(),
310
+ });
311
+ ```
312
+
313
+ | Parameter | Type | Default | Description |
314
+ | --------- | ---- | ------- | ----------- |
315
+ | `label` | `string` | `"Undo"` | Button text label |
316
+ | `showCountdown` | `boolean` | `true` | Decays remaining duration in seconds in real-time |
317
+ | `onUndo` | `function` | `undefined` | Callback fired on click; supports async promises before auto-closing toast |
318
+
319
+ ### πŸŒ€ Configurable Spring Physics Animation Engine
320
+
321
+ Replaces standard transitions with damped harmonic oscillator physics:
322
+
323
+ ```js
324
+ // Use built-in presets: 'default', 'gentle', 'wobbly', 'stiff', 'bouncy'
325
+ createToast({
326
+ message: "Synced to cloud",
327
+ spring: "bouncy",
328
+ });
329
+
330
+ // Or customize exact physical constants:
331
+ createToast({
332
+ message: "Physics simulated notification",
333
+ spring: {
334
+ stiffness: 180, // Spring tension (k)
335
+ damping: 12, // Friction resistance (c)
336
+ mass: 1.2, // Inertial mass (m)
337
+ },
338
+ });
339
+ ```
340
+
341
+ | Preset | Stiffness ($k$) | Damping ($c$) | Mass ($m$) | Behavior |
342
+ | ------ | --------------- | ------------- | ---------- | -------- |
343
+ | `default` | 100 | 10 | 1 | Natural subtle bounce |
344
+ | `gentle` | 120 | 14 | 1 | Smooth with minimal overshoot |
345
+ | `wobbly` | 180 | 12 | 1 | Playful oscillation |
346
+ | `stiff` | 210 | 20 | 1 | Crisp, rapid settling |
347
+ | `bouncy` | 300 | 15 | 1.2 | High energy with dynamic bounce |
348
+
349
+ Register custom global presets or resolve spring curves directly:
350
+ ```js
351
+ import { registerSpringPreset, getSpringTransition } from "customizable-toast-notification";
352
+
353
+ registerSpringPreset("snappy", { stiffness: 250, damping: 22, mass: 1 });
354
+ ```
355
+
240
356
  ### Loader Options
241
357
 
242
358
  Add an animated SVG spinner directly alongside the message:
@@ -403,6 +519,187 @@ The loading toast doesn't use `duration` from `options` β€” it stays until
403
519
  the promise settles, then is replaced by a success or error toast that
404
520
  does respect the normal duration/auto-dismiss behavior.
405
521
 
522
+ ## βš™οΈ Global Configuration
523
+
524
+ Configure library-wide defaults using `setConfig()` and check current settings with `getConfig()`:
525
+
526
+ ```js
527
+ import { setConfig, getConfig, shouldReduceMotion } from "customizable-toast-notification";
528
+
529
+ // Configure global defaults
530
+ setConfig({
531
+ maxVisible: 5, // Max simultaneously visible toasts (default: 3)
532
+ zIndex: 10000, // Base z-index for containers (default: 9999)
533
+ defaultPosition: "top-right", // Default position for all toasts (default: "bottom-right")
534
+ disableInlineStyles: false, // Use external CSS mode (default: false)
535
+ reducedMotion: "auto", // Respect prefers-reduced-motion (default: "auto")
536
+ targetNode: document.getElementById("toast-root"), // Custom mount target (default: document.body)
537
+ });
538
+
539
+ // Read current config
540
+ const config = getConfig();
541
+ console.log(config.maxVisible); // 5
542
+
543
+ // Check if animations should be reduced
544
+ if (shouldReduceMotion()) {
545
+ console.log("User prefers reduced motion");
546
+ }
547
+ ```
548
+
549
+ ### Global Config Options
550
+
551
+ | Parameter | Type | Default | Description |
552
+ | ---------------------- | --------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- |
553
+ | `maxVisible` | `number` | `3` | Maximum simultaneously visible toasts. Additional toasts are queued. |
554
+ | `maxQueueSize` | `number` | `100` | Maximum queue capacity for high-frequency bursts. Evicts oldest items to prevent memory bloat and main-thread lock. |
555
+ | `zIndex` | `number` | `9999` | Base z-index for toast containers and toasts. Adjust if toasts appear behind other elements. |
556
+ | `defaultPosition` | `string` | `"bottom-right"` | Default position when individual toast options omit `position`. |
557
+ | `theme` | `"light" \| "dark" \| "high-contrast" \| "compact" \| "spacious" \| "glass"` | `"light"` | Built-in CSS theme applied via `data-toast-theme` on document root. |
558
+ | `stacked` | `boolean` | `false` | Enable iOS-style 3D card deck layout with depth scaling and hover expansion. |
559
+ | `swipeToDismiss` | `boolean` | `true` | Enable touch / mouse drag swipe gesture to dismiss toasts with spring snap-back physics. |
560
+ | `sound` | `boolean` | `true` | Enable pure Web Audio API notification chimes (0KB network, zero audio assets). |
561
+ | `soundPreset` | `"modern" \| "retro" \| "futuristic" \| "subtle" \| "bell"` | `"modern"` | Built-in sound synthesis theme for audio notifications. |
562
+ | `syncTabs` | `boolean` | `false` | Synchronize toast notifications across browser tabs using BroadcastChannel. |
563
+ | `aiPrioritization` | `boolean` | `false` | Enable offline content-aware queue priority sorting (critical alerts jump ahead of routine messages). |
564
+ | `priorityScorer` | `((context) => number) \| null` | `null` | Custom priority scoring function for custom business logic or external AI models. |
565
+ | `onMetrics` | `((metrics: ToastMetrics) => void) \| null` | `null` | Real-time telemetry callback emitting `{ activeCount, queueDepth, visibleCount, droppedCount, timestamp }`. |
566
+ | `disableInlineStyles` | `boolean` | `false` | When `true`, toasts use CSS classes instead of inline `style.*` for stricter CSP compliance. |
567
+ | `reducedMotion` | `"auto" \| "always" \| "never"` | `"auto"` | Control animation behavior. `"auto"` respects `prefers-reduced-motion`, `"always"` disables, `"never"` enables. |
568
+ | `targetNode` | `Element \| ShadowRoot \| null` | `null` | Custom DOM node to mount toast containers. Defaults to `document.body` if not provided. |
569
+
570
+ Call `resetConfig()` at any time to restore pristine defaults and clean up DOM attributes.
571
+
572
+ ### Enterprise Telemetry & Real-Time Metrics
573
+
574
+ Inspect live queue depth, active toast count, dropped toasts, and timestamps via `getToastMetrics()` or subscribe reactively via `onMetrics`:
575
+
576
+ ```js
577
+ import { getToastMetrics, setConfig } from "customizable-toast-notification";
578
+
579
+ // 1. Synchronous snapshot
580
+ const metrics = getToastMetrics();
581
+ console.log(`Active: ${metrics.activeCount}, Queued: ${metrics.queueDepth}, Dropped: ${metrics.droppedCount}`);
582
+
583
+ // 2. Real-time telemetry hook
584
+ setConfig({
585
+ onMetrics: (m) => {
586
+ myMonitoringService.track("toast_metrics", m);
587
+ },
588
+ });
589
+ ```
590
+
591
+
592
+ ### Use Cases
593
+
594
+ **Strict Content Security Policy (CSP):**
595
+
596
+ ```js
597
+ // Use external CSS instead of inline styles
598
+ setConfig({ disableInlineStyles: true });
599
+ // Don't forget to import the CSS: import "customizable-toast-notification/dist/index.css"
600
+ ```
601
+
602
+ **Accessibility: Respect User Motion Preferences:**
603
+
604
+ ```js
605
+ // Enable automatic animation reduction
606
+ setConfig({ reducedMotion: "auto" });
607
+
608
+ // Or force reduction for all users
609
+ setConfig({ reducedMotion: "always" });
610
+ ```
611
+
612
+ **Shadow DOM / Scoped Mounting:**
613
+
614
+ ```js
615
+ const shadowHost = document.querySelector("#app");
616
+ const shadowRoot = shadowHost.attachShadow({ mode: "open" });
617
+ shadowRoot.innerHTML = `<style>/* your styles */</style>`;
618
+
619
+ setConfig({ targetNode: shadowRoot });
620
+ createToast({ message: "Mounted in Shadow DOM!" });
621
+ ```
622
+
623
+ **Increase Visible Toasts:**
624
+
625
+ ```js
626
+ // Allow up to 5 toasts instead of 3
627
+ setConfig({ maxVisible: 5 });
628
+ ```
629
+
630
+ **Adjust Z-Index:**
631
+
632
+ ```js
633
+ // If toasts appear behind other elements, increase z-index
634
+ setConfig({ zIndex: 50000 });
635
+ ```
636
+
637
+ ## πŸš€ Phase 3: Advanced Features
638
+
639
+ The following enterprise-grade features are available in v3.15.0+ and are opt-in via global config or toast options:
640
+
641
+ ### πŸ”„ Cross-Tab Toast Synchronization
642
+
643
+ 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.
644
+
645
+ ```js
646
+ import { setConfig, createToast } from "customizable-toast-notification";
647
+
648
+ // Enable cross-tab sync globally
649
+ setConfig({ syncTabs: true });
650
+
651
+ createToast({ message: "Shared across all open tabs!", type: "info" });
652
+ ```
653
+
654
+ Graceful degradation: if `BroadcastChannel` is unavailable (e.g. Node.js or older browsers), the library simply runs in single-tab mode β€” no errors.
655
+
656
+ ### 🧠 AI-Powered Priority Queue Routing
657
+
658
+ 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.
659
+
660
+ ```js
661
+ setConfig({ aiPrioritization: true });
662
+
663
+ createToast({ message: "Payment failed", type: "error" }); // Highest priority
664
+ createToast({ message: "Background sync", type: "info" }); // Queued behind the error
665
+ ```
666
+
667
+ The built-in scorer also exposes `calculateToastPriority(context)` and `categorizeToast(message)` for custom routing integrations.
668
+
669
+ ### πŸƒ Virtual Scrolling β€” DOM Element Pool
670
+
671
+ 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`.
672
+
673
+ No configuration required β€” it's transparent to callers. The queue drains in priority order (when enabled above) and reuses the same recycled elements.
674
+
675
+ ### πŸ‘† Advanced Gestures: Flick Swipe & Pinch-to-Expand
676
+
677
+ Swipe-to-dismiss already exists in Phase 2; Phase 3 refines the physics:
678
+
679
+ - **Flick detection**: velocity β‰₯ 0.65 px/ms over β‰₯ 50 px triggers instant dismiss; anything shorter snaps back with spring easing.
680
+ - **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.
681
+
682
+ The multi-touch math (`calculateVelocity`, `isFlick`, `detectPinch`) is exported for consumer recipes that want custom gesture behavior.
683
+
684
+ ### πŸ—οΈ How It All Fits Together
685
+
686
+ ```js
687
+ import { setConfig } from "customizable-toast-notification";
688
+
689
+ setConfig({
690
+ maxVisible: 3,
691
+ syncTabs: true, // mirror to other tabs
692
+ aiPrioritization: true,// sort the queue by urgency
693
+ stacked: true, // iOS-style card deck
694
+ swipeToDismiss: true, // flick physics (Phase 2)
695
+ sound: true, // zero-asset Web Audio chimes (Phase 2)
696
+ });
697
+
698
+ createToast({ message: "New notification", type: "success" });
699
+ ```
700
+
701
+ 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.
702
+
406
703
  ## πŸ’‘ Examples
407
704
 
408
705
  ### Basic Toast Types
@@ -463,6 +760,145 @@ setDefaultMessages({
463
760
  createToast({ type: "success" }); // Uses your custom colors & messages
464
761
  ```
465
762
 
763
+ ### React Integration
764
+
765
+ ```jsx
766
+ import { useCallback } from "react";
767
+ import { createToast, toastPromise, dismiss, setConfig } from "customizable-toast-notification";
768
+
769
+ export function useToast() {
770
+ const showToast = useCallback(
771
+ (type, message, options = {}) =>
772
+ createToast({ type, message, ...options }),
773
+ []
774
+ );
775
+
776
+ return {
777
+ success: (msg, opts) => showToast("success", msg, opts),
778
+ error: (msg, opts) => showToast("error", msg, opts),
779
+ warning: (msg, opts) => showToast("warning", msg, opts),
780
+ info: (msg, opts) => showToast("info", msg, opts),
781
+ promise: toastPromise,
782
+ dismiss: dismiss,
783
+ setConfig: setConfig,
784
+ };
785
+ }
786
+
787
+ // Usage in a component:
788
+ export function MyComponent() {
789
+ const toast = useToast();
790
+
791
+ const handleSave = async () => {
792
+ try {
793
+ await toast.promise(saveData(), {
794
+ loading: "Saving...",
795
+ success: "Saved!",
796
+ error: "Failed to save",
797
+ });
798
+ } catch (err) {
799
+ toast.error(err.message);
800
+ }
801
+ };
802
+
803
+ return <button onClick={handleSave}>Save</button>;
804
+ }
805
+ ```
806
+
807
+ ### Vue Integration
808
+
809
+ ```js
810
+ // composables/useToast.js
811
+ import { createToast, toastPromise, dismiss, setConfig } from "customizable-toast-notification";
812
+
813
+ export function useToast() {
814
+ return {
815
+ success: (message, options = {}) => createToast({ type: "success", message, ...options }),
816
+ error: (message, options = {}) => createToast({ type: "error", message, ...options }),
817
+ warning: (message, options = {}) => createToast({ type: "warning", message, ...options }),
818
+ info: (message, options = {}) => createToast({ type: "info", message, ...options }),
819
+ promise: toastPromise,
820
+ dismiss: dismiss,
821
+ setConfig: setConfig,
822
+ };
823
+ }
824
+
825
+ // Usage in a component:
826
+ <script setup>
827
+ import { useToast } from "@/composables/useToast";
828
+
829
+ const toast = useToast();
830
+
831
+ const handleSave = async () => {
832
+ try {
833
+ await toast.promise(saveData(), {
834
+ loading: "Saving...",
835
+ success: "Saved!",
836
+ error: "Failed to save",
837
+ });
838
+ } catch (err) {
839
+ toast.error(err.message);
840
+ }
841
+ };
842
+ </script>
843
+ ```
844
+
845
+ ### Svelte Integration
846
+
847
+ Use our ready-to-use Svelte store adapter in [`examples/svelte/toastStore.js`](examples/svelte/toastStore.js):
848
+
849
+ ```svelte
850
+ <script>
851
+ import { toast } from "./toastStore.js";
852
+ const { metrics } = toast;
853
+
854
+ async function handleAction() {
855
+ await toast.success("Saved in Svelte!");
856
+ }
857
+ </script>
858
+
859
+ <button on:click={handleAction}>Save</button>
860
+ <p>Active toasts: {$metrics.activeCount}</p>
861
+ ```
862
+
863
+ ### Angular Integration
864
+
865
+ Injectable service in [`examples/angular/toast.service.ts`](examples/angular/toast.service.ts):
866
+
867
+ ```typescript
868
+ import { Component } from '@angular/core';
869
+ import { ToastService } from './toast.service';
870
+
871
+ @Component({
872
+ selector: 'app-root',
873
+ template: `<button (click)="notify()">Notify</button>`,
874
+ })
875
+ export class AppComponent {
876
+ constructor(private toast: ToastService) {}
877
+
878
+ notify() {
879
+ this.toast.success('Saved with Angular DI!');
880
+ }
881
+ }
882
+ ```
883
+
884
+ ### SolidJS Integration
885
+
886
+ Reactive primitive in [`examples/solid/useToast.js`](examples/solid/useToast.js):
887
+
888
+ ```jsx
889
+ import { useToast } from "./useToast";
890
+
891
+ export function Counter() {
892
+ const toast = useToast();
893
+
894
+ return (
895
+ <button onClick={() => toast.info(`Current queue: ${toast.metrics().queueDepth}`)}>
896
+ Check Queue
897
+ </button>
898
+ );
899
+ }
900
+ ```
901
+
466
902
  ### HTML content (sanitized)
467
903
 
468
904
  ```js
@@ -520,6 +956,202 @@ Identical toasts (same type, message, and position) are automatically grouped:
520
956
  - **Formats**: UMD, ES Modules, CommonJS
521
957
  - **TypeScript**: Full type definitions included β€” real autocomplete and type-checking, not just placeholder types
522
958
 
959
+ ### External CSS Mode (Strict CSP Compliance)
960
+
961
+ For environments with strict Content Security Policies that disallow inline `style.*` assignments, import the external CSS file and enable CSS-only mode:
962
+
963
+ ```js
964
+ // JavaScript
965
+ import "customizable-toast-notification/dist/index.css";
966
+ import { setConfig, createToast } from "customizable-toast-notification";
967
+
968
+ setConfig({ disableInlineStyles: true });
969
+ createToast({ message: "Using external CSS!" });
970
+ ```
971
+
972
+ ```html
973
+ <!-- HTML (CDN) -->
974
+ <link rel="stylesheet" href="https://unpkg.com/customizable-toast-notification@3.15.0/dist/index.css">
975
+ <script src="https://unpkg.com/customizable-toast-notification@3.15.0/dist/index.umd.js"></script>
976
+ <script>
977
+ customizableToast.setConfig({ disableInlineStyles: true });
978
+ customizableToast.createToast({ message: "Using external CSS!" });
979
+ </script>
980
+ ```
981
+
982
+ **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.
983
+
984
+ ## 🎨 CSS Customization & Themes
985
+
986
+ ### CSS Variables (Custom Properties)
987
+
988
+ 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:
989
+
990
+ ```css
991
+ :root {
992
+ /* Colors */
993
+ --toast-bg: #ffffff;
994
+ --toast-text: #1a1a1a;
995
+ --toast-border-radius: 50px;
996
+ --toast-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
997
+ --toast-padding: 12px 16px;
998
+ --toast-min-width: 250px;
999
+ --toast-max-width: 400px;
1000
+
1001
+ /* Animations */
1002
+ --toast-transition-duration: 0.4s;
1003
+ --toast-transition-timing: ease;
1004
+
1005
+ /* Type-specific Colors */
1006
+ --toast-success-bg: #28a745;
1007
+ --toast-success-text: #ffffff;
1008
+ --toast-error-bg: #dc3545;
1009
+ --toast-error-text: #ffffff;
1010
+ --toast-warning-bg: #ffc107;
1011
+ --toast-warning-text: #000000;
1012
+ --toast-info-bg: #17a2b8;
1013
+ --toast-info-text: #ffffff;
1014
+
1015
+ /* Z-index Stack */
1016
+ --toast-z-index: 9999;
1017
+ --toast-emergency-z-index: 10099;
1018
+
1019
+ /* Spacing */
1020
+ --toast-gap: 10px;
1021
+ --toast-offset: 10px;
1022
+ }
1023
+ ```
1024
+
1025
+ **Example: Custom Dark Theme**
1026
+
1027
+ ```css
1028
+ :root {
1029
+ --toast-bg: #1a1a1a;
1030
+ --toast-text: #f5f5f5;
1031
+ --toast-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
1032
+ --toast-success-bg: #1e7e34;
1033
+ --toast-error-bg: #a71930;
1034
+ }
1035
+ ```
1036
+
1037
+ **Example: Compact Layout**
1038
+
1039
+ ```css
1040
+ :root {
1041
+ --toast-padding: 8px 12px;
1042
+ --toast-min-width: 200px;
1043
+ --toast-max-width: 300px;
1044
+ --toast-border-radius: 6px;
1045
+ }
1046
+ ```
1047
+
1048
+ ### Built-in Themes
1049
+
1050
+ Use the global `setConfig()` API to switch between pre-built themes:
1051
+
1052
+ ```js
1053
+ import { setConfig } from 'customizable-toast-notification';
1054
+ import 'customizable-toast-notification/index.css';
1055
+
1056
+ // Apply theme globally
1057
+ setConfig({ theme: 'dark' });
1058
+ createToast({ message: 'Dark mode enabled!' });
1059
+ ```
1060
+
1061
+ **Available Themes:**
1062
+
1063
+ | Theme | Use Case | Example |
1064
+ |-------|----------|---------|
1065
+ | `light` (default) | Standard bright interface | Default white background |
1066
+ | `dark` | Dark mode apps | Dark background, light text |
1067
+ | `high-contrast` | WCAG AAA accessibility | High contrast borders, colors |
1068
+ | `compact` | Space-constrained UIs | Reduced padding, smaller bounds |
1069
+ | `spacious` | Relaxed, prominent toasts | Larger padding, wider bounds |
1070
+ | `glass` | Modern glassmorphism | Backdrop blur, semi-transparent |
1071
+
1072
+ **Example: High-Contrast Theme**
1073
+
1074
+ ```js
1075
+ setConfig({
1076
+ theme: 'high-contrast',
1077
+ disableInlineStyles: true
1078
+ });
1079
+ createToast({
1080
+ message: 'Accessible toast',
1081
+ type: 'success'
1082
+ });
1083
+ ```
1084
+
1085
+ ### TypeScript Support for CSS Classes
1086
+
1087
+ All CSS class names are automatically typed when you import the CSS file:
1088
+
1089
+ ```ts
1090
+ import { toast, toastMessage, toastCta, toastSuccess } from 'customizable-toast-notification/index.css';
1091
+
1092
+ // βœ… Full autocomplete and type checking
1093
+ console.log(toast); // "toast"
1094
+ console.log(toastSuccess); // "toast-success"
1095
+ ```
1096
+
1097
+ **Available CSS Classes:**
1098
+
1099
+ - **Container:** `toast-container-base`, `toast-position-*` (13 positions)
1100
+ - **Toast:** `toast`, `toast-outer-wrapper`, `toast-inner-wrapper`
1101
+ - **Types:** `toast-success`, `toast-error`, `toast-warning`, `toast-info`
1102
+ - **Content:** `toast-message`, `toast-message-spacer`, `toast-loader`, `toast-loader-circle`
1103
+ - **UI:** `toast-cta`, `toast-close-btn`, `toast-progress-bar`, `toast-count-badge`
1104
+ - **States:** `active`, `is-truncated`
1105
+
1106
+ ### Combining Custom CSS + Global Config
1107
+
1108
+ ```js
1109
+ import { createToast, setConfig } from 'customizable-toast-notification';
1110
+ import 'customizable-toast-notification/index.css';
1111
+
1112
+ // Set theme
1113
+ setConfig({
1114
+ theme: 'dark',
1115
+ maxVisible: 5,
1116
+ defaultPosition: 'top-right'
1117
+ });
1118
+
1119
+ // Override specific variables in your app CSS
1120
+ document.documentElement.style.setProperty('--toast-max-width', '600px');
1121
+ document.documentElement.style.setProperty('--toast-success-bg', '#10b981');
1122
+ ```
1123
+
1124
+ ### CSS Variables Full Reference
1125
+
1126
+ ```css
1127
+ /* Core Dimensions */
1128
+ --toast-padding: 12px 16px;
1129
+ --toast-min-width: 250px;
1130
+ --toast-max-width: 400px;
1131
+ --toast-border-radius: 50px;
1132
+
1133
+ /* Visual Effects */
1134
+ --toast-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
1135
+ --toast-bg: #ffffff;
1136
+ --toast-text: #1a1a1a;
1137
+
1138
+ /* Animations */
1139
+ --toast-transition-duration: 0.4s;
1140
+ --toast-transition-timing: ease;
1141
+
1142
+ /* Type-Specific Colors (6 variants) */
1143
+ --toast-success-bg, --toast-success-text
1144
+ --toast-error-bg, --toast-error-text
1145
+ --toast-warning-bg, --toast-warning-text
1146
+ --toast-info-bg, --toast-info-text
1147
+
1148
+ /* Layout & Positioning */
1149
+ --toast-gap: 10px; /* Space between toasts */
1150
+ --toast-offset: 10px; /* Distance from viewport edge */
1151
+ --toast-z-index: 9999; /* Normal toast z-index */
1152
+ --toast-emergency-z-index: 10099; /* Emergency fallback z-index */
1153
+ ```
1154
+
523
1155
  ## 🀝 Contributing
524
1156
 
525
1157
  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 +1165,13 @@ npm install
533
1165
  npm run zone-build
534
1166
  ```
535
1167
 
1168
+ ## πŸ“š Documentation & Cookbooks
1169
+
1170
+ - 🍳 **[Developer Cookbook](docs/COOKBOOK.md)** β€” Production recipes for Multi-Action CTAs, Network Status monitoring, Global Error Boundaries, and Streaming file uploads.
1171
+ - πŸ“– **[API Reference](docs/API.md)** β€” Complete API documentation for all methods, configurations, and events.
1172
+ - πŸ”Œ **[Integration Guide](docs/INTEGRATION_GUIDE.md)** β€” Framework integration guides for React, Vue, Svelte, Angular, and SolidJS.
1173
+ - ⚑ **[Performance Guide](docs/PERFORMANCE.md)** β€” CSS containment, GPU compositor acceleration, and memory benchmarking.
1174
+
536
1175
  ## πŸ“„ License
537
1176
 
538
1177
  This project is licensed under the [Apache-2.0 License](LICENSE).