@tsirosgeorge/toastnotification 5.6.1 → 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 +51 -24
- package/assets/css/toast.min.css +1 -1
- package/package.json +6 -4
- package/toast.d.ts +3 -2
- package/toast.js +35 -34
- package/toast.min.js +1 -1
- package/toast.module.js +35 -34
- 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%;
|
|
@@ -348,12 +328,8 @@
|
|
|
348
328
|
|
|
349
329
|
/* Tiny utility: flex icon container */
|
|
350
330
|
/* Scoped utility to avoid conflicts */
|
|
351
|
-
.ts-toast-d-flex { display: inline-flex; align-items: center; }
|
|
352
331
|
|
|
353
332
|
/* Prevent scroll behind confirm overlay */
|
|
354
|
-
body.ts-toast-no-scroll {
|
|
355
|
-
overflow: hidden;
|
|
356
|
-
}
|
|
357
333
|
|
|
358
334
|
/* Progress bar counting down the remaining time */
|
|
359
335
|
@keyframes ts-toast-progress {
|
|
@@ -400,3 +376,54 @@ body.ts-toast-no-scroll {
|
|
|
400
376
|
.ts-toast-container .ts-toast-action:hover {
|
|
401
377
|
background: var(--toast-action-hover, rgba(59, 130, 246, 0.12));
|
|
402
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() {
|
|
@@ -71,7 +93,7 @@ let tsToastIdCounter = 0;
|
|
|
71
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; }
|
|
72
94
|
.ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }
|
|
73
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; }
|
|
74
|
-
.ts-toast.ts-toast-confirm .ts-toast-icon
|
|
96
|
+
.ts-toast.ts-toast-confirm .ts-toast-icon svg { width: 36px; height: 36px; }
|
|
75
97
|
.ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }
|
|
76
98
|
.ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }
|
|
77
99
|
.ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }
|
|
@@ -120,9 +142,9 @@ const toast = function (message, options = {}) {
|
|
|
120
142
|
action = null,
|
|
121
143
|
// Escape cancels a confirm dialog
|
|
122
144
|
closeOnEscape = true,
|
|
123
|
-
// `message` is
|
|
124
|
-
//
|
|
125
|
-
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,
|
|
126
148
|
// interactions
|
|
127
149
|
dismissOnClick = true, // ignored if confirm-mode
|
|
128
150
|
onClick = null, // Custom onClick event listener
|
|
@@ -216,27 +238,15 @@ const toast = function (message, options = {}) {
|
|
|
216
238
|
if (icon) {
|
|
217
239
|
iconElement.textContent = icon;
|
|
218
240
|
} else {
|
|
219
|
-
|
|
220
|
-
img.alt = '';
|
|
221
|
-
img.setAttribute('aria-hidden', 'true');
|
|
222
|
-
img.style.width = '30px';
|
|
223
|
-
img.style.height = '30px';
|
|
224
|
-
img.style.objectFit = 'contain';
|
|
225
|
-
|
|
226
|
-
// No cache-buster: these GIFs are immutable per version, so let the
|
|
227
|
-
// browser and the CDN actually cache them.
|
|
228
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
229
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
230
|
-
|
|
231
|
-
iconElement.appendChild(img);
|
|
241
|
+
tsToastPaintIcon(iconElement, type);
|
|
232
242
|
}
|
|
233
243
|
|
|
234
244
|
// Create Body
|
|
235
245
|
const toastBody = document.createElement('div');
|
|
236
246
|
toastBody.className = 'ts-toast-body';
|
|
237
247
|
toastBody.id = `${uid}-body`;
|
|
238
|
-
//
|
|
239
|
-
//
|
|
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.
|
|
240
250
|
if (allowHtml) toastBody.innerHTML = message;
|
|
241
251
|
else toastBody.textContent = message;
|
|
242
252
|
|
|
@@ -668,7 +678,7 @@ const toast = function (message, options = {}) {
|
|
|
668
678
|
icon = null,
|
|
669
679
|
showLoader = false,
|
|
670
680
|
duration = 3000, // Default duration (in ms); 0 keeps the toast on screen
|
|
671
|
-
allowHtml =
|
|
681
|
+
allowHtml = false,
|
|
672
682
|
onDismiss = null // Replaces the callback the toast was created with
|
|
673
683
|
} = options;
|
|
674
684
|
|
|
@@ -700,25 +710,16 @@ const toast = function (message, options = {}) {
|
|
|
700
710
|
iconElement.className = 'ts-toast-icon';
|
|
701
711
|
iconElement.style.display = 'flex';
|
|
702
712
|
|
|
713
|
+
let hasIcon = Boolean(icon);
|
|
703
714
|
if (icon) {
|
|
704
715
|
iconElement.textContent = icon;
|
|
705
716
|
} else {
|
|
706
|
-
|
|
707
|
-
img.alt = '';
|
|
708
|
-
img.setAttribute('aria-hidden', 'true');
|
|
709
|
-
img.style.width = '30px';
|
|
710
|
-
img.style.height = '30px';
|
|
711
|
-
img.style.objectFit = 'contain';
|
|
712
|
-
|
|
713
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
714
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
715
|
-
|
|
716
|
-
iconElement.appendChild(img);
|
|
717
|
+
hasIcon = tsToastPaintIcon(iconElement, type);
|
|
717
718
|
}
|
|
718
719
|
|
|
719
720
|
// Only attach an icon we actually have. Without a type and without an explicit
|
|
720
|
-
// icon this used to append an empty
|
|
721
|
-
if (
|
|
721
|
+
// icon this used to append an empty icon element.
|
|
722
|
+
if (hasIcon) {
|
|
722
723
|
const contentRow = toastElement.querySelector('.ts-toast-content');
|
|
723
724
|
(contentRow || toastElement).appendChild(iconElement);
|
|
724
725
|
}
|
package/toast.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const TS_TOAST_VERSION="5.6.1",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.1";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 .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 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:y=null,cancelButtonBg:h=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:k=!1,action:L=null,closeOnEscape:_=!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,h&&(t.style.background=h),b&&(t.style.color=b),g&&(e.style.background=g),y&&(e.style.color=y),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&&L&&"object"==typeof L&&L.text){const t=document.createElement("button");t.className="ts-toast-action",t.type="button",t.textContent=L.text,t.addEventListener("click",(t=>{t.stopPropagation(),"function"==typeof L.onClick&&L.onClick(j),j._dismiss()})),j.appendChild(t)}let G=null;!M&&k&&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){Q=document.createElement("div");const t=tsToastOpenModals>0?" ts-toast-overlay-stacked":"";if(Q.className="ts-toast-overlay"+t+(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&&_)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() {
|
|
@@ -71,7 +93,7 @@ let tsToastIdCounter = 0;
|
|
|
71
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; }
|
|
72
94
|
.ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }
|
|
73
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; }
|
|
74
|
-
.ts-toast.ts-toast-confirm .ts-toast-icon
|
|
96
|
+
.ts-toast.ts-toast-confirm .ts-toast-icon svg { width: 36px; height: 36px; }
|
|
75
97
|
.ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }
|
|
76
98
|
.ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }
|
|
77
99
|
.ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }
|
|
@@ -120,9 +142,9 @@ const toast = function (message, options = {}) {
|
|
|
120
142
|
action = null,
|
|
121
143
|
// Escape cancels a confirm dialog
|
|
122
144
|
closeOnEscape = true,
|
|
123
|
-
// `message` is
|
|
124
|
-
//
|
|
125
|
-
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,
|
|
126
148
|
// interactions
|
|
127
149
|
dismissOnClick = true, // ignored if confirm-mode
|
|
128
150
|
onClick = null, // Custom onClick event listener
|
|
@@ -216,27 +238,15 @@ const toast = function (message, options = {}) {
|
|
|
216
238
|
if (icon) {
|
|
217
239
|
iconElement.textContent = icon;
|
|
218
240
|
} else {
|
|
219
|
-
|
|
220
|
-
img.alt = '';
|
|
221
|
-
img.setAttribute('aria-hidden', 'true');
|
|
222
|
-
img.style.width = '30px';
|
|
223
|
-
img.style.height = '30px';
|
|
224
|
-
img.style.objectFit = 'contain';
|
|
225
|
-
|
|
226
|
-
// No cache-buster: these GIFs are immutable per version, so let the
|
|
227
|
-
// browser and the CDN actually cache them.
|
|
228
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
229
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
230
|
-
|
|
231
|
-
iconElement.appendChild(img);
|
|
241
|
+
tsToastPaintIcon(iconElement, type);
|
|
232
242
|
}
|
|
233
243
|
|
|
234
244
|
// Create Body
|
|
235
245
|
const toastBody = document.createElement('div');
|
|
236
246
|
toastBody.className = 'ts-toast-body';
|
|
237
247
|
toastBody.id = `${uid}-body`;
|
|
238
|
-
//
|
|
239
|
-
//
|
|
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.
|
|
240
250
|
if (allowHtml) toastBody.innerHTML = message;
|
|
241
251
|
else toastBody.textContent = message;
|
|
242
252
|
|
|
@@ -668,7 +678,7 @@ const toast = function (message, options = {}) {
|
|
|
668
678
|
icon = null,
|
|
669
679
|
showLoader = false,
|
|
670
680
|
duration = 3000, // Default duration (in ms); 0 keeps the toast on screen
|
|
671
|
-
allowHtml =
|
|
681
|
+
allowHtml = false,
|
|
672
682
|
onDismiss = null // Replaces the callback the toast was created with
|
|
673
683
|
} = options;
|
|
674
684
|
|
|
@@ -700,25 +710,16 @@ const toast = function (message, options = {}) {
|
|
|
700
710
|
iconElement.className = 'ts-toast-icon';
|
|
701
711
|
iconElement.style.display = 'flex';
|
|
702
712
|
|
|
713
|
+
let hasIcon = Boolean(icon);
|
|
703
714
|
if (icon) {
|
|
704
715
|
iconElement.textContent = icon;
|
|
705
716
|
} else {
|
|
706
|
-
|
|
707
|
-
img.alt = '';
|
|
708
|
-
img.setAttribute('aria-hidden', 'true');
|
|
709
|
-
img.style.width = '30px';
|
|
710
|
-
img.style.height = '30px';
|
|
711
|
-
img.style.objectFit = 'contain';
|
|
712
|
-
|
|
713
|
-
const iconFile = { success: 'success.gif', error: 'error.gif', info: 'info.gif', warning: 'warning.gif' }[type];
|
|
714
|
-
if (iconFile) img.src = `${TS_TOAST_CDN}/assets/img/${iconFile}`;
|
|
715
|
-
|
|
716
|
-
iconElement.appendChild(img);
|
|
717
|
+
hasIcon = tsToastPaintIcon(iconElement, type);
|
|
717
718
|
}
|
|
718
719
|
|
|
719
720
|
// Only attach an icon we actually have. Without a type and without an explicit
|
|
720
|
-
// icon this used to append an empty
|
|
721
|
-
if (
|
|
721
|
+
// icon this used to append an empty icon element.
|
|
722
|
+
if (hasIcon) {
|
|
722
723
|
const contentRow = toastElement.querySelector('.ts-toast-content');
|
|
723
724
|
(contentRow || toastElement).appendChild(iconElement);
|
|
724
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
|