@tsirosgeorge/toastnotification 5.6.0 → 6.0.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 +20 -1
- package/assets/css/toast.css +53 -24
- package/assets/css/toast.min.css +1 -1
- package/package.json +6 -4
- package/toast.d.ts +3 -2
- package/toast.js +40 -35
- package/toast.min.js +1 -1
- package/toast.module.js +40 -35
- package/assets/img/error.gif +0 -0
- package/assets/img/error.png +0 -0
- package/assets/img/info.gif +0 -0
- package/assets/img/info.png +0 -0
- package/assets/img/success.gif +0 -0
- package/assets/img/success.png +0 -0
- package/assets/img/warning.gif +0 -0
- package/assets/img/warning.png +0 -0
package/Readme.md
CHANGED
|
@@ -159,6 +159,25 @@ const t = toast.loading('Uploading…', { type: 'info' });
|
|
|
159
159
|
t.update('Done!', { type: 'success', duration: 2000 });
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
+
## ⬆️ Upgrading to 6.0.0
|
|
163
|
+
|
|
164
|
+
**`message` is now rendered as text, not HTML.** Before 6.0.0 it went through `innerHTML`,
|
|
165
|
+
so a message assembled from a database field, a form value or an API response could run
|
|
166
|
+
JavaScript on your page — `<img src=x onerror="…">` is enough, and `<script>` tags are not
|
|
167
|
+
required. That default is now off.
|
|
168
|
+
|
|
169
|
+
If you deliberately put markup in a message, add `allowHtml: true` to those calls:
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
toast('Saved <b>invoice.pdf</b>', { allowHtml: true }); // markup you wrote
|
|
173
|
+
toast(serverResponse.error); // untrusted — leave it as text
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Icons are inline SVG.** The four animated GIFs (323 kB, and a network request per toast)
|
|
177
|
+
are gone; the glyph is now drawn on once as the toast appears. The package went from
|
|
178
|
+
531 kB to 135 kB, icons appear instantly, and the library no longer fetches images at all.
|
|
179
|
+
`assets/img/` is no longer published.
|
|
180
|
+
|
|
162
181
|
## 🛠️ Available Options
|
|
163
182
|
|
|
164
183
|
| Option | Type | Default | Description |
|
|
@@ -172,7 +191,7 @@ t.update('Done!', { type: 'success', duration: 2000 });
|
|
|
172
191
|
| `pauseOnHover` | `boolean` | `true` | Freeze the countdown while the pointer or keyboard focus is on the toast. |
|
|
173
192
|
| `showProgress` | `boolean` | `false` | Thin bar counting the remaining time down. Needs `duration > 0`; pauses with `pauseOnHover`. |
|
|
174
193
|
| `action` | `object` or `null` | `null` | `{ text, onClick }` renders a button inside the toast, e.g. Undo. Clicking it runs `onClick` and closes the toast. |
|
|
175
|
-
| `allowHtml` | `boolean` | `
|
|
194
|
+
| `allowHtml` | `boolean` | `false` | Render `message` as HTML instead of text. Turn it on only for markup you wrote yourself: a string built from user input becomes executable HTML. |
|
|
176
195
|
| `closeOnEscape` | `boolean` | `true` | Confirm dialogs only. Escape cancels the dialog. |
|
|
177
196
|
| `onClick` | `function` or `null` | `null` | Callback function executed when the toast is clicked. |
|
|
178
197
|
| `onShow` | `function` or `null` | `null` | Callback function executed when the toast appears (after it's added to the DOM and shown). |
|
package/assets/css/toast.css
CHANGED
|
@@ -213,14 +213,6 @@
|
|
|
213
213
|
font-size: 1.2rem;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
.ts-toast-container .ts-toast-success .ts-toast-icon {
|
|
217
|
-
color: var(--toast-success-color, #66ee78);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.ts-toast-container .ts-toast-error .ts-toast-icon {
|
|
221
|
-
color: var(--toast-error-color, #ef4444);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
216
|
/* Existing toast styles... */
|
|
225
217
|
|
|
226
218
|
/* Loader styles */
|
|
@@ -256,18 +248,6 @@
|
|
|
256
248
|
transition: opacity 0.5s ease;
|
|
257
249
|
}
|
|
258
250
|
|
|
259
|
-
.ts-toast-container .ts-toast-icon {
|
|
260
|
-
font-size: 1.2rem;
|
|
261
|
-
opacity: 0;
|
|
262
|
-
transition: opacity 0.5s ease;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/* Show the icon after the loader has completed */
|
|
266
|
-
.ts-toast-container .ts-toast.ts-toast-show .ts-toast-icon {
|
|
267
|
-
opacity: 1;
|
|
268
|
-
/* Fade in the icon */
|
|
269
|
-
}
|
|
270
|
-
|
|
271
251
|
@keyframes progress-bar {
|
|
272
252
|
0% {
|
|
273
253
|
width: 0%;
|
|
@@ -343,15 +323,13 @@
|
|
|
343
323
|
.ts-toast-overlay.bottom-center { align-items: flex-end; justify-content: center; padding: 1rem; }
|
|
344
324
|
.ts-toast-overlay.bottom-right { align-items: flex-end; justify-content: flex-end; padding: 1rem; }
|
|
345
325
|
.ts-toast-overlay.center { align-items: center; justify-content: center; padding: 1rem; }
|
|
326
|
+
/* A dialog opening over another must not dim the page a second time. */
|
|
327
|
+
.ts-toast-overlay.ts-toast-overlay-stacked { background: transparent; }
|
|
346
328
|
|
|
347
329
|
/* Tiny utility: flex icon container */
|
|
348
330
|
/* Scoped utility to avoid conflicts */
|
|
349
|
-
.ts-toast-d-flex { display: inline-flex; align-items: center; }
|
|
350
331
|
|
|
351
332
|
/* Prevent scroll behind confirm overlay */
|
|
352
|
-
body.ts-toast-no-scroll {
|
|
353
|
-
overflow: hidden;
|
|
354
|
-
}
|
|
355
333
|
|
|
356
334
|
/* Progress bar counting down the remaining time */
|
|
357
335
|
@keyframes ts-toast-progress {
|
|
@@ -398,3 +376,54 @@ body.ts-toast-no-scroll {
|
|
|
398
376
|
.ts-toast-container .ts-toast-action:hover {
|
|
399
377
|
background: var(--toast-action-hover, rgba(59, 130, 246, 0.12));
|
|
400
378
|
}
|
|
379
|
+
|
|
380
|
+
/* ---- Icons ---- */
|
|
381
|
+
/* Inline SVG, drawn on once when the toast appears. The glyph is a stroked path, so
|
|
382
|
+
animating stroke-dashoffset draws it; the dots fade and pop in alongside. */
|
|
383
|
+
.ts-toast-icon svg {
|
|
384
|
+
width: 30px;
|
|
385
|
+
height: 30px;
|
|
386
|
+
display: block;
|
|
387
|
+
overflow: visible;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.ts-toast-icon .ts-toast-ring { fill: currentColor; }
|
|
391
|
+
|
|
392
|
+
.ts-toast-icon .ts-toast-glyph {
|
|
393
|
+
fill: none;
|
|
394
|
+
stroke: var(--toast-glyph-color, #fff);
|
|
395
|
+
stroke-width: 2.6;
|
|
396
|
+
stroke-linecap: round;
|
|
397
|
+
stroke-linejoin: round;
|
|
398
|
+
stroke-dasharray: var(--ts-len);
|
|
399
|
+
animation: ts-toast-draw 420ms ease-out 1 both;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.ts-toast-icon .ts-toast-dot {
|
|
403
|
+
fill: var(--toast-glyph-color, #fff);
|
|
404
|
+
transform-origin: center;
|
|
405
|
+
animation: ts-toast-pop 420ms ease-out 1 both;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
@keyframes ts-toast-draw {
|
|
409
|
+
from { stroke-dashoffset: var(--ts-len); }
|
|
410
|
+
to { stroke-dashoffset: 0; }
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
@keyframes ts-toast-pop {
|
|
414
|
+
from { opacity: 0; transform: scale(0.3); }
|
|
415
|
+
to { opacity: 1; transform: scale(1); }
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* Someone who asked for less motion gets the finished icon, not a drawing of it. */
|
|
419
|
+
@media (prefers-reduced-motion: reduce) {
|
|
420
|
+
.ts-toast-icon .ts-toast-glyph,
|
|
421
|
+
.ts-toast-icon .ts-toast-dot { animation: none; }
|
|
422
|
+
.ts-toast-icon .ts-toast-glyph { stroke-dashoffset: 0; }
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Icon colours, matching the palette of the GIFs these replaced. */
|
|
426
|
+
.ts-toast-success .ts-toast-icon { color: var(--toast-success-color, #86e08a); }
|
|
427
|
+
.ts-toast-error .ts-toast-icon { color: var(--toast-error-color, #e8635e); }
|
|
428
|
+
.ts-toast-info .ts-toast-icon { color: var(--toast-info-color, #6fc8ef); }
|
|
429
|
+
.ts-toast-warning .ts-toast-icon { color: var(--toast-warning-color, #f7e07a); }
|
package/assets/css/toast.min.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.ts-toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:10px;pointer-events:none;width:fit-content;max-width:calc(100% - 2rem)}.ts-toast-container>:not(:last-child){margin-bottom:0!important}.ts-toast-container.top-right{top:1rem;right:1rem;align-items:flex-end}.ts-toast-container.top-left{top:1rem;left:1rem;align-items:flex-start}.ts-toast-container.top-center{top:1rem;left:50%;transform:translateX(-50%);align-items:center}.ts-toast-container.bottom-right{bottom:1rem;right:1rem;align-items:flex-end}.ts-toast-container.bottom-left{bottom:1rem;left:1rem;align-items:flex-start}.ts-toast-container.bottom-center{bottom:1rem;left:50%;transform:translateX(-50%);align-items:center}.ts-toast-container.center{top:50%;left:50%;transform:translate(-50%,-50%);align-items:center}.ts-toast-container .ts-toast{display:flex;align-items:center;gap:.75rem;background-color:var(--toast-bg,#fff);color:var(--toast-color,#000);padding:.75rem 1rem;border-radius:8px;border:1px solid var(--toast-border,#e5e7eb);box-shadow:var(--toast-shadow,0 10px 15px -3px rgba(0,0,0,.1));font-family:sans-serif;font-size:.95rem;pointer-events:all;position:relative;opacity:0;transform:translateY(20px);transition:opacity .5s ease,transform .5s ease;width:auto!important}.ts-toast.ts-toast-confirm{display:flex;align-items:center;justify-content:center;background-color:var(--toast-bg,#fff);color:var(--toast-color,#000);border:1px solid var(--toast-border,#e5e7eb);border-radius:12px;padding:16px 20px;box-shadow:var(--toast-shadow,0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1));transition:opacity .5s ease,transform .5s ease}.ts-toast.ts-toast-confirm .ts-toast-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;text-align:center}.ts-toast.ts-toast-confirm .ts-toast-body{text-align:center}.ts-toast-actions{display:flex;gap:10px;justify-content:center;margin-top:12px}.ts-toast-input{width:100%;padding:8px 12px;border:1px solid var(--toast-border,#e5e7eb);border-radius:8px;font-family:inherit;font-size:.95rem;margin-top:12px;background:var(--toast-bg,#fff);color:var(--toast-color,#000);outline:0;transition:border-color .2s ease}.ts-toast-input:focus{border-color:#3b82f6}.ts-toast-container .ts-toast.ts-toast-show{opacity:1;transform:translateY(0)}@keyframes ts-toast-slide-left{from{transform:translateX(-100%)}to{transform:translateX(0)}}@keyframes ts-toast-slide-right{from{transform:translateX(100%)}to{transform:translateX(0)}}@keyframes ts-toast-slide-top{from{transform:translateY(-100%)}to{transform:translateY(0)}}@keyframes ts-toast-slide-bottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes ts-toast-zoom-in{from{transform:scale(0)}to{transform:scale(1)}}@keyframes ts-toast-zoom-out{from{transform:scale(1)}to{transform:scale(0)}}@keyframes ts-toast-flip{from{transform:rotateY(90deg)}to{transform:rotateY(0)}}.ts-toast-container .ts-toast-icon{font-size:1.2rem}.ts-toast-container .ts-toast-
|
|
1
|
+
.ts-toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:10px;pointer-events:none;width:fit-content;max-width:calc(100% - 2rem)}.ts-toast-container>:not(:last-child){margin-bottom:0!important}.ts-toast-container.top-right{top:1rem;right:1rem;align-items:flex-end}.ts-toast-container.top-left{top:1rem;left:1rem;align-items:flex-start}.ts-toast-container.top-center{top:1rem;left:50%;transform:translateX(-50%);align-items:center}.ts-toast-container.bottom-right{bottom:1rem;right:1rem;align-items:flex-end}.ts-toast-container.bottom-left{bottom:1rem;left:1rem;align-items:flex-start}.ts-toast-container.bottom-center{bottom:1rem;left:50%;transform:translateX(-50%);align-items:center}.ts-toast-container.center{top:50%;left:50%;transform:translate(-50%,-50%);align-items:center}.ts-toast-container .ts-toast{display:flex;align-items:center;gap:.75rem;background-color:var(--toast-bg,#fff);color:var(--toast-color,#000);padding:.75rem 1rem;border-radius:8px;border:1px solid var(--toast-border,#e5e7eb);box-shadow:var(--toast-shadow,0 10px 15px -3px rgba(0,0,0,.1));font-family:sans-serif;font-size:.95rem;pointer-events:all;position:relative;opacity:0;transform:translateY(20px);transition:opacity .5s ease,transform .5s ease;width:auto!important}.ts-toast.ts-toast-confirm{display:flex;align-items:center;justify-content:center;background-color:var(--toast-bg,#fff);color:var(--toast-color,#000);border:1px solid var(--toast-border,#e5e7eb);border-radius:12px;padding:16px 20px;box-shadow:var(--toast-shadow,0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1));transition:opacity .5s ease,transform .5s ease}.ts-toast.ts-toast-confirm .ts-toast-content{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;text-align:center}.ts-toast.ts-toast-confirm .ts-toast-body{text-align:center}.ts-toast-actions{display:flex;gap:10px;justify-content:center;margin-top:12px}.ts-toast-input{width:100%;padding:8px 12px;border:1px solid var(--toast-border,#e5e7eb);border-radius:8px;font-family:inherit;font-size:.95rem;margin-top:12px;background:var(--toast-bg,#fff);color:var(--toast-color,#000);outline:0;transition:border-color .2s ease}.ts-toast-input:focus{border-color:#3b82f6}.ts-toast-container .ts-toast.ts-toast-show{opacity:1;transform:translateY(0)}@keyframes ts-toast-slide-left{from{transform:translateX(-100%)}to{transform:translateX(0)}}@keyframes ts-toast-slide-right{from{transform:translateX(100%)}to{transform:translateX(0)}}@keyframes ts-toast-slide-top{from{transform:translateY(-100%)}to{transform:translateY(0)}}@keyframes ts-toast-slide-bottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes ts-toast-zoom-in{from{transform:scale(0)}to{transform:scale(1)}}@keyframes ts-toast-zoom-out{from{transform:scale(1)}to{transform:scale(0)}}@keyframes ts-toast-flip{from{transform:rotateY(90deg)}to{transform:rotateY(0)}}.ts-toast-container .ts-toast-icon{font-size:1.2rem}.ts-toast-container .ts-toast-loader{width:20px;height:20px;border:3px solid #f3f3f3;border-top:3px solid var(--toast-loader-color,#66ee78);border-radius:50%;animation:ts-toast-spin 1s linear infinite}@keyframes ts-toast-spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.ts-toast-container .ts-toast-loader.done{animation:none;opacity:0;transition:opacity .5s ease}@keyframes progress-bar{0%{width:0%}100%{width:100%}}@keyframes ts-toast-slide-top-reverse{from{transform:translateY(0)}to{transform:translateY(-100%)}}@keyframes ts-toast-slide-bottom-reverse{from{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes ts-toast-slide-left-reverse{from{transform:translateX(0)}to{transform:translateX(-100%)}}@keyframes ts-toast-slide-right-reverse{from{transform:translateX(0)}to{transform:translateX(100%)}}.ts-toast.ts-toast-slide-out{opacity:0}.ts-toast-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:2147483646}.ts-toast-overlay.top-left{align-items:flex-start;justify-content:flex-start;padding:1rem}.ts-toast-overlay.top-center{align-items:flex-start;justify-content:center;padding:1rem}.ts-toast-overlay.top-right{align-items:flex-start;justify-content:flex-end;padding:1rem}.ts-toast-overlay.bottom-left{align-items:flex-end;justify-content:flex-start;padding:1rem}.ts-toast-overlay.bottom-center{align-items:flex-end;justify-content:center;padding:1rem}.ts-toast-overlay.bottom-right{align-items:flex-end;justify-content:flex-end;padding:1rem}.ts-toast-overlay.center{align-items:center;justify-content:center;padding:1rem}.ts-toast-overlay.ts-toast-overlay-stacked{background:0 0}@keyframes ts-toast-progress{from{transform:scaleX(1)}to{transform:scaleX(0)}}.ts-toast-container .ts-toast-progress{position:absolute;left:0;right:0;bottom:0;height:3px;transform-origin:left center;border-radius:0 0 8px 8px;background:var(--toast-progress-color,currentColor);opacity:.35;pointer-events:none}.ts-toast-container .ts-toast-success .ts-toast-progress{background:var(--toast-success-color,#17a35c)}.ts-toast-container .ts-toast-error .ts-toast-progress{background:var(--toast-error-color,#ef4444)}.ts-toast-container .ts-toast-warning .ts-toast-progress{background:var(--toast-warning-color,#f0a020)}.ts-toast-container .ts-toast-info .ts-toast-progress{background:var(--toast-info-color,#3b82f6)}.ts-toast-container .ts-toast-action{order:-1;flex:none;appearance:none;border:0;background:0 0;color:var(--toast-action-color,#3b82f6);font:inherit;font-weight:600;padding:4px 8px;margin-left:4px;border-radius:6px;cursor:pointer}.ts-toast-container .ts-toast-action:hover{background:var(--toast-action-hover,rgba(59,130,246,.12))}.ts-toast-icon svg{width:30px;height:30px;display:block;overflow:visible}.ts-toast-icon .ts-toast-ring{fill:currentColor}.ts-toast-icon .ts-toast-glyph{fill:none;stroke:var(--toast-glyph-color,#fff);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:var(--ts-len);animation:ts-toast-draw 420ms ease-out 1 both}.ts-toast-icon .ts-toast-dot{fill:var(--toast-glyph-color,#fff);transform-origin:center;animation:ts-toast-pop 420ms ease-out 1 both}@keyframes ts-toast-draw{from{stroke-dashoffset:var(--ts-len)}to{stroke-dashoffset:0}}@keyframes ts-toast-pop{from{opacity:0;transform:scale(.3)}to{opacity:1;transform:scale(1)}}@media (prefers-reduced-motion:reduce){.ts-toast-icon .ts-toast-dot,.ts-toast-icon .ts-toast-glyph{animation:none}.ts-toast-icon .ts-toast-glyph{stroke-dashoffset:0}}.ts-toast-success .ts-toast-icon{color:var(--toast-success-color,#86e08a)}.ts-toast-error .ts-toast-icon{color:var(--toast-error-color,#e8635e)}.ts-toast-info .ts-toast-icon{color:var(--toast-info-color,#6fc8ef)}.ts-toast-warning .ts-toast-icon{color:var(--toast-warning-color,#f7e07a)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsirosgeorge/toastnotification",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "a toast notification plugin",
|
|
5
5
|
"main": "toast.min.js",
|
|
6
6
|
"module": "toast.module.js",
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"./package.json": "./package.json"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"test": "tsc --noEmit --strict --skipLibCheck toast.d.ts",
|
|
18
|
+
"test:types": "tsc --noEmit --strict --skipLibCheck toast.d.ts",
|
|
19
|
+
"test:e2e": "playwright test",
|
|
20
|
+
"test": "npm run test:types && npm run test:e2e",
|
|
19
21
|
"sync:version": "node scripts/sync-version.mjs",
|
|
20
22
|
"build:module": "node scripts/build-module.mjs",
|
|
21
23
|
"build:css": "cleancss -o assets/css/toast.min.css assets/css/toast.css",
|
|
@@ -32,8 +34,6 @@
|
|
|
32
34
|
"toast.d.ts",
|
|
33
35
|
"assets/css/toast.css",
|
|
34
36
|
"assets/css/toast.min.css",
|
|
35
|
-
"assets/img/",
|
|
36
|
-
"!assets/img/old/",
|
|
37
37
|
"LICENSE",
|
|
38
38
|
"Readme.md"
|
|
39
39
|
],
|
|
@@ -57,7 +57,9 @@
|
|
|
57
57
|
},
|
|
58
58
|
"homepage": "https://github.com/tsirosgeorge/toast-notification#readme",
|
|
59
59
|
"devDependencies": {
|
|
60
|
+
"@playwright/test": "^1.63.0",
|
|
60
61
|
"clean-css-cli": "^5.6.3",
|
|
62
|
+
"http-server": "^14.1.1",
|
|
61
63
|
"terser": "^5.40.0",
|
|
62
64
|
"typescript": "^5.9.3"
|
|
63
65
|
},
|
package/toast.d.ts
CHANGED
|
@@ -38,8 +38,9 @@ export interface ToastOptions {
|
|
|
38
38
|
/** Renders a button inside the toast, e.g. Undo. */
|
|
39
39
|
action?: ToastAction | null;
|
|
40
40
|
/**
|
|
41
|
-
* `message` is
|
|
42
|
-
*
|
|
41
|
+
* `message` is rendered as plain text. Pass `true` only for markup you wrote
|
|
42
|
+
* yourself — a string built from user input becomes executable HTML.
|
|
43
|
+
* @default false
|
|
43
44
|
*/
|
|
44
45
|
allowHtml?: boolean;
|
|
45
46
|
/** `'confirm'` (alias `'swal'`) renders a modal dialog instead of a toast. */
|
package/toast.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// Single source of truth for the CDN this build points at.
|
|
4
4
|
// `npm run sync:version` rewrites it from package.json, so it can never go stale.
|
|
5
|
-
const TS_TOAST_VERSION = "
|
|
5
|
+
const TS_TOAST_VERSION = "6.0.0";
|
|
6
6
|
// Point this at your own copy of assets/ to self-host the CSS and icons
|
|
7
7
|
// (useful offline, behind a strict CSP, or when you don't want a CDN dependency):
|
|
8
8
|
// window.TS_TOAST_ASSET_BASE = '/vendor/toastnotification';
|
|
@@ -28,6 +28,28 @@ const tsToastFocusable = (root) => Array.from(
|
|
|
28
28
|
|
|
29
29
|
let tsToastIdCounter = 0;
|
|
30
30
|
|
|
31
|
+
// Icons are inline SVG rather than animated GIFs. The four GIFs were 323 kB — fifteen
|
|
32
|
+
// times the whole library — were 400x400 for a 30px slot, and each one cost a network
|
|
33
|
+
// round trip before the icon could appear. The glyph is stroked so CSS can draw it on,
|
|
34
|
+
// once, when the toast appears.
|
|
35
|
+
const TS_TOAST_GLYPHS = {
|
|
36
|
+
success: '<path class="ts-toast-glyph" style="--ts-len:26" d="M7 12.6 L10.4 16 L17 8.8"/>',
|
|
37
|
+
error: '<path class="ts-toast-glyph" style="--ts-len:23" d="M8.3 8.3 L15.7 15.7 M15.7 8.3 L8.3 15.7"/>',
|
|
38
|
+
info: '<circle class="ts-toast-dot" cx="12" cy="7.4" r="1.5"/><path class="ts-toast-glyph" style="--ts-len:7" d="M12 11 L12 17"/>',
|
|
39
|
+
warning: '<path class="ts-toast-glyph" style="--ts-len:8" d="M12 6.6 L12 14"/><circle class="ts-toast-dot" cx="12" cy="17.3" r="1.5"/>'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Fills the icon span for a type. Returns false when the type has no icon.
|
|
43
|
+
const tsToastPaintIcon = (el, type) => {
|
|
44
|
+
const glyph = TS_TOAST_GLYPHS[type];
|
|
45
|
+
if (!glyph) return false;
|
|
46
|
+
// Fixed internal markup, never caller input.
|
|
47
|
+
el.innerHTML =
|
|
48
|
+
'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">' +
|
|
49
|
+
'<circle class="ts-toast-ring" cx="12" cy="12" r="12"/>' + glyph + '</svg>';
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
|
|
31
53
|
// Load the stylesheet from the CDN, unless the page opted out by importing it itself
|
|
32
54
|
// (set window.TS_TOAST_NO_CSS = true before loading, or ship assets/css/toast.css yourself).
|
|
33
55
|
(function loadStylesheet() {
|
|
@@ -53,6 +75,7 @@ let tsToastIdCounter = 0;
|
|
|
53
75
|
.ts-toast-container.bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }
|
|
54
76
|
.ts-toast-container.center { top: 50%; left: 50%; transform: translate(-50%, -50%); align-items: center; }
|
|
55
77
|
.ts-toast-overlay.center { align-items: center; justify-content: center; }
|
|
78
|
+
.ts-toast-overlay.ts-toast-overlay-stacked { background: transparent; }
|
|
56
79
|
@keyframes ts-toast-progress { from { transform: scaleX(1); } to { transform: scaleX(0); } }
|
|
57
80
|
.ts-toast .ts-toast-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; transform-origin: left center; border-radius: 0 0 8px 8px; background: currentColor; opacity: 0.35; pointer-events: none; }
|
|
58
81
|
.ts-toast .ts-toast-action { order: -1; flex: none; appearance: none; border: 0; background: transparent; color: #3b82f6; font: inherit; font-weight: 600; padding: 4px 8px; margin-left: 4px; border-radius: 6px; cursor: pointer; }
|
|
@@ -70,7 +93,7 @@ let tsToastIdCounter = 0;
|
|
|
70
93
|
.ts-toast.ts-toast-confirm .ts-toast-close { position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 999px; border: 0; background: transparent; color: #6b7280; font-size: 20px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
|
|
71
94
|
.ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }
|
|
72
95
|
.ts-toast.ts-toast-confirm .ts-toast-icon { width: 64px; height: 64px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; }
|
|
73
|
-
.ts-toast.ts-toast-confirm .ts-toast-icon
|
|
96
|
+
.ts-toast.ts-toast-confirm .ts-toast-icon svg { width: 36px; height: 36px; }
|
|
74
97
|
.ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }
|
|
75
98
|
.ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }
|
|
76
99
|
.ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }
|
|
@@ -119,9 +142,9 @@ const toast = function (message, options = {}) {
|
|
|
119
142
|
action = null,
|
|
120
143
|
// Escape cancels a confirm dialog
|
|
121
144
|
closeOnEscape = true,
|
|
122
|
-
// `message` is
|
|
123
|
-
//
|
|
124
|
-
allowHtml =
|
|
145
|
+
// `message` is rendered as plain text. Pass true only for markup you wrote
|
|
146
|
+
// yourself: any string built from user input becomes executable HTML.
|
|
147
|
+
allowHtml = false,
|
|
125
148
|
// interactions
|
|
126
149
|
dismissOnClick = true, // ignored if confirm-mode
|
|
127
150
|
onClick = null, // Custom onClick event listener
|
|
@@ -215,27 +238,15 @@ const toast = function (message, options = {}) {
|
|
|
215
238
|
if (icon) {
|
|
216
239
|
iconElement.textContent = icon;
|
|
217
240
|
} else {
|
|
218
|
-
|
|
219
|
-
img.alt = '';
|
|
220
|
-
img.setAttribute('aria-hidden', 'true');
|
|
221
|
-
img.style.width = '30px';
|
|
222
|
-
img.style.height = '30px';
|
|
223
|
-
img.style.objectFit = 'contain';
|
|
224
|
-
|
|
225
|
-
// No cache-buster: these GIFs are immutable per version, so let the
|
|
226
|
-
// browser and the CDN actually cache them.
|
|
227
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
228
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
229
|
-
|
|
230
|
-
iconElement.appendChild(img);
|
|
241
|
+
tsToastPaintIcon(iconElement, type);
|
|
231
242
|
}
|
|
232
243
|
|
|
233
244
|
// Create Body
|
|
234
245
|
const toastBody = document.createElement('div');
|
|
235
246
|
toastBody.className = 'ts-toast-body';
|
|
236
247
|
toastBody.id = `${uid}-body`;
|
|
237
|
-
//
|
|
238
|
-
//
|
|
248
|
+
// Text by default. innerHTML runs event handlers such as <img onerror>, so a
|
|
249
|
+
// message assembled from user input was a scripting hole in every caller.
|
|
239
250
|
if (allowHtml) toastBody.innerHTML = message;
|
|
240
251
|
else toastBody.textContent = message;
|
|
241
252
|
|
|
@@ -383,7 +394,10 @@ const toast = function (message, options = {}) {
|
|
|
383
394
|
overlay = document.createElement('div');
|
|
384
395
|
// A modal centres by default. The `position` default of 'top-right' is meant
|
|
385
396
|
// for toasts; applying it here parked the dialog in a corner of the backdrop.
|
|
386
|
-
|
|
397
|
+
// Each backdrop paints its own 50% black, so a second dialog opening over a
|
|
398
|
+
// first turned the page almost fully dark. Only the bottom one dims.
|
|
399
|
+
const stacked = tsToastOpenModals > 0 ? ' ts-toast-overlay-stacked' : '';
|
|
400
|
+
overlay.className = 'ts-toast-overlay' + stacked + (options.position ? ` ${position}` : '');
|
|
387
401
|
document.body.appendChild(overlay);
|
|
388
402
|
overlay.appendChild(toastElement);
|
|
389
403
|
if (showClose) {
|
|
@@ -664,7 +678,7 @@ const toast = function (message, options = {}) {
|
|
|
664
678
|
icon = null,
|
|
665
679
|
showLoader = false,
|
|
666
680
|
duration = 3000, // Default duration (in ms); 0 keeps the toast on screen
|
|
667
|
-
allowHtml =
|
|
681
|
+
allowHtml = false,
|
|
668
682
|
onDismiss = null // Replaces the callback the toast was created with
|
|
669
683
|
} = options;
|
|
670
684
|
|
|
@@ -696,25 +710,16 @@ const toast = function (message, options = {}) {
|
|
|
696
710
|
iconElement.className = 'ts-toast-icon';
|
|
697
711
|
iconElement.style.display = 'flex';
|
|
698
712
|
|
|
713
|
+
let hasIcon = Boolean(icon);
|
|
699
714
|
if (icon) {
|
|
700
715
|
iconElement.textContent = icon;
|
|
701
716
|
} else {
|
|
702
|
-
|
|
703
|
-
img.alt = '';
|
|
704
|
-
img.setAttribute('aria-hidden', 'true');
|
|
705
|
-
img.style.width = '30px';
|
|
706
|
-
img.style.height = '30px';
|
|
707
|
-
img.style.objectFit = 'contain';
|
|
708
|
-
|
|
709
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
710
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
711
|
-
|
|
712
|
-
iconElement.appendChild(img);
|
|
717
|
+
hasIcon = tsToastPaintIcon(iconElement, type);
|
|
713
718
|
}
|
|
714
719
|
|
|
715
720
|
// Only attach an icon we actually have. Without a type and without an explicit
|
|
716
|
-
// icon this used to append an empty
|
|
717
|
-
if (
|
|
721
|
+
// icon this used to append an empty icon element.
|
|
722
|
+
if (hasIcon) {
|
|
718
723
|
const contentRow = toastElement.querySelector('.ts-toast-content');
|
|
719
724
|
(contentRow || toastElement).appendChild(iconElement);
|
|
720
725
|
}
|
package/toast.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const TS_TOAST_VERSION="5.6.0",TS_TOAST_CDN="undefined"!=typeof window&&window.TS_TOAST_ASSET_BASE?String(window.TS_TOAST_ASSET_BASE).replace(/\/+$/,""):"https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.6.0";let tsToastOpenModals=0,tsToastPrevOverflow="",tsToastPrevPaddingRight="";const tsToastReducedMotion=()=>"undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,tsToastFocusable=t=>Array.from(t.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')).filter((t=>!t.disabled&&null!==t.offsetParent));let tsToastIdCounter=0;!function(){const t="ts-toast-stylesheet";if("undefined"!=typeof window&&window.TS_TOAST_NO_CSS)return;if(document.getElementById(t))return;const e=document.createElement("link");e.id=t,e.rel="stylesheet",e.href=`${TS_TOAST_CDN}/assets/css/toast.min.css`,document.head.appendChild(e)}(),function(){const t="ts-toast-inline-extras";if(document.getElementById(t))return;const e=document.createElement("style");e.id=t,e.textContent="\n /* Ensure center positions exist even if external CSS lacks them */\n .ts-toast-container.top-center { top: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }\n .ts-toast-container.bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }\n .ts-toast-container.center { top: 50%; left: 50%; transform: translate(-50%, -50%); align-items: center; }\n .ts-toast-overlay.center { align-items: center; justify-content: center; }\n @keyframes ts-toast-progress { from { transform: scaleX(1); } to { transform: scaleX(0); } }\n .ts-toast .ts-toast-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; transform-origin: left center; border-radius: 0 0 8px 8px; background: currentColor; opacity: 0.35; pointer-events: none; }\n .ts-toast .ts-toast-action { order: -1; flex: none; appearance: none; border: 0; background: transparent; color: #3b82f6; font: inherit; font-weight: 600; padding: 4px 8px; margin-left: 4px; border-radius: 6px; cursor: pointer; }\n .ts-toast .ts-toast-action:hover { background: rgba(59,130,246,0.12); }\n .ts-toast-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 2147483646; }\n .ts-toast.ts-toast-confirm { max-width: min(92vw, 440px); width: max(320px, 60%); flex-direction: column; gap: 12px; padding: 16px 20px; background: var(--toast-bg, #fff); color: var(--toast-color, #000); border: 1px solid var(--toast-border, #e5e7eb); border-radius: 12px; box-shadow: var(--toast-shadow, 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)); text-align: center; }\n .ts-toast.ts-toast-confirm .ts-toast-content { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }\n .ts-toast-actions { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }\n .ts-toast-btn { appearance: none; border: 0; padding: 8px 12px; border-radius: 8px; font-weight: 600; cursor: pointer; }\n .ts-toast-btn.cancel { background: #e9ecef; color: #1f2937; }\n .ts-toast-btn.confirm { background: #3b82f6; color: #fff; }\n .ts-toast.ts-toast-error .ts-toast-btn.confirm,\n .ts-toast.ts-toast-warning .ts-toast-btn.confirm { background: #ef4444; color: #fff; }\n .ts-toast.ts-toast-confirm .ts-toast-title { font-weight: 700; font-size: 1.05rem; margin-top: 4px; }\n .ts-toast.ts-toast-confirm .ts-toast-close { position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 999px; border: 0; background: transparent; color: #6b7280; font-size: 20px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }\n .ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }\n .ts-toast.ts-toast-confirm .ts-toast-icon { width: 64px; height: 64px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; }\n .ts-toast.ts-toast-confirm .ts-toast-icon img { width: 36px; height: 36px; }\n .ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }\n .ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }\n .ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }\n .ts-toast.ts-toast-confirm.ts-toast-error .ts-toast-icon { background: #fee2e2; }\n ",document.head.appendChild(e)}();const toast=function(t,e={}){e={...toast.defaults||{},...e};const{position:o="top-right",animation:s="slide-right",type:n="info",duration:a=3e3,icon:i=null,showLoader:r=!1,mode:l="alert",title:c=null,confirmText:d="Yes",cancelText:u="No",input:m=!1,inputPlaceholder:p="",inputValue:f="",confirmButtonBg:g=null,confirmButtonColor:h=null,cancelButtonBg:y=null,cancelButtonColor:b=null,onConfirm:x=null,onCancel:v=null,onResult:w=null,useOverlay:T=!0,closeOnOverlayClick:C=!0,showClose:E=!1,pauseOnHover:S=!0,showProgress:L=!1,action:_=null,closeOnEscape:k=!0,allowHtml:A=!0,dismissOnClick:N=!0,onClick:O=null,onShow:D=null,onDismiss:P=null}=e,M="confirm"===l||"swal"===l,$=tsToastReducedMotion(),B="string"==typeof e.animation&&e.animation.trim()?{"slide-top":"ts-toast-slide-top","slide-bottom":"ts-toast-slide-bottom","slide-left":"ts-toast-slide-left","slide-right":"ts-toast-slide-right","zoom-in":"ts-toast-zoom-in","zoom-out":"ts-toast-zoom-out",flip:"ts-toast-flip"}[q=e.animation.trim()]||q:M||"center"===o?"ts-toast-zoom-in":o.startsWith("top")?"ts-toast-slide-top":o.startsWith("bottom")?"ts-toast-slide-bottom":o.endsWith("left")?"ts-toast-slide-left":"ts-toast-slide-right";var q;const R=(t,e)=>{const o=t.dataset&&t.dataset.anim?t.dataset.anim:t.style.animation||"";let s="";o.includes("ts-toast-slide-top")?s="translateY(-100%)":o.includes("ts-toast-slide-bottom")?s="translateY(100%)":(o.includes("ts-toast-slide-left")||o.includes("ts-toast-slide-right"))&&(s="translateX(100%)"),t.classList.add("ts-toast-slide-out"),t.classList.remove("ts-toast-show"),t.style.animation="",s&&(t.style.transform=s),t.style.opacity="0",setTimeout((()=>{t.classList.remove("ts-toast-slide-out"),t.parentNode&&t.parentNode.removeChild(t),"function"==typeof e&&e()}),$?0:500)},j=document.createElement("div");j.className=`ts-toast ts-toast-${n}${M?" ts-toast-confirm":""}`,j.dataset.anim=B,$||(j.style.animation=`${B} 0.5s ease`);const z="ts-toast-"+ ++tsToastIdCounter;M?(j.setAttribute("role","dialog"),j.setAttribute("aria-modal","true"),j.tabIndex=-1):"error"!==n&&"warning"!==n||j.setAttribute("role","alert"),M||(j.style.flexDirection="row-reverse",j.style.justifyContent="flex-end");const X=document.createElement("span");if(X.className="ts-toast-icon",X.style.display="flex",i)X.textContent=i;else{const t=document.createElement("img");t.alt="",t.setAttribute("aria-hidden","true"),t.style.width="30px",t.style.height="30px",t.style.objectFit="contain";const e={success:"success.gif",error:"error.gif",info:"info.gif",warning:"warning.gif"}[n];e&&(t.src=`${TS_TOAST_CDN}/assets/img/${e}`),X.appendChild(t)}const F=document.createElement("div");F.className="ts-toast-body",F.id=`${z}-body`,A?F.innerHTML=t:F.textContent=t;let H=null;if(M){if(H=document.createElement("div"),H.className="ts-toast-content",H.appendChild(X),c){const t=document.createElement("div");t.className="ts-toast-title",t.id=`${z}-title`,t.textContent=c,H.appendChild(t),j.setAttribute("aria-labelledby",t.id)}H.appendChild(F),j.setAttribute("aria-describedby",F.id),j.appendChild(H)}else j.appendChild(F);let I=null;M&&m&&("textarea"===m?(I=document.createElement("textarea"),I.rows=3):(I=document.createElement("input"),I.type="text"===m||"email"===m||"password"===m||"number"===m?m:"text"),I.className="ts-toast-input",I.placeholder=p,I.value=f,"textarea"!==m&&I.addEventListener("keydown",(t=>{"Enter"===t.key&&(t.preventDefault(),K(!0))})),j.appendChild(I));let W=null,Y=null,K=null,V=()=>{};if(M){W=document.createElement("div"),W.className="ts-toast-actions";const t=document.createElement("button");t.className="ts-toast-btn cancel",t.textContent=u;const e=document.createElement("button");e.className="ts-toast-btn confirm",e.textContent=d,y&&(t.style.background=y),b&&(t.style.color=b),g&&(e.style.background=g),h&&(e.style.color=h),W.appendChild(t),W.appendChild(e),j.appendChild(W),j.result=new Promise((t=>{Y=t}));let o=!1;K=t=>{if(o)return;o=!0;const e=t?!I||I.value:!!I&&null;Y&&Y(e),t&&"function"==typeof x&&x(e,j),t||"function"!=typeof v||v(j),"function"==typeof w&&w(e,j),V(),R(j,(()=>{P&&"function"==typeof P&&P(j),Q&&Q.parentNode&&Q.parentNode.removeChild(Q)}))},t.addEventListener("click",(t=>{t.stopPropagation(),K(!1)})),e.addEventListener("click",(t=>{t.stopPropagation(),K(!0)}))}if(!M&&_&&"object"==typeof _&&_.text){const t=document.createElement("button");t.className="ts-toast-action",t.type="button",t.textContent=_.text,t.addEventListener("click",(t=>{t.stopPropagation(),"function"==typeof _.onClick&&_.onClick(j),j._dismiss()})),j.appendChild(t)}let G=null;!M&&L&&a>0&&!$&&(G=document.createElement("div"),G.className="ts-toast-progress",G.style.animation=`ts-toast-progress ${a}ms linear forwards`,G.style.animationPlayState="paused",j.appendChild(G));let J=null;r&&(J=document.createElement("div"),J.className="ts-toast-loader",j.appendChild(J));let Q=null,U=null;if(M&&T){if(Q=document.createElement("div"),Q.className="ts-toast-overlay"+(e.position?` ${o}`:""),document.body.appendChild(Q),Q.appendChild(j),E){const t=document.createElement("button");t.className="ts-toast-close",t.setAttribute("aria-label","Close"),t.innerHTML="×",t.addEventListener("click",(t=>{t.stopPropagation(),K(!1)})),j.appendChild(t)}if(C){let t=!1;Q.addEventListener("pointerdown",(e=>{t=e.target===Q})),Q.addEventListener("click",(e=>{e.target===Q&&t&&K(!1),t=!1}))}}else{let t=document.querySelector(`.ts-toast-container.${o}`);t||(t=document.createElement("div"),t.className=`ts-toast-container ${o}`,document.body.appendChild(t)),t.hasAttribute("aria-live")||(t.setAttribute("role","status"),t.setAttribute("aria-live","polite"),t.setAttribute("aria-relevant","additions")),t.appendChild(j),U=t}if(M){const t=document.activeElement;if(tsToastOpenModals+=1,1===tsToastOpenModals){tsToastPrevOverflow=document.body.style.overflow,tsToastPrevPaddingRight=document.body.style.paddingRight;const t=window.innerWidth-document.documentElement.clientWidth;if(t>0){const e=parseFloat(window.getComputedStyle(document.body).paddingRight)||0;document.body.style.paddingRight=`${e+t}px`}document.body.style.overflow="hidden"}const e=()=>{const t=document.querySelectorAll(".ts-toast.ts-toast-confirm");return 0===t.length||t[t.length-1]===j},o=t=>{if(!e())return;if("Escape"===t.key&&k)return t.preventDefault(),void K(!1);if("Tab"!==t.key)return;const o=tsToastFocusable(j);if(!o.length)return void t.preventDefault();const s=o[0],n=o[o.length-1];j.contains(document.activeElement)?t.shiftKey&&document.activeElement===s?(t.preventDefault(),n.focus()):t.shiftKey||document.activeElement!==n||(t.preventDefault(),s.focus()):(t.preventDefault(),(t.shiftKey?n:s).focus())};document.addEventListener("keydown",o,!0),V=()=>{document.removeEventListener("keydown",o,!0),tsToastOpenModals=Math.max(0,tsToastOpenModals-1),0===tsToastOpenModals&&(document.body.style.overflow=tsToastPrevOverflow,document.body.style.paddingRight=tsToastPrevPaddingRight),t&&"function"==typeof t.focus&&document.contains(t)&&t.focus()},(I||j.querySelector(".ts-toast-btn.confirm")||j).focus()}D&&"function"==typeof D&&D(j),setTimeout((()=>{j.classList.add("ts-toast-show")}),100);const Z=a>0?Math.min(2e3,Math.max(0,a-500)):2e3;r&&J&&setTimeout((()=>{j._managedByLoading||(J.classList.add("done"),J.remove(),j.contains(X)||(M&&H?H.appendChild(X):j.appendChild(X)))}),Z),r||M||j.contains(X)||j.appendChild(X),j._onDismiss="function"==typeof P?P:null;let tt=a,et=null,ot=0;const st=()=>{et&&(clearTimeout(et),et=null)},nt=()=>{M||tt<=0||et||(ot=Date.now(),et=setTimeout((()=>{et=null,j._dismiss()}),tt),G&&(G.style.animationPlayState="running"))},at=()=>{et&&(clearTimeout(et),et=null,tt-=Date.now()-ot,G&&(G.style.animationPlayState="paused"))};if(j._dismiss=()=>{j._removing||(j._removing=!0,st(),R(j,(()=>{j._onDismiss&&j._onDismiss(j),U&&!U.children.length&&U.remove()})))},j._setDuration=t=>{st(),tt=t,nt()},nt(),!M&&S&&(j.addEventListener("mouseenter",at),j.addEventListener("mouseleave",nt),j.addEventListener("focusin",at),j.addEventListener("focusout",nt)),!M&&N&&j.addEventListener("click",(()=>{O&&"function"==typeof O&&O(j),j._dismiss()})),!M){let t=0,e=0,o=0;j.addEventListener("touchstart",(o=>{t=o.changedTouches[0].screenX,e=o.changedTouches[0].screenY}),{passive:!0}),j.addEventListener("touchend",(s=>{o=s.changedTouches[0].screenX;const n=Math.abs(t-o),a=Math.abs(e-s.changedTouches[0].screenY);n>50&&n>a&&j._dismiss()}))}return j.close=()=>{M?K(!1):j._dismiss()},j};toast.success=function(t,e){return toast(t,{...e,type:"success"})},toast.error=function(t,e){return toast(t,{...e,type:"error"})},toast.warning=function(t,e){return toast(t,{...e,type:"warning"})},toast.info=function(t,e){return toast(t,{...e,type:"info"})},toast.update=function(t,e,o={}){const{type:s=null,icon:n=null,showLoader:a=!1,duration:i=3e3,allowHtml:r=!0,onDismiss:l=null}=o,c=t.querySelector(".ts-toast-loader"),d=t.querySelector(".ts-toast-icon");c&&c.remove(),s&&(["success","error","info","warning"].forEach((e=>t.classList.remove(`ts-toast-${e}`))),t.classList.add("ts-toast",`ts-toast-${s}`,"ts-toast-show"));const u=t.querySelector(".ts-toast-body");u&&(r?u.innerHTML=e:u.textContent=e),d&&d.remove();const m=document.createElement("span");if(m.className="ts-toast-icon",m.style.display="flex",n)m.textContent=n;else{const t=document.createElement("img");t.alt="",t.setAttribute("aria-hidden","true"),t.style.width="30px",t.style.height="30px",t.style.objectFit="contain";const e={success:"success.gif",error:"error.gif",info:"info.gif",warning:"warning.gif"}[s];e&&(t.src=`${TS_TOAST_CDN}/assets/img/${e}`),m.appendChild(t)}if(n||m.querySelector("img[src]")){(t.querySelector(".ts-toast-content")||t).appendChild(m)}if(a){const e=document.createElement("div");e.className="ts-toast-loader",t.appendChild(e),setTimeout((()=>{e.classList.add("done")}),i>0?Math.min(2e3,Math.max(0,i-500)):2e3)}"function"==typeof l&&(t._onDismiss=l),"function"==typeof t._setDuration&&t._setDuration(i)},toast.loading=function(t,e={}){const o=toast(t,{...e,type:e.type||"info",duration:0,showLoader:!0,icon:null});requestAnimationFrame((()=>{o.classList.add("ts-toast-show")}));const s=o.querySelector(".ts-toast-loader");let n=o.querySelector(".ts-toast-icon");return n||(n=document.createElement("span"),n.className="ts-toast-icon",n.style.display="flex",o.appendChild(n)),o._managedByLoading=!0,s&&setTimeout((()=>{o._managedByLoading||s.classList.add("done")}),2e3),{update:(t,e={})=>{o._managedByLoading=!1,toast.update(o,t,{...e,showLoader:!1})},close:()=>{o._managedByLoading=!1,o.close()}}},toast.confirm=function(t,e={}){return new Promise((o=>{toast(t,{...e,mode:"confirm",duration:0,dismissOnClick:!1,onResult:t=>o(t)})}))},toast.promise=function(t,e={},o={}){const{loading:s="Loading…",success:n="Done",error:a="Something went wrong"}=e,i=toast.loading(s,o),r=(t,e)=>"function"==typeof t?t(e):t;return Promise.resolve(t).then((t=>(i.update(r(n,t),{type:"success",duration:o.duration}),t)),(t=>{throw i.update(r(a,t),{type:"error",duration:o.duration}),t}))},toast.defaults={},toast.dismissAll=function(){document.querySelectorAll(".ts-toast").forEach((t=>{"function"==typeof t.close&&t.close()}))},"undefined"!=typeof window&&(window.toast=toast),"undefined"!=typeof module&&module.exports&&(module.exports=toast);
|
|
1
|
+
"use strict";const TS_TOAST_VERSION="6.0.0",TS_TOAST_CDN="undefined"!=typeof window&&window.TS_TOAST_ASSET_BASE?String(window.TS_TOAST_ASSET_BASE).replace(/\/+$/,""):"https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@6.0.0";let tsToastOpenModals=0,tsToastPrevOverflow="",tsToastPrevPaddingRight="";const tsToastReducedMotion=()=>"undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,tsToastFocusable=t=>Array.from(t.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')).filter((t=>!t.disabled&&null!==t.offsetParent));let tsToastIdCounter=0;const TS_TOAST_GLYPHS={success:'<path class="ts-toast-glyph" style="--ts-len:26" d="M7 12.6 L10.4 16 L17 8.8"/>',error:'<path class="ts-toast-glyph" style="--ts-len:23" d="M8.3 8.3 L15.7 15.7 M15.7 8.3 L8.3 15.7"/>',info:'<circle class="ts-toast-dot" cx="12" cy="7.4" r="1.5"/><path class="ts-toast-glyph" style="--ts-len:7" d="M12 11 L12 17"/>',warning:'<path class="ts-toast-glyph" style="--ts-len:8" d="M12 6.6 L12 14"/><circle class="ts-toast-dot" cx="12" cy="17.3" r="1.5"/>'},tsToastPaintIcon=(t,e)=>{const s=TS_TOAST_GLYPHS[e];return!!s&&(t.innerHTML='<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle class="ts-toast-ring" cx="12" cy="12" r="12"/>'+s+"</svg>",!0)};!function(){const t="ts-toast-stylesheet";if("undefined"!=typeof window&&window.TS_TOAST_NO_CSS)return;if(document.getElementById(t))return;const e=document.createElement("link");e.id=t,e.rel="stylesheet",e.href=`${TS_TOAST_CDN}/assets/css/toast.min.css`,document.head.appendChild(e)}(),function(){const t="ts-toast-inline-extras";if(document.getElementById(t))return;const e=document.createElement("style");e.id=t,e.textContent="\n /* Ensure center positions exist even if external CSS lacks them */\n .ts-toast-container.top-center { top: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }\n .ts-toast-container.bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }\n .ts-toast-container.center { top: 50%; left: 50%; transform: translate(-50%, -50%); align-items: center; }\n .ts-toast-overlay.center { align-items: center; justify-content: center; }\n .ts-toast-overlay.ts-toast-overlay-stacked { background: transparent; }\n @keyframes ts-toast-progress { from { transform: scaleX(1); } to { transform: scaleX(0); } }\n .ts-toast .ts-toast-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; transform-origin: left center; border-radius: 0 0 8px 8px; background: currentColor; opacity: 0.35; pointer-events: none; }\n .ts-toast .ts-toast-action { order: -1; flex: none; appearance: none; border: 0; background: transparent; color: #3b82f6; font: inherit; font-weight: 600; padding: 4px 8px; margin-left: 4px; border-radius: 6px; cursor: pointer; }\n .ts-toast .ts-toast-action:hover { background: rgba(59,130,246,0.12); }\n .ts-toast-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 2147483646; }\n .ts-toast.ts-toast-confirm { max-width: min(92vw, 440px); width: max(320px, 60%); flex-direction: column; gap: 12px; padding: 16px 20px; background: var(--toast-bg, #fff); color: var(--toast-color, #000); border: 1px solid var(--toast-border, #e5e7eb); border-radius: 12px; box-shadow: var(--toast-shadow, 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)); text-align: center; }\n .ts-toast.ts-toast-confirm .ts-toast-content { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }\n .ts-toast-actions { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }\n .ts-toast-btn { appearance: none; border: 0; padding: 8px 12px; border-radius: 8px; font-weight: 600; cursor: pointer; }\n .ts-toast-btn.cancel { background: #e9ecef; color: #1f2937; }\n .ts-toast-btn.confirm { background: #3b82f6; color: #fff; }\n .ts-toast.ts-toast-error .ts-toast-btn.confirm,\n .ts-toast.ts-toast-warning .ts-toast-btn.confirm { background: #ef4444; color: #fff; }\n .ts-toast.ts-toast-confirm .ts-toast-title { font-weight: 700; font-size: 1.05rem; margin-top: 4px; }\n .ts-toast.ts-toast-confirm .ts-toast-close { position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 999px; border: 0; background: transparent; color: #6b7280; font-size: 20px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }\n .ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }\n .ts-toast.ts-toast-confirm .ts-toast-icon { width: 64px; height: 64px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; }\n .ts-toast.ts-toast-confirm .ts-toast-icon svg { width: 36px; height: 36px; }\n .ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }\n .ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }\n .ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }\n .ts-toast.ts-toast-confirm.ts-toast-error .ts-toast-icon { background: #fee2e2; }\n ",document.head.appendChild(e)}();const toast=function(t,e={}){e={...toast.defaults||{},...e};const{position:s="top-right",animation:o="slide-right",type:n="info",duration:a=3e3,icon:i=null,showLoader:r=!1,mode:l="alert",title:c=null,confirmText:d="Yes",cancelText:u="No",input:m=!1,inputPlaceholder:p="",inputValue:f="",confirmButtonBg:y=null,confirmButtonColor:g=null,cancelButtonBg:h=null,cancelButtonColor:b=null,onConfirm:v=null,onCancel:x=null,onResult:w=null,useOverlay:T=!0,closeOnOverlayClick:C=!0,showClose:E=!1,pauseOnHover:L=!0,showProgress:S=!1,action:k=null,closeOnEscape:_=!0,allowHtml:A=!1,dismissOnClick:M=!0,onClick:N=null,onShow:O=null,onDismiss:P=null}=e,D="confirm"===l||"swal"===l,B=tsToastReducedMotion(),$="string"==typeof e.animation&&e.animation.trim()?{"slide-top":"ts-toast-slide-top","slide-bottom":"ts-toast-slide-bottom","slide-left":"ts-toast-slide-left","slide-right":"ts-toast-slide-right","zoom-in":"ts-toast-zoom-in","zoom-out":"ts-toast-zoom-out",flip:"ts-toast-flip"}[q=e.animation.trim()]||q:D||"center"===s?"ts-toast-zoom-in":s.startsWith("top")?"ts-toast-slide-top":s.startsWith("bottom")?"ts-toast-slide-bottom":s.endsWith("left")?"ts-toast-slide-left":"ts-toast-slide-right";var q;const R=(t,e)=>{const s=t.dataset&&t.dataset.anim?t.dataset.anim:t.style.animation||"";let o="";s.includes("ts-toast-slide-top")?o="translateY(-100%)":s.includes("ts-toast-slide-bottom")?o="translateY(100%)":(s.includes("ts-toast-slide-left")||s.includes("ts-toast-slide-right"))&&(o="translateX(100%)"),t.classList.add("ts-toast-slide-out"),t.classList.remove("ts-toast-show"),t.style.animation="",o&&(t.style.transform=o),t.style.opacity="0",setTimeout((()=>{t.classList.remove("ts-toast-slide-out"),t.parentNode&&t.parentNode.removeChild(t),"function"==typeof e&&e()}),B?0:500)},j=document.createElement("div");j.className=`ts-toast ts-toast-${n}${D?" ts-toast-confirm":""}`,j.dataset.anim=$,B||(j.style.animation=`${$} 0.5s ease`);const H="ts-toast-"+ ++tsToastIdCounter;D?(j.setAttribute("role","dialog"),j.setAttribute("aria-modal","true"),j.tabIndex=-1):"error"!==n&&"warning"!==n||j.setAttribute("role","alert"),D||(j.style.flexDirection="row-reverse",j.style.justifyContent="flex-end");const I=document.createElement("span");I.className="ts-toast-icon",I.style.display="flex",i?I.textContent=i:tsToastPaintIcon(I,n);const z=document.createElement("div");z.className="ts-toast-body",z.id=`${H}-body`,A?z.innerHTML=t:z.textContent=t;let X=null;if(D){if(X=document.createElement("div"),X.className="ts-toast-content",X.appendChild(I),c){const t=document.createElement("div");t.className="ts-toast-title",t.id=`${H}-title`,t.textContent=c,X.appendChild(t),j.setAttribute("aria-labelledby",t.id)}X.appendChild(z),j.setAttribute("aria-describedby",z.id),j.appendChild(X)}else j.appendChild(z);let Y=null;D&&m&&("textarea"===m?(Y=document.createElement("textarea"),Y.rows=3):(Y=document.createElement("input"),Y.type="text"===m||"email"===m||"password"===m||"number"===m?m:"text"),Y.className="ts-toast-input",Y.placeholder=p,Y.value=f,"textarea"!==m&&Y.addEventListener("keydown",(t=>{"Enter"===t.key&&(t.preventDefault(),K(!0))})),j.appendChild(Y));let W=null,F=null,K=null,G=()=>{};if(D){W=document.createElement("div"),W.className="ts-toast-actions";const t=document.createElement("button");t.className="ts-toast-btn cancel",t.textContent=u;const e=document.createElement("button");e.className="ts-toast-btn confirm",e.textContent=d,h&&(t.style.background=h),b&&(t.style.color=b),y&&(e.style.background=y),g&&(e.style.color=g),W.appendChild(t),W.appendChild(e),j.appendChild(W),j.result=new Promise((t=>{F=t}));let s=!1;K=t=>{if(s)return;s=!0;const e=t?!Y||Y.value:!!Y&&null;F&&F(e),t&&"function"==typeof v&&v(e,j),t||"function"!=typeof x||x(j),"function"==typeof w&&w(e,j),G(),R(j,(()=>{P&&"function"==typeof P&&P(j),Q&&Q.parentNode&&Q.parentNode.removeChild(Q)}))},t.addEventListener("click",(t=>{t.stopPropagation(),K(!1)})),e.addEventListener("click",(t=>{t.stopPropagation(),K(!0)}))}if(!D&&k&&"object"==typeof k&&k.text){const t=document.createElement("button");t.className="ts-toast-action",t.type="button",t.textContent=k.text,t.addEventListener("click",(t=>{t.stopPropagation(),"function"==typeof k.onClick&&k.onClick(j),j._dismiss()})),j.appendChild(t)}let V=null;!D&&S&&a>0&&!B&&(V=document.createElement("div"),V.className="ts-toast-progress",V.style.animation=`ts-toast-progress ${a}ms linear forwards`,V.style.animationPlayState="paused",j.appendChild(V));let J=null;r&&(J=document.createElement("div"),J.className="ts-toast-loader",j.appendChild(J));let Q=null,U=null;if(D&&T){Q=document.createElement("div");const t=tsToastOpenModals>0?" ts-toast-overlay-stacked":"";if(Q.className="ts-toast-overlay"+t+(e.position?` ${s}`:""),document.body.appendChild(Q),Q.appendChild(j),E){const t=document.createElement("button");t.className="ts-toast-close",t.setAttribute("aria-label","Close"),t.innerHTML="×",t.addEventListener("click",(t=>{t.stopPropagation(),K(!1)})),j.appendChild(t)}if(C){let t=!1;Q.addEventListener("pointerdown",(e=>{t=e.target===Q})),Q.addEventListener("click",(e=>{e.target===Q&&t&&K(!1),t=!1}))}}else{let t=document.querySelector(`.ts-toast-container.${s}`);t||(t=document.createElement("div"),t.className=`ts-toast-container ${s}`,document.body.appendChild(t)),t.hasAttribute("aria-live")||(t.setAttribute("role","status"),t.setAttribute("aria-live","polite"),t.setAttribute("aria-relevant","additions")),t.appendChild(j),U=t}if(D){const t=document.activeElement;if(tsToastOpenModals+=1,1===tsToastOpenModals){tsToastPrevOverflow=document.body.style.overflow,tsToastPrevPaddingRight=document.body.style.paddingRight;const t=window.innerWidth-document.documentElement.clientWidth;if(t>0){const e=parseFloat(window.getComputedStyle(document.body).paddingRight)||0;document.body.style.paddingRight=`${e+t}px`}document.body.style.overflow="hidden"}const e=()=>{const t=document.querySelectorAll(".ts-toast.ts-toast-confirm");return 0===t.length||t[t.length-1]===j},s=t=>{if(!e())return;if("Escape"===t.key&&_)return t.preventDefault(),void K(!1);if("Tab"!==t.key)return;const s=tsToastFocusable(j);if(!s.length)return void t.preventDefault();const o=s[0],n=s[s.length-1];j.contains(document.activeElement)?t.shiftKey&&document.activeElement===o?(t.preventDefault(),n.focus()):t.shiftKey||document.activeElement!==n||(t.preventDefault(),o.focus()):(t.preventDefault(),(t.shiftKey?n:o).focus())};document.addEventListener("keydown",s,!0),G=()=>{document.removeEventListener("keydown",s,!0),tsToastOpenModals=Math.max(0,tsToastOpenModals-1),0===tsToastOpenModals&&(document.body.style.overflow=tsToastPrevOverflow,document.body.style.paddingRight=tsToastPrevPaddingRight),t&&"function"==typeof t.focus&&document.contains(t)&&t.focus()},(Y||j.querySelector(".ts-toast-btn.confirm")||j).focus()}O&&"function"==typeof O&&O(j),setTimeout((()=>{j.classList.add("ts-toast-show")}),100);const Z=a>0?Math.min(2e3,Math.max(0,a-500)):2e3;r&&J&&setTimeout((()=>{j._managedByLoading||(J.classList.add("done"),J.remove(),j.contains(I)||(D&&X?X.appendChild(I):j.appendChild(I)))}),Z),r||D||j.contains(I)||j.appendChild(I),j._onDismiss="function"==typeof P?P:null;let tt=a,et=null,st=0;const ot=()=>{et&&(clearTimeout(et),et=null)},nt=()=>{D||tt<=0||et||(st=Date.now(),et=setTimeout((()=>{et=null,j._dismiss()}),tt),V&&(V.style.animationPlayState="running"))},at=()=>{et&&(clearTimeout(et),et=null,tt-=Date.now()-st,V&&(V.style.animationPlayState="paused"))};if(j._dismiss=()=>{j._removing||(j._removing=!0,ot(),R(j,(()=>{j._onDismiss&&j._onDismiss(j),U&&!U.children.length&&U.remove()})))},j._setDuration=t=>{ot(),tt=t,nt()},nt(),!D&&L&&(j.addEventListener("mouseenter",at),j.addEventListener("mouseleave",nt),j.addEventListener("focusin",at),j.addEventListener("focusout",nt)),!D&&M&&j.addEventListener("click",(()=>{N&&"function"==typeof N&&N(j),j._dismiss()})),!D){let t=0,e=0,s=0;j.addEventListener("touchstart",(s=>{t=s.changedTouches[0].screenX,e=s.changedTouches[0].screenY}),{passive:!0}),j.addEventListener("touchend",(o=>{s=o.changedTouches[0].screenX;const n=Math.abs(t-s),a=Math.abs(e-o.changedTouches[0].screenY);n>50&&n>a&&j._dismiss()}))}return j.close=()=>{D?K(!1):j._dismiss()},j};toast.success=function(t,e){return toast(t,{...e,type:"success"})},toast.error=function(t,e){return toast(t,{...e,type:"error"})},toast.warning=function(t,e){return toast(t,{...e,type:"warning"})},toast.info=function(t,e){return toast(t,{...e,type:"info"})},toast.update=function(t,e,s={}){const{type:o=null,icon:n=null,showLoader:a=!1,duration:i=3e3,allowHtml:r=!1,onDismiss:l=null}=s,c=t.querySelector(".ts-toast-loader"),d=t.querySelector(".ts-toast-icon");c&&c.remove(),o&&(["success","error","info","warning"].forEach((e=>t.classList.remove(`ts-toast-${e}`))),t.classList.add("ts-toast",`ts-toast-${o}`,"ts-toast-show"));const u=t.querySelector(".ts-toast-body");u&&(r?u.innerHTML=e:u.textContent=e),d&&d.remove();const m=document.createElement("span");m.className="ts-toast-icon",m.style.display="flex";let p=Boolean(n);if(n?m.textContent=n:p=tsToastPaintIcon(m,o),p){(t.querySelector(".ts-toast-content")||t).appendChild(m)}if(a){const e=document.createElement("div");e.className="ts-toast-loader",t.appendChild(e),setTimeout((()=>{e.classList.add("done")}),i>0?Math.min(2e3,Math.max(0,i-500)):2e3)}"function"==typeof l&&(t._onDismiss=l),"function"==typeof t._setDuration&&t._setDuration(i)},toast.loading=function(t,e={}){const s=toast(t,{...e,type:e.type||"info",duration:0,showLoader:!0,icon:null});requestAnimationFrame((()=>{s.classList.add("ts-toast-show")}));const o=s.querySelector(".ts-toast-loader");let n=s.querySelector(".ts-toast-icon");return n||(n=document.createElement("span"),n.className="ts-toast-icon",n.style.display="flex",s.appendChild(n)),s._managedByLoading=!0,o&&setTimeout((()=>{s._managedByLoading||o.classList.add("done")}),2e3),{update:(t,e={})=>{s._managedByLoading=!1,toast.update(s,t,{...e,showLoader:!1})},close:()=>{s._managedByLoading=!1,s.close()}}},toast.confirm=function(t,e={}){return new Promise((s=>{toast(t,{...e,mode:"confirm",duration:0,dismissOnClick:!1,onResult:t=>s(t)})}))},toast.promise=function(t,e={},s={}){const{loading:o="Loading…",success:n="Done",error:a="Something went wrong"}=e,i=toast.loading(o,s),r=(t,e)=>"function"==typeof t?t(e):t;return Promise.resolve(t).then((t=>(i.update(r(n,t),{type:"success",duration:s.duration}),t)),(t=>{throw i.update(r(a,t),{type:"error",duration:s.duration}),t}))},toast.defaults={},toast.dismissAll=function(){document.querySelectorAll(".ts-toast").forEach((t=>{"function"==typeof t.close&&t.close()}))},"undefined"!=typeof window&&(window.toast=toast),"undefined"!=typeof module&&module.exports&&(module.exports=toast);
|
package/toast.module.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// Single source of truth for the CDN this build points at.
|
|
4
4
|
// `npm run sync:version` rewrites it from package.json, so it can never go stale.
|
|
5
|
-
const TS_TOAST_VERSION = "
|
|
5
|
+
const TS_TOAST_VERSION = "6.0.0";
|
|
6
6
|
// Point this at your own copy of assets/ to self-host the CSS and icons
|
|
7
7
|
// (useful offline, behind a strict CSP, or when you don't want a CDN dependency):
|
|
8
8
|
// window.TS_TOAST_ASSET_BASE = '/vendor/toastnotification';
|
|
@@ -28,6 +28,28 @@ const tsToastFocusable = (root) => Array.from(
|
|
|
28
28
|
|
|
29
29
|
let tsToastIdCounter = 0;
|
|
30
30
|
|
|
31
|
+
// Icons are inline SVG rather than animated GIFs. The four GIFs were 323 kB — fifteen
|
|
32
|
+
// times the whole library — were 400x400 for a 30px slot, and each one cost a network
|
|
33
|
+
// round trip before the icon could appear. The glyph is stroked so CSS can draw it on,
|
|
34
|
+
// once, when the toast appears.
|
|
35
|
+
const TS_TOAST_GLYPHS = {
|
|
36
|
+
success: '<path class="ts-toast-glyph" style="--ts-len:26" d="M7 12.6 L10.4 16 L17 8.8"/>',
|
|
37
|
+
error: '<path class="ts-toast-glyph" style="--ts-len:23" d="M8.3 8.3 L15.7 15.7 M15.7 8.3 L8.3 15.7"/>',
|
|
38
|
+
info: '<circle class="ts-toast-dot" cx="12" cy="7.4" r="1.5"/><path class="ts-toast-glyph" style="--ts-len:7" d="M12 11 L12 17"/>',
|
|
39
|
+
warning: '<path class="ts-toast-glyph" style="--ts-len:8" d="M12 6.6 L12 14"/><circle class="ts-toast-dot" cx="12" cy="17.3" r="1.5"/>'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Fills the icon span for a type. Returns false when the type has no icon.
|
|
43
|
+
const tsToastPaintIcon = (el, type) => {
|
|
44
|
+
const glyph = TS_TOAST_GLYPHS[type];
|
|
45
|
+
if (!glyph) return false;
|
|
46
|
+
// Fixed internal markup, never caller input.
|
|
47
|
+
el.innerHTML =
|
|
48
|
+
'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">' +
|
|
49
|
+
'<circle class="ts-toast-ring" cx="12" cy="12" r="12"/>' + glyph + '</svg>';
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
|
|
31
53
|
// Load the stylesheet from the CDN, unless the page opted out by importing it itself
|
|
32
54
|
// (set window.TS_TOAST_NO_CSS = true before loading, or ship assets/css/toast.css yourself).
|
|
33
55
|
(function loadStylesheet() {
|
|
@@ -53,6 +75,7 @@ let tsToastIdCounter = 0;
|
|
|
53
75
|
.ts-toast-container.bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }
|
|
54
76
|
.ts-toast-container.center { top: 50%; left: 50%; transform: translate(-50%, -50%); align-items: center; }
|
|
55
77
|
.ts-toast-overlay.center { align-items: center; justify-content: center; }
|
|
78
|
+
.ts-toast-overlay.ts-toast-overlay-stacked { background: transparent; }
|
|
56
79
|
@keyframes ts-toast-progress { from { transform: scaleX(1); } to { transform: scaleX(0); } }
|
|
57
80
|
.ts-toast .ts-toast-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; transform-origin: left center; border-radius: 0 0 8px 8px; background: currentColor; opacity: 0.35; pointer-events: none; }
|
|
58
81
|
.ts-toast .ts-toast-action { order: -1; flex: none; appearance: none; border: 0; background: transparent; color: #3b82f6; font: inherit; font-weight: 600; padding: 4px 8px; margin-left: 4px; border-radius: 6px; cursor: pointer; }
|
|
@@ -70,7 +93,7 @@ let tsToastIdCounter = 0;
|
|
|
70
93
|
.ts-toast.ts-toast-confirm .ts-toast-close { position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 999px; border: 0; background: transparent; color: #6b7280; font-size: 20px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
|
|
71
94
|
.ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }
|
|
72
95
|
.ts-toast.ts-toast-confirm .ts-toast-icon { width: 64px; height: 64px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; }
|
|
73
|
-
.ts-toast.ts-toast-confirm .ts-toast-icon
|
|
96
|
+
.ts-toast.ts-toast-confirm .ts-toast-icon svg { width: 36px; height: 36px; }
|
|
74
97
|
.ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }
|
|
75
98
|
.ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }
|
|
76
99
|
.ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }
|
|
@@ -119,9 +142,9 @@ const toast = function (message, options = {}) {
|
|
|
119
142
|
action = null,
|
|
120
143
|
// Escape cancels a confirm dialog
|
|
121
144
|
closeOnEscape = true,
|
|
122
|
-
// `message` is
|
|
123
|
-
//
|
|
124
|
-
allowHtml =
|
|
145
|
+
// `message` is rendered as plain text. Pass true only for markup you wrote
|
|
146
|
+
// yourself: any string built from user input becomes executable HTML.
|
|
147
|
+
allowHtml = false,
|
|
125
148
|
// interactions
|
|
126
149
|
dismissOnClick = true, // ignored if confirm-mode
|
|
127
150
|
onClick = null, // Custom onClick event listener
|
|
@@ -215,27 +238,15 @@ const toast = function (message, options = {}) {
|
|
|
215
238
|
if (icon) {
|
|
216
239
|
iconElement.textContent = icon;
|
|
217
240
|
} else {
|
|
218
|
-
|
|
219
|
-
img.alt = '';
|
|
220
|
-
img.setAttribute('aria-hidden', 'true');
|
|
221
|
-
img.style.width = '30px';
|
|
222
|
-
img.style.height = '30px';
|
|
223
|
-
img.style.objectFit = 'contain';
|
|
224
|
-
|
|
225
|
-
// No cache-buster: these GIFs are immutable per version, so let the
|
|
226
|
-
// browser and the CDN actually cache them.
|
|
227
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
228
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
229
|
-
|
|
230
|
-
iconElement.appendChild(img);
|
|
241
|
+
tsToastPaintIcon(iconElement, type);
|
|
231
242
|
}
|
|
232
243
|
|
|
233
244
|
// Create Body
|
|
234
245
|
const toastBody = document.createElement('div');
|
|
235
246
|
toastBody.className = 'ts-toast-body';
|
|
236
247
|
toastBody.id = `${uid}-body`;
|
|
237
|
-
//
|
|
238
|
-
//
|
|
248
|
+
// Text by default. innerHTML runs event handlers such as <img onerror>, so a
|
|
249
|
+
// message assembled from user input was a scripting hole in every caller.
|
|
239
250
|
if (allowHtml) toastBody.innerHTML = message;
|
|
240
251
|
else toastBody.textContent = message;
|
|
241
252
|
|
|
@@ -383,7 +394,10 @@ const toast = function (message, options = {}) {
|
|
|
383
394
|
overlay = document.createElement('div');
|
|
384
395
|
// A modal centres by default. The `position` default of 'top-right' is meant
|
|
385
396
|
// for toasts; applying it here parked the dialog in a corner of the backdrop.
|
|
386
|
-
|
|
397
|
+
// Each backdrop paints its own 50% black, so a second dialog opening over a
|
|
398
|
+
// first turned the page almost fully dark. Only the bottom one dims.
|
|
399
|
+
const stacked = tsToastOpenModals > 0 ? ' ts-toast-overlay-stacked' : '';
|
|
400
|
+
overlay.className = 'ts-toast-overlay' + stacked + (options.position ? ` ${position}` : '');
|
|
387
401
|
document.body.appendChild(overlay);
|
|
388
402
|
overlay.appendChild(toastElement);
|
|
389
403
|
if (showClose) {
|
|
@@ -664,7 +678,7 @@ const toast = function (message, options = {}) {
|
|
|
664
678
|
icon = null,
|
|
665
679
|
showLoader = false,
|
|
666
680
|
duration = 3000, // Default duration (in ms); 0 keeps the toast on screen
|
|
667
|
-
allowHtml =
|
|
681
|
+
allowHtml = false,
|
|
668
682
|
onDismiss = null // Replaces the callback the toast was created with
|
|
669
683
|
} = options;
|
|
670
684
|
|
|
@@ -696,25 +710,16 @@ const toast = function (message, options = {}) {
|
|
|
696
710
|
iconElement.className = 'ts-toast-icon';
|
|
697
711
|
iconElement.style.display = 'flex';
|
|
698
712
|
|
|
713
|
+
let hasIcon = Boolean(icon);
|
|
699
714
|
if (icon) {
|
|
700
715
|
iconElement.textContent = icon;
|
|
701
716
|
} else {
|
|
702
|
-
|
|
703
|
-
img.alt = '';
|
|
704
|
-
img.setAttribute('aria-hidden', 'true');
|
|
705
|
-
img.style.width = '30px';
|
|
706
|
-
img.style.height = '30px';
|
|
707
|
-
img.style.objectFit = 'contain';
|
|
708
|
-
|
|
709
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
710
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
711
|
-
|
|
712
|
-
iconElement.appendChild(img);
|
|
717
|
+
hasIcon = tsToastPaintIcon(iconElement, type);
|
|
713
718
|
}
|
|
714
719
|
|
|
715
720
|
// Only attach an icon we actually have. Without a type and without an explicit
|
|
716
|
-
// icon this used to append an empty
|
|
717
|
-
if (
|
|
721
|
+
// icon this used to append an empty icon element.
|
|
722
|
+
if (hasIcon) {
|
|
718
723
|
const contentRow = toastElement.querySelector('.ts-toast-content');
|
|
719
724
|
(contentRow || toastElement).appendChild(iconElement);
|
|
720
725
|
}
|
package/assets/img/error.gif
DELETED
|
Binary file
|
package/assets/img/error.png
DELETED
|
Binary file
|
package/assets/img/info.gif
DELETED
|
Binary file
|
package/assets/img/info.png
DELETED
|
Binary file
|
package/assets/img/success.gif
DELETED
|
Binary file
|
package/assets/img/success.png
DELETED
|
Binary file
|
package/assets/img/warning.gif
DELETED
|
Binary file
|
package/assets/img/warning.png
DELETED
|
Binary file
|