customizable-toast-notification 3.11.4 → 3.12.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [3.12.0](https://github.com/sammy-cool/customizable-toast-notification/compare/v3.11.5...v3.12.0) (2026-08-31)
2
+
3
+
4
+ ### Features
5
+
6
+ * add toastPromise() and targeted per-toast dismissal handles ([2acd46a](https://github.com/sammy-cool/customizable-toast-notification/commit/2acd46a7b004ff68e078f5a08b4be1cc1d4e3ce7))
7
+
8
+ ## [3.11.5](https://github.com/sammy-cool/customizable-toast-notification/compare/v3.11.4...v3.11.5) (2026-08-23)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * correct README defaults and add real TypeScript types ([8f262d3](https://github.com/sammy-cool/customizable-toast-notification/commit/8f262d387363cc7931b8431594d9147fd45ef2c1))
14
+
1
15
  ## [3.11.4](https://github.com/sammy-cool/customizable-toast-notification/compare/v3.11.3...v3.11.4) (2026-08-19)
2
16
 
3
17
 
package/README.md CHANGED
@@ -5,24 +5,26 @@
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
6
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/customizable-toast-notification)](https://bundlephobia.com/package/customizable-toast-notification)
7
7
 
8
- A **lightweight**, **zero-dependency** toast notification library for modern JavaScript applications. Built with production-grade reliability and comprehensive secret mechanisms.
8
+ **[▶ Try the live demo](https://sammy-cool.github.io/customizable-toast-notification/)** — click a button, watch a real toast fire, sanitized HTML included.
9
+
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.
9
11
 
10
12
  ## ✨ Key Features
11
13
 
12
- - 🚫 **Zero Dependencies** - Pure JavaScript with no external requirements Lightweight and fast
13
- - 🛡️ **Production Ready** - Reliable and scalable for production environments
14
- - 🎨 **Highly Customizable** - Colors, positions, animations, progress bars
15
- - 🌐 **Framework Agnostic** - Works with React, Vue, Angular, or vanilla JS
16
- - 📱 **Responsive** - Works on all screen sizes and devices
17
- - ⚡ **CDN Ready** - Easy integration via CDN or npm
18
- - 🎨 **Fully Customizable** - Colors, positions, animations, and styling
19
- - ♿ **Accessible** - ARIA live regions and keyboard navigation support
20
- - 🔄 **Smart Grouping** - Duplicate notifications are automatically grouped with badges
21
- - ⏸️ **Pause on Hover** - CTA toasts pause when user hovers or focuses
22
- - 🎯 **Call-to-Action** - Built-in support for interactive buttons and links
14
+ - 🌐 **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
+ - 🛡️ **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"
17
+ - 🚫 **Zero Runtime Dependencies** - Nothing pulled in when your users load your app
18
+ - 🔧 **Real TypeScript Types** - Full type definitions with real autocomplete and type-checking, not a placeholder `any`
19
+ - 🎨 **Highly Customizable** - Colors, positions, animations, progress bars, and styling
20
+ - ♿ **Accessible** - ARIA live regions, keyboard navigation, and WCAG-contrast text color computed automatically
21
+ - 🔄 **Smart Grouping** - Duplicate notifications are automatically grouped with a count badge instead of stacking
22
+ - ⏸️ **Pause on Hover** - CTA toasts pause on hover or keyboard focus
23
+ - 🎯 **Call-to-Action** - Built-in button or link CTA, with optional async `onClick`
24
+ - ⏳ **Promise-based Toasts** - `toastPromise()` shows loading → success/error automatically, transparently passing through the original resolved value or error
23
25
  - 📊 **Queue Management** - Maximum 3 visible toasts with intelligent queueing
24
26
  - 🌈 **Multiple Themes** - Success, error, warning, and info styles
25
- - 🔧 **TypeScript Ready** - TypeScript definitions included Full type support (coming soon)
27
+ - ⚡ **CDN Ready** - One `<script>` tag, no build step, no npm required
26
28
 
27
29
  ## 📦 Installation
28
30
 
@@ -42,29 +44,31 @@ yarn add customizable-toast-notification
42
44
 
43
45
  ### ES Modules
44
46
 
45
- ```bash
46
-
47
- import { createToast, setDefaultColors, setDefaultMessages } from 'customizable-toast-notification';
47
+ ```js
48
+ import {
49
+ createToast,
50
+ setDefaultColors,
51
+ setDefaultMessages,
52
+ } from "customizable-toast-notification";
48
53
 
49
54
  // Simple usage
50
55
  createToast({
51
- message: "Hello World!",
52
- type: "success",
53
- duration: 3000
56
+ message: "Hello World!",
57
+ type: "success",
58
+ duration: 3000,
54
59
  });
55
-
56
60
  ```
57
61
 
58
62
  ### CDN/Browser (UMD Build) / Quick Try with jsDelivr
59
63
 
60
- ```bash
61
- Global Variable Name: customizableToast
64
+ Global Variable Name: `customizableToast`
62
65
 
66
+ ```html
63
67
  <!-- Always latest version -->
64
68
  <script src="https://cdn.jsdelivr.net/npm/customizable-toast-notification/dist/index.umd.js"></script>
65
69
 
66
70
  <!-- OR pin to a specific version (recommended for stability) -->
67
- <script src="https://cdn.jsdelivr.net/npm/customizable-toast-notification@3.9.5/dist/index.umd.js"></script>
71
+ <script src="https://cdn.jsdelivr.net/npm/customizable-toast-notification@3.11.4/dist/index.umd.js"></script>
68
72
 
69
73
  <script>
70
74
  // Access the global UMD export
@@ -77,46 +81,60 @@ Global Variable Name: customizableToast
77
81
  animationEasing: "ease",
78
82
  progressPosition: "top",
79
83
  cta: {
80
- autoClose: false,
81
- label: "Check Pkg!",
82
- href: "https://www.npmjs.com/package/customizable-toast-notification",
83
- variant: "link",
84
- target: "_blank"
85
- }
84
+ autoClose: false,
85
+ label: "Check Pkg!",
86
+ href: "https://www.npmjs.com/package/customizable-toast-notification",
87
+ variant: "link",
88
+ target: "_blank",
89
+ },
86
90
  });
87
91
  </script>
88
-
89
92
  ```
90
93
 
91
94
  ## 📖 API Reference
92
95
 
93
96
  ### `createToast(options)`
94
97
 
95
- Creates and displays a toast notification.
98
+ Creates and displays a toast notification. Returns a handle for
99
+ dismissing _that specific toast_ later — useful when other toasts might
100
+ be created in between:
101
+
102
+ ```js
103
+ const handle = await createToast({ message: "Uploading...", duration: 60000 });
104
+
105
+ // later, regardless of what else has happened on screen since:
106
+ await handle.dismiss();
107
+ ```
108
+
109
+ `handle.dismiss()` is always safe to call, even if the toast already
110
+ auto-dismissed on its own — it no-ops rather than throwing.
96
111
 
97
112
  #### Options
98
113
 
99
- | Parameter | Type | Default | Description |
100
- | ------------------- | --------- | ----------------------- | --------------------------------------------------------- |
101
- | `message` | `string` | Based on `type` | Toast message content |
102
- | `type` | `string` | `"info"` | `"info"`, `"success"`, `"error"`, `"warning"` |
103
- | `duration` | `number` | `3000` | Auto-dismiss time in milliseconds |
104
- | `position` | `string` | `"bottom-right"` | Toast position on screen |
105
- | `backgroundColor` | `string` | Based on `type` | Custom background color |
106
- | `textColor` | `string` | `"white"` | Custom text color |
107
- | `showCloseButton` | `boolean` | `false` | Show close (×) button |
108
- | `showProgressBar` | `boolean` | `false` | Show countdown progress bar |
109
- | `animationDuration` | `string` | `"0.5s"` | CSS animation duration |
110
- | `animationEasing` | `string` | `"ease"` | CSS animation easing function |
111
- | `progressColor` | `string` | `rgba(255,255,255,0.3)` | Progress bar color |
112
- | `progressHeight` | `string` | `"4px"` | Progress bar height |
113
- | `progressPosition` | `string` | `"bottom"` | Progress bar position: `"top"` or `"bottom"` |
114
- | `pauseOnHover` | `boolean` | `auto` | Pause timer on hover (auto: true for CTA toasts) |
115
- | `cta` | `object` | `null` | Call-to-action configuration (see [CTA](#call-to-action)) |
114
+ | Parameter | Type | Default | Description |
115
+ | ------------------- | --------- | ------------------------------- | --------------------------------------------------------- |
116
+ | `message` | `string` | Based on `type` | Toast message content |
117
+ | `type` | `string` | `"info"` | `"info"`, `"success"`, `"error"`, `"warning"` |
118
+ | `duration` | `number` | `2500` | Auto-dismiss time in milliseconds |
119
+ | `position` | `string` | `"bottom-right"` | Toast position on screen |
120
+ | `borderRadius` | `string` | `"50px"` | Toast corner radius |
121
+ | `backgroundColor` | `string` | Based on `type` | Custom background color |
122
+ | `textColor` | `string` | Auto-computed for WCAG contrast | Custom text color |
123
+ | `showCloseButton` | `boolean` | `true` | Show close (×) button |
124
+ | `showProgressBar` | `boolean` | `true` | Show countdown progress bar |
125
+ | `animationDuration` | `string` | `"0.4s"` | CSS animation duration |
126
+ | `animationEasing` | `string` | `"ease"` | CSS animation easing function |
127
+ | `progressColor` | `string` | Falls back to `textColor` | Progress bar color |
128
+ | `progressHeight` | `string` | `"4px"` | Progress bar height |
129
+ | `progressPosition` | `string` | `"bottom"` | Progress bar position: `"top"` or `"bottom"` |
130
+ | `pauseOnHover` | `boolean` | `auto` | Pause timer on hover (auto: true for CTA toasts) |
131
+ | `allowHtml` | `boolean` | `false` | Render `message` as sanitized HTML instead of plain text |
132
+ | `wrapText` | `string` | `"normal"` | `"normal"` wraps naturally; falsy truncates to 3 lines |
133
+ | `cta` | `object` | `null` | Call-to-action configuration (see [CTA](#call-to-action)) |
116
134
 
117
135
  #### Position Options
118
136
 
119
- ```bash
137
+ ```
120
138
  // Corner positions
121
139
  - "top-left", "top-right", "bottom-left", "bottom-right"
122
140
 
@@ -128,105 +146,177 @@ Creates and displays a toast notification.
128
146
 
129
147
  // Center
130
148
  - "center"
131
-
132
149
  ```
133
150
 
134
151
  ## 🎯 Call-to-Action (CTA)
135
152
 
136
153
  Add interactive buttons or links to your toasts:
137
154
 
138
- ```bash
155
+ ```js
139
156
  // Button CTA
140
157
  createToast({
141
- message: "File uploaded successfully!",
142
- type: "success",
143
- cta: {
144
- label: "View File",
145
- onClick: () => {
146
- window.open('/files/latest');
147
- },
148
- autoClose: true // Close toast after click (default: true)
149
- }
158
+ message: "File uploaded successfully!",
159
+ type: "success",
160
+ cta: {
161
+ label: "View File",
162
+ onClick: () => {
163
+ window.open("/files/latest");
164
+ },
165
+ autoClose: true, // Close toast after click (default: true)
166
+ },
150
167
  });
151
168
 
152
169
  // Link CTA
153
170
  createToast({
154
- message: "New version available!",
155
- cta: {
156
- label: "Download",
157
- href: "https://example.com/download",
158
- variant: "link",
159
- target: "_blank"
160
- }
171
+ message: "New version available!",
172
+ cta: {
173
+ label: "Download",
174
+ href: "https://example.com/download",
175
+ variant: "link",
176
+ target: "_blank",
177
+ },
161
178
  });
162
179
 
163
180
  // Advanced CTA with async action
164
181
  createToast({
165
- message: "Ready to sync your data?",
166
- cta: {
167
- label: "Sync Now",
168
- ariaLabel: "Start data synchronization",
169
- autoClose: false,
170
- onClick: async () => {
171
- await performDataSync();
172
- // Manually close if needed
173
- }
174
- }
182
+ message: "Ready to sync your data?",
183
+ cta: {
184
+ label: "Sync Now",
185
+ ariaLabel: "Start data synchronization",
186
+ autoClose: false,
187
+ onClick: async () => {
188
+ await performDataSync();
189
+ // Manually close if needed
190
+ },
191
+ },
175
192
  });
176
-
177
193
  ```
178
194
 
179
- ### CTA Options
180
-
181
- | Parameter | Type | Default | Description |
182
- | ----------- | ---------- | ---------- | ------------------------------ |
183
- | `label` | `string` | `required` | Button/link text |
184
- | `onClick` | `function` | `null` | Click handler (for buttons) |
185
- | `href` | `string` | `null` | URL (for links) |
186
- | `variant` | `string` | `"button"` | `"button"` or `"link"` |
187
- | `target` | `string` | `null` | Link target (`"_blank"`, etc.) |
188
- | `rel` | `string` | `auto` | Link relationship |
189
- | `autoClose` | `boolean` | `true` | Close toast after CTA click |
190
- | `ariaLabel` | `string` | `label` | Accessibility label |
195
+ Any toast with a `cta` automatically gets `pauseOnHover: true` unless you override it.
191
196
 
192
- ## 🎨 Examples
197
+ ### CTA Options
193
198
 
194
- ### All Toast Types
199
+ | Parameter | Type | Default | Description |
200
+ | ----------- | ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------ |
201
+ | `label` | `string` | `"CTA Label Missing!"` if omitted | Button/link text |
202
+ | `onClick` | `function` | `null` | Click handler (for buttons); may be async — the toast waits for it to resolve before auto-closing |
203
+ | `href` | `string` | `null` | URL (for links) |
204
+ | `variant` | `string` | `"button"` | `"button"` or `"link"` |
205
+ | `target` | `string` | `null` | Link target (`"_blank"`, etc.) |
206
+ | `rel` | `string` | `auto` | Link relationship — `target="_blank"` automatically gets `rel="noopener noreferrer"` unless you set your own |
207
+ | `autoClose` | `boolean` | `true` | Close toast after CTA click |
208
+ | `ariaLabel` | `string` | `label` | Accessibility label |
195
209
 
196
210
  ### `setDefaultColors(colors)`
197
211
 
198
- ```bash
199
-
200
212
  Configure default colors for toast types.
201
213
 
214
+ ```js
202
215
  setDefaultColors({
203
- success: "#10b981",
204
- error: "#ef4444",
205
- warning: "#f59e0b",
206
- info: "#3b82f6"
216
+ success: "#10b981",
217
+ error: "#ef4444",
218
+ warning: "#f59e0b",
219
+ info: "#3b82f6",
207
220
  });
208
-
209
221
  ```
210
222
 
211
223
  ### `setDefaultMessages(messages)`
212
224
 
213
- ```bash
214
225
  Configure default messages for toast types.
215
226
 
227
+ ```js
216
228
  setDefaultMessages({
217
- success: "Operation completed successfully!",
218
- error: "Something went wrong!",
219
- warning: "Please check your input!",
220
- info: "Here's some information!"
229
+ success: "Operation completed successfully!",
230
+ error: "Something went wrong!",
231
+ warning: "Please check your input!",
232
+ info: "Here's some information!",
221
233
  });
234
+ ```
235
+
236
+ ## ⏳ Promise-based Toasts
222
237
 
238
+ Show a loading toast that automatically swaps to success or error once an
239
+ async operation settles — no manual dismiss/create juggling required:
240
+
241
+ ```js
242
+ import { toastPromise } from "customizable-toast-notification";
243
+
244
+ await toastPromise(
245
+ saveUserData(), // any Promise
246
+ {
247
+ loading: "Saving...",
248
+ success: "Saved successfully!",
249
+ error: "Failed to save.",
250
+ },
251
+ );
252
+ ```
253
+
254
+ Messages can also be functions, receiving the resolved value or the caught
255
+ error:
256
+
257
+ ```js
258
+ await toastPromise(
259
+ fetch("/api/user").then((r) => r.json()),
260
+ {
261
+ loading: "Loading profile...",
262
+ success: (user) => `Welcome back, ${user.name}!`,
263
+ error: (err) => `Couldn't load profile: ${err.message}`,
264
+ },
265
+ );
266
+
267
+ // A function that returns a promise works too — called immediately
268
+ await toastPromise(() => fetch("/api/save", { method: "POST" }), {
269
+ loading: "Saving...",
270
+ success: "Saved!",
271
+ error: "Save failed.",
272
+ });
273
+ ```
274
+
275
+ `toastPromise` resolves or rejects with whatever the original promise did —
276
+ it's a thin UI layer on top of a promise you're already awaiting, not a
277
+ replacement for your own error handling:
278
+
279
+ ```js
280
+ try {
281
+ const result = await toastPromise(riskyOperation(), {
282
+ /* ... */
283
+ });
284
+ // result is the real resolved value
285
+ } catch (err) {
286
+ // err is the real original error — toastPromise re-throws it
287
+ }
223
288
  ```
224
289
 
290
+ A third argument accepts any normal toast options (position, colors, etc.),
291
+ applied to all three phases:
292
+
293
+ ```js
294
+ await toastPromise(
295
+ syncData(),
296
+ { loading: "Syncing...", success: "Synced!", error: "Sync failed." },
297
+ { position: "top-center" },
298
+ );
299
+ ```
300
+
301
+ ### `toastPromise` reference
302
+
303
+ | Parameter | Type | Description |
304
+ | ------------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
305
+ | `promiseOrFn` | `Promise \| () => Promise` | The operation to track. A function is called immediately. |
306
+ | `messages.loading` | `string` | Default: `"Loading..."` |
307
+ | `messages.success` | `string \| (value) => string` | Default: `"Done!"` |
308
+ | `messages.error` | `string \| (error) => string` | Default: `"Something went wrong."` |
309
+ | `options` | `ToastOptions` | Applied to the loading, success, and error toasts. `type` and `message` are controlled by this function and can't be overridden here. |
310
+
311
+ The loading toast doesn't use `duration` from `options` — it stays until
312
+ the promise settles, then is replaced by a success or error toast that
313
+ does respect the normal duration/auto-dismiss behavior.
314
+
225
315
  ## 💡 Examples
226
316
 
227
317
  ### Basic Toast Types
228
318
 
229
- ```bash
319
+ ```js
230
320
  // Success
231
321
  createToast({ type: "success", message: "Data saved!" });
232
322
 
@@ -238,50 +328,61 @@ createToast({ type: "warning", message: "Please confirm!" });
238
328
 
239
329
  // Info
240
330
  createToast({ type: "info", message: "New update available!" });
241
-
242
331
  ```
243
332
 
244
333
  ### Advanced Customization
245
334
 
246
- ```bash
335
+ ```js
247
336
  createToast({
248
- message: "File uploading...",
249
- type: "info",
250
- duration: 5000,
251
- position: "top-center",
252
- showProgressBar: true,
253
- showCloseButton: true,
254
- backgroundColor: "#6366f1",
255
- textColor: "white",
256
- progressColor: "#e0e7ff",
257
- progressPosition: "top",
258
- animationDuration: "0.8s",
259
- animationEasing: "ease-out"
337
+ message: "File uploading...",
338
+ type: "info",
339
+ duration: 5000,
340
+ position: "top-center",
341
+ showProgressBar: true,
342
+ showCloseButton: true,
343
+ backgroundColor: "#6366f1",
344
+ textColor: "white",
345
+ progressColor: "#e0e7ff",
346
+ progressPosition: "top",
347
+ animationDuration: "0.8s",
348
+ animationEasing: "ease-out",
260
349
  });
350
+ ```
261
351
 
262
352
  ### App-wide Configuration
263
353
 
354
+ ```js
264
355
  // Set your brand colors once
265
356
  setDefaultColors({
266
- success: "#10b981", // Your brand green
267
- error: "#ef4444", // Your brand red
268
- warning: "#f59e0b", // Your brand yellow
269
- info: "#3b82f6" // Your brand blue
357
+ success: "#10b981", // Your brand green
358
+ error: "#ef4444", // Your brand red
359
+ warning: "#f59e0b", // Your brand yellow
360
+ info: "#3b82f6", // Your brand blue
270
361
  });
271
362
 
272
363
  // Set your app messages
273
364
  setDefaultMessages({
274
- success: "✅ Success! Changes saved.",
275
- error: "❌ Error! Please try again.",
276
- warning: "⚠️ Warning! Check your input.",
277
- info: "💡 Info! Here's a tip."
365
+ success: "✅ Success! Changes saved.",
366
+ error: "❌ Error! Please try again.",
367
+ warning: "⚠️ Warning! Check your input.",
368
+ info: "💡 Info! Here's a tip.",
278
369
  });
279
370
 
280
371
  // Now just use types throughout your app
281
372
  createToast({ type: "success" }); // Uses your custom colors & messages
373
+ ```
282
374
 
375
+ ### HTML content (sanitized)
376
+
377
+ ```js
378
+ createToast({
379
+ message: '<b>Bold text</b> and a <a href="https://example.com">link</a>',
380
+ allowHtml: true,
381
+ });
283
382
  ```
284
383
 
384
+ `allowHtml` content is always sanitized before rendering — `<script>` tags, event-handler attributes, and `javascript:` URIs are stripped regardless. Uses [DOMPurify](https://github.com/cure53/DOMPurify) automatically if it's loaded on the page, otherwise a built-in fallback sanitizer with the same allowlist.
385
+
285
386
  ## 🔄 Advanced Features
286
387
 
287
388
  ### Smart Grouping
@@ -301,7 +402,7 @@ Identical toasts (same type, message, and position) are automatically grouped:
301
402
  ### Accessibility
302
403
 
303
404
  - ARIA live regions announce new toasts to screen readers
304
- - Keyboard navigation support (Tab, Enter, Escape)
405
+ - Keyboard navigation support (Tab, Enter, Escape — Escape dismisses the most recent toast)
305
406
  - High contrast badge design
306
407
  - Semantic HTML structure
307
408
 
@@ -309,10 +410,9 @@ Identical toasts (same type, message, and position) are automatically grouped:
309
410
 
310
411
  ### Production-Grade System
311
412
 
312
- - \*\*Rich toast → Basic toast → Emergency alert
413
+ - **Layered fallback**: Rich toast → Basic toast → Emergency alert
313
414
  - **Zero-Crash Guarantee**: Comprehensive error handling prevents application crashes
314
415
  - **Memory Management**: Automatic cleanup prevents memory leaks
315
- - **CDN Cache-Busting**: Ensures fresh content delivery
316
416
 
317
417
  ### Browser Compatibility
318
418
 
@@ -324,10 +424,10 @@ Identical toasts (same type, message, and position) are automatically grouped:
324
424
 
325
425
  ## 📁 Bundle Information
326
426
 
327
- - **Size**: ~8KB minified, ~4KB gzipped
427
+ - **Size**: see the live bundle size badge above (auto-updates from the published package)
328
428
  - **Dependencies**: Zero
329
- - **Formats**: UMD, ES Modules
330
- - **TypeScript**: Definitions included (full coming soon)
429
+ - **Formats**: UMD, ES Modules, CommonJS
430
+ - **TypeScript**: Full type definitions included — real autocomplete and type-checking, not just placeholder types
331
431
 
332
432
  ## 🤝 Contributing
333
433
 
@@ -336,12 +436,10 @@ Exciting times ahead! Looking for sponsors and eager to explore new collaboratio
336
436
  ### Development Setup
337
437
 
338
438
  ```bash
339
-
340
439
  git clone https://github.com/sammy-cool/customizable-toast-notification.git
341
440
  cd customizable-toast-notification
342
441
  npm install
343
- npm run build
344
-
442
+ npm run zone-build
345
443
  ```
346
444
 
347
445
  ## 📄 License