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/CHANGELOG.md +67 -0
- package/README.md +643 -4
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +2 -0
- package/dist/index.css.d.ts +50 -0
- package/dist/index.css.map +7 -0
- package/dist/index.d.ts +586 -6
- package/dist/index.esm.mjs +3 -3
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.umd.js +3 -3
- package/dist/index.umd.js.map +1 -1
- package/package.json +16 -5
package/README.md
CHANGED
|
@@ -1,13 +1,40 @@
|
|
|
1
1
|
# π Customizable Toast Notifications
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-

|
|
3
|
+
[](https://www.npmjs.com/package/customizable-toast-notification)
|
|
4
|
+
[](https://www.npmjs.com/package/customizable-toast-notification)
|
|
5
5
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
|
+
[](package.json)
|
|
6
7
|
[](https://bundlephobia.com/package/customizable-toast-notification)
|
|
8
|
+
[](dist/index.d.ts)
|
|
9
|
+
[](.github/workflows/codeql.yml)
|
|
10
|
+
[](https://stackblitz.com/edit/customizable-toast-notification-demo?file=index.html)
|
|
7
11
|
|
|
8
|
-
**[βΆ Try the live
|
|
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
|
-
|
|
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).
|