@tsirosgeorge/toastnotification 5.0.7 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Readme.md CHANGED
@@ -6,7 +6,7 @@ A lightweight, customizable, and dependency-free toast notification system writt
6
6
 
7
7
  ## 📦 Include package via cdn
8
8
  ```html
9
- <script src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@{LATEST VERSION GOES HERE}/toast.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/toast.min.js"></script>
10
10
  ```
11
11
 
12
12
  ## 📦 Include package via npm
@@ -35,12 +35,58 @@ toast('Data saved successfully!', {
35
35
  });
36
36
  ```
37
37
 
38
+ ### ✅ Convenience helpers
39
+ ```javascript
40
+ toast.success('Saved!');
41
+ toast.error('Failed!');
42
+ ```
43
+
44
+ ### ⚠️ Confirm (SweetAlert-like)
45
+ - Promise API
46
+ ```javascript
47
+ const ok = await toast.confirm('This will delete the file.', {
48
+ title: 'Are you sure?',
49
+ type: 'warning',
50
+ confirmText: 'Yes, delete',
51
+ cancelText: 'Cancel',
52
+ useOverlay: true,
53
+ closeOnOverlayClick: true,
54
+ showClose: true,
55
+ // optional custom button colors
56
+ confirmButtonBg: '#10b981',
57
+ confirmButtonColor: '#fff',
58
+ cancelButtonBg: '#e5e7eb',
59
+ cancelButtonColor: '#1f2937',
60
+ });
61
+ if (ok) {
62
+ // proceed
63
+ }
64
+ ```
65
+
66
+ - Callback API
67
+ ```javascript
68
+ toast('Are you sure?', {
69
+ mode: 'confirm',
70
+ type: 'warning',
71
+ title: 'Confirm action',
72
+ onConfirm: () => console.log('YES'),
73
+ onCancel: () => console.log('NO'),
74
+ });
75
+ ```
76
+
77
+ ### ⏳ Loading → Update
78
+ ```javascript
79
+ const t = toast.loading('Uploading…', { type: 'info' });
80
+ // later
81
+ t.update('Done!', { type: 'success', duration: 2000 });
82
+ ```
83
+
38
84
  ## 🛠️ Available Options
39
85
 
40
86
  | Option | Type | Default | Description |
41
87
  |--------------|------------|---------------|-----------------------------------------------------------------------------------------------|
42
- | `position` | `string` | `'top-right'` | Position of the toast container. Possible values: `'top-left'`, `'top-right'`, `'bottom-left'`, `'bottom-right'`, `top-center`. |
43
- | `animation` | `string` | `'slide-right'` | Animation effect applied to the toast when it shows and hides. Examples: `'fade'`, `'slide-right'`, `'slide-left'`, `'slide-top'`, `'slide-bottom'`, `'zoom-in'`. The hide animation reverses the show animation automatically. |
88
+ | `position` | `string` | `'top-right'` | Container position. Values: `'top-left'`, `'top-right'`, `'bottom-left'`, `'bottom-right'`, `'top-center'`, `'bottom-center'`. |
89
+ | `animation` | `string` | `'slide-right'` | Show animation. Examples: `'slide-right'`, `'slide-left'`, `'slide-top'`, `'slide-bottom'`, `'zoom-in'`. Hide uses reverse automatically. |
44
90
  | `type` | `string` | `'info'` | Type of toast, controlling icon and styling. Possible values: `'info'`, `'success'`, `'error'`, `'warning'`. |
45
91
  | `duration` | `number` | `3000` | Duration in milliseconds before the toast automatically dismisses. |
46
92
  | `icon` | `string` or `null` | `null` | Optional custom icon displayed as text (e.g., emoji) before the toast message. If not set, a default GIF icon is used based on the `type`. |
@@ -49,6 +95,24 @@ toast('Data saved successfully!', {
49
95
  | `onShow` | `function` or `null` | `null` | Callback function executed when the toast appears (after it's added to the DOM and shown). |
50
96
  | `onDismiss` | `function` or `null` | `null` | Callback function executed when the toast is dismissed and removed from the DOM. |
51
97
 
98
+ ### 🧩 Confirm-specific options
99
+ | Option | Type | Default | Description |
100
+ |-------|------|---------|-------------|
101
+ | `mode` | `"confirm" | "swal"` | — | Set to show a confirm dialog with Yes/No buttons. |
102
+ | `title` | `string` | `null` | Optional heading shown above the message. |
103
+ | `confirmText` | `string` | `"Yes"` | Confirm button label. |
104
+ | `cancelText` | `string` | `"No"` | Cancel button label. |
105
+ | `useOverlay` | `boolean` | `true` | Dim the background and center the dialog. |
106
+ | `closeOnOverlayClick` | `boolean` | `true` | Clicking the overlay cancels. |
107
+ | `showClose` | `boolean` | `false` | Show a top-right × button. |
108
+ | `confirmButtonBg` | `string` | `null` | Inline background color for confirm button. |
109
+ | `confirmButtonColor` | `string` | `null` | Inline text color for confirm button. |
110
+ | `cancelButtonBg` | `string` | `null` | Inline background color for cancel button. |
111
+ | `cancelButtonColor` | `string` | `null` | Inline text color for cancel button. |
112
+
113
+ ### 🧪 Playground
114
+ Open `index.html` to experiment with all options (message, type, position, animation, duration, icon, loader, confirm title/texts, overlay, close, and button colors).
115
+
52
116
 
53
117
  ## 📝 License
54
118
 
@@ -76,6 +76,37 @@
76
76
  width: auto!important;
77
77
  }
78
78
 
79
+ /* When toast is used outside a container (e.g., confirm in overlay), keep card styles */
80
+ .ts-toast.ts-toast-confirm {
81
+ display: flex;
82
+ align-items: center;
83
+ justify-content: center;
84
+ background-color: var(--toast-bg, #fff);
85
+ color: var(--toast-color, #000);
86
+ border: 1px solid var(--toast-border, #e5e7eb);
87
+ border-radius: 12px;
88
+ padding: 16px 20px;
89
+ 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));
90
+ }
91
+
92
+ .ts-toast.ts-toast-confirm .ts-toast-content {
93
+ display: flex;
94
+ flex-direction: column;
95
+ align-items: center;
96
+ justify-content: center;
97
+ gap: 12px;
98
+ text-align: center;
99
+ }
100
+
101
+ .ts-toast.ts-toast-confirm .ts-toast-body { text-align: center; }
102
+
103
+ .ts-toast-actions {
104
+ display: flex;
105
+ gap: 10px;
106
+ justify-content: center;
107
+ margin-top: 12px;
108
+ }
109
+
79
110
  /* Show toast with animation */
80
111
  .ts-toast-container .ts-toast.show {
81
112
  opacity: 1;
@@ -260,4 +291,26 @@
260
291
  animation-duration: 0.5s;
261
292
  animation-timing-function: ease-in-out;
262
293
  animation-fill-mode: forwards;
294
+ }
295
+
296
+ /* Overlay for confirm dialogs */
297
+ .ts-toast-overlay {
298
+ position: fixed;
299
+ inset: 0;
300
+ background: rgba(0, 0, 0, 0.5); /* darker backdrop */
301
+ display: flex;
302
+ align-items: center;
303
+ justify-content: center;
304
+ z-index: 2147483646;
305
+ }
306
+
307
+ /* Tiny utility: flex icon container */
308
+ .d-flex {
309
+ display: inline-flex;
310
+ align-items: center;
311
+ }
312
+
313
+ /* Prevent scroll behind confirm overlay */
314
+ body.ts-toast-no-scroll {
315
+ overflow: hidden;
263
316
  }
@@ -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 .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-container .ts-toast.show{opacity:1;transform:translateY(0)}@keyframes slide-left{from{transform:translateX(-100%)}to{transform:translateX(0)}}@keyframes slide-right{from{transform:translateX(100%)}to{transform:translateX(0)}}@keyframes slide-top{from{transform:translateY(-100%)}to{transform:translateY(0)}}@keyframes slide-bottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes zoom-in{from{transform:scale(0)}to{transform:scale(1)}}@keyframes flip{from{transform:rotateY(90deg)}to{transform:rotateY(0)}}.ts-toast-container .ts-toast-icon{font-size:1.2rem}.ts-toast-container .ts-toast-success .ts-toast-icon{color:var(--toast-success-color,#66ee78)}.ts-toast-container .ts-toast-error .ts-toast-icon{color:var(--toast-error-color,#ef4444)}.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:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.ts-toast-container .ts-toast-loader.done{animation:none;opacity:0;transition:opacity .5s ease}.ts-toast-container .ts-toast-icon{font-size:1.2rem;opacity:0;transition:opacity .5s ease}.ts-toast-container .ts-toast.show .ts-toast-icon{opacity:1}@keyframes progress-bar{0%{width:0%}100%{width:100%}}@keyframes slide-top-reverse{from{transform:translateY(0)}to{transform:translateY(-100%)}}@keyframes slide-bottom-reverse{from{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes slide-left-reverse{from{transform:translateX(0)}to{transform:translateX(-100%)}}@keyframes slide-right-reverse{from{transform:translateX(0)}to{transform:translateX(100%)}}.ts-toast-container .ts-toast.slide-out{animation-duration:.5s;animation-timing-function:ease-in-out;animation-fill-mode:forwards}
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 .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))}.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-container .ts-toast.show{opacity:1;transform:translateY(0)}@keyframes slide-left{from{transform:translateX(-100%)}to{transform:translateX(0)}}@keyframes slide-right{from{transform:translateX(100%)}to{transform:translateX(0)}}@keyframes slide-top{from{transform:translateY(-100%)}to{transform:translateY(0)}}@keyframes slide-bottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes zoom-in{from{transform:scale(0)}to{transform:scale(1)}}@keyframes flip{from{transform:rotateY(90deg)}to{transform:rotateY(0)}}.ts-toast-container .ts-toast-icon{font-size:1.2rem}.ts-toast-container .ts-toast-success .ts-toast-icon{color:var(--toast-success-color,#66ee78)}.ts-toast-container .ts-toast-error .ts-toast-icon{color:var(--toast-error-color,#ef4444)}.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:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.ts-toast-container .ts-toast-loader.done{animation:none;opacity:0;transition:opacity .5s ease}.ts-toast-container .ts-toast-icon{font-size:1.2rem;opacity:0;transition:opacity .5s ease}.ts-toast-container .ts-toast.show .ts-toast-icon{opacity:1}@keyframes progress-bar{0%{width:0%}100%{width:100%}}@keyframes slide-top-reverse{from{transform:translateY(0)}to{transform:translateY(-100%)}}@keyframes slide-bottom-reverse{from{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes slide-left-reverse{from{transform:translateX(0)}to{transform:translateX(-100%)}}@keyframes slide-right-reverse{from{transform:translateX(0)}to{transform:translateX(100%)}}.ts-toast-container .ts-toast.slide-out{animation-duration:.5s;animation-timing-function:ease-in-out;animation-fill-mode:forwards}.ts-toast-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:2147483646}.d-flex{display:inline-flex;align-items:center}body.ts-toast-no-scroll{overflow:hidden}
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,20 +1,22 @@
1
1
  {
2
2
  "name": "@tsirosgeorge/toastnotification",
3
- "version": "5.0.7",
3
+ "version": "5.1.1",
4
4
  "description": "a toast notification plugin",
5
5
  "main": "toast.min.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1",
8
- "build:css": "cleancss -o assets/css/toast.min.css assets/css/toast.css",
9
- "build:js": "terser toast.js --compress --mangle --output toast.min.js",
10
- "build": "npm run build:css && npm run build:js",
11
- "prepublishOnly": "npm run build"
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "build:css": "cleancss -o assets/css/toast.min.css assets/css/toast.css",
9
+ "build:js": "terser toast.js --compress --mangle --output toast.min.js",
10
+ "build": "npm run build:css && npm run build:js",
11
+ "prepublishOnly": "npm run build",
12
+ "release": "npm version && git push origin main --follow-tags && npm publish --access public"
12
13
  },
13
14
  "files": [
14
15
  "toast.js",
15
16
  "toast.min.js",
16
17
  "assets/css/toast.css",
17
- "assets/css/toast.min.css"
18
+ "assets/css/toast.min.css",
19
+ "assets/img/"
18
20
  ],
19
21
  "repository": {
20
22
  "type": "git",
package/toast.js CHANGED
@@ -4,32 +4,128 @@
4
4
  // Dynamically load the external CSS file
5
5
  const link = document.createElement("link");
6
6
  link.rel = "stylesheet";
7
- link.href = "https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.0.7/assets/css/toast.min.css";// Update path as needed
7
+ link.href = "https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/css/toast.min.css";// Pinned to current release
8
8
  document.head.appendChild(link);
9
9
 
10
+ // Inject minimal styles for confirm actions and overlay (kept tiny to avoid breaking existing CSS)
11
+ (function injectInlineStyles() {
12
+ const STYLE_ID = 'ts-toast-inline-extras';
13
+ if (document.getElementById(STYLE_ID)) return;
14
+ const style = document.createElement('style');
15
+ style.id = STYLE_ID;
16
+ style.textContent = `
17
+ /* Ensure center positions exist even if external CSS lacks them */
18
+ .ts-toast-container.top-center { top: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }
19
+ .ts-toast-container.bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); align-items: center; }
20
+ .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; }
21
+ .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; }
22
+ .ts-toast.ts-toast-confirm .ts-toast-content { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }
23
+ .ts-toast-actions { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }
24
+ .ts-toast-btn { appearance: none; border: 0; padding: 8px 12px; border-radius: 8px; font-weight: 600; cursor: pointer; }
25
+ .ts-toast-btn.cancel { background: #e9ecef; color: #1f2937; }
26
+ .ts-toast-btn.confirm { background: #3b82f6; color: #fff; }
27
+ .ts-toast.ts-toast-error .ts-toast-btn.confirm,
28
+ .ts-toast.ts-toast-warning .ts-toast-btn.confirm { background: #ef4444; color: #fff; }
29
+ .ts-toast.ts-toast-confirm .ts-toast-title { font-weight: 700; font-size: 1.05rem; margin-top: 4px; }
30
+ .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; }
31
+ .ts-toast.ts-toast-confirm .ts-toast-close:hover { background: rgba(0,0,0,0.06); }
32
+ .ts-toast.ts-toast-confirm .ts-toast-icon { width: 64px; height: 64px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; }
33
+ .ts-toast.ts-toast-confirm .ts-toast-icon img { width: 36px; height: 36px; }
34
+ .ts-toast.ts-toast-confirm.ts-toast-success .ts-toast-icon { background: #dcfce7; }
35
+ .ts-toast.ts-toast-confirm.ts-toast-info .ts-toast-icon { background: #dbeafe; }
36
+ .ts-toast.ts-toast-confirm.ts-toast-warning .ts-toast-icon { background: #fef3c7; }
37
+ .ts-toast.ts-toast-confirm.ts-toast-error .ts-toast-icon { background: #fee2e2; }
38
+ `;
39
+ document.head.appendChild(style);
40
+ })();
41
+
10
42
  const toast = function (message, options = {}) {
11
43
  const {
12
44
  position = 'top-right',
13
- animation = 'slide-right', // Default animation is fade
45
+ animation = 'slide-right', // Default fallback animation
14
46
  type = 'info',
15
47
  duration = 3000,
16
48
  icon = null,
17
49
  showLoader = false,
50
+ // behavior/mode: 'alert' (default) or 'confirm'/'swal'
51
+ mode = 'alert',
52
+ // confirm options (used when mode is 'confirm' or 'swal')
53
+ title = null,
54
+ confirmText = 'Yes',
55
+ cancelText = 'No',
56
+ // confirm button color customization (optional)
57
+ confirmButtonBg = null,
58
+ confirmButtonColor = null,
59
+ cancelButtonBg = null,
60
+ cancelButtonColor = null,
61
+ onConfirm = null,
62
+ onCancel = null,
63
+ onResult = null,
64
+ useOverlay = true,
65
+ closeOnOverlayClick = true,
66
+ showClose = false,
67
+ // interactions
68
+ dismissOnClick = true, // ignored if confirm-mode
18
69
  onClick = null, // Custom onClick event listener
19
70
  onShow = null, // Custom onShow event listener
20
71
  onDismiss = null // Custom onDismiss event listener
21
72
  } = options;
22
73
 
23
- const toastElement = document.createElement('div');
24
- toastElement.className = `ts-toast ts-toast-${type}`;
25
- toastElement.style.animation = `${animation} 0.5s ease`; // Default fade animation
26
- toastElement.style.flexDirection = 'row-reverse';
27
- toastElement.style.justifyContent = 'flex-end';
74
+ const isConfirm = (mode === 'confirm' || mode === 'swal');
28
75
 
29
- // Create Icon Element
30
- const iconElement = document.createElement('span');
31
- iconElement.className = 'ts-toast-icon';
76
+ // Pick an animation intelligently when one wasn't explicitly provided
77
+ const resolvedAnimation = (typeof options.animation === 'string' && options.animation.trim())
78
+ ? options.animation.trim()
79
+ : (isConfirm ? 'zoom-in' : (position.startsWith('top') ? 'slide-top'
80
+ : position.startsWith('bottom') ? 'slide-bottom'
81
+ : position.endsWith('left') ? 'slide-left'
82
+ : 'slide-right'));
83
+
84
+ // helper: remove with reverse animation and cleanup
85
+ const removeWithAnimation = (el, callback) => {
86
+ // Get the current animation applied to the toast
87
+ const currentAnimation = el.style.animation || '';
88
+
89
+ // Determine the reverse animation based on the current animation
90
+ let reverseAnimation = '';
91
+ if (currentAnimation.includes('slide-top')) {
92
+ reverseAnimation = 'slide-top-reverse';
93
+ } else if (currentAnimation.includes('slide-bottom')) {
94
+ reverseAnimation = 'slide-bottom-reverse';
95
+ } else if (currentAnimation.includes('slide-left')) {
96
+ reverseAnimation = 'slide-left-reverse';
97
+ } else if (currentAnimation.includes('slide-right')) {
98
+ reverseAnimation = 'slide-right-reverse';
99
+ } else if (currentAnimation.includes('zoom-in')) {
100
+ reverseAnimation = 'zoom-out';
101
+ }
102
+
103
+ // Apply the reverse animation dynamically
104
+ el.classList.add('slide-out');
105
+ el.style.animation = `${reverseAnimation} 0.5s ease`;
106
+
107
+ // Wait for the reverse animation to finish before removing the toast
108
+ setTimeout(() => {
109
+ el.classList.remove('show', 'slide-out');
110
+ el.style.animation = '';
111
+ if (el.parentNode) el.parentNode.removeChild(el);
112
+ if (typeof callback === 'function') callback();
113
+ }, 500);
114
+ };
115
+
116
+ const toastElement = document.createElement('div');
117
+ toastElement.className = `ts-toast ts-toast-${type}${isConfirm ? ' ts-toast-confirm' : ''}`;
118
+ toastElement.style.animation = `${resolvedAnimation} 0.5s ease`;
119
+ // In confirm mode, we stack content vertically; in alert mode keep original layout
120
+ if (!isConfirm) {
121
+ toastElement.style.flexDirection = 'row-reverse';
122
+ toastElement.style.justifyContent = 'flex-end';
123
+ }
32
124
 
125
+ // Create Icon Element
126
+ const iconElement = document.createElement('span');
127
+ iconElement.className = 'ts-toast-icon';
128
+ iconElement.style.display = 'flex';
33
129
  if (icon) {
34
130
  iconElement.textContent = icon;
35
131
  } else {
@@ -39,7 +135,7 @@
39
135
  img.style.height = '30px';
40
136
  img.style.objectFit = 'contain';
41
137
 
42
- const baseUrl = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/';
138
+ const baseUrl = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/';
43
139
  const timestamp = new Date().getTime(); // 🔄 force refresh
44
140
 
45
141
  if (type === 'success') {
@@ -59,7 +155,68 @@
59
155
  const toastBody = document.createElement('div');
60
156
  toastBody.className = 'ts-toast-body';
61
157
  toastBody.innerHTML = message; // Allow HTML content in message
62
- toastElement.appendChild(toastBody);
158
+
159
+ // Content row for confirm (icon + text side-by-side)
160
+ let contentRow = null;
161
+ if (isConfirm) {
162
+ contentRow = document.createElement('div');
163
+ contentRow.className = 'ts-toast-content';
164
+ contentRow.appendChild(iconElement);
165
+ if (title) {
166
+ const titleEl = document.createElement('div');
167
+ titleEl.className = 'ts-toast-title';
168
+ titleEl.textContent = title;
169
+ contentRow.appendChild(titleEl);
170
+ }
171
+ contentRow.appendChild(toastBody);
172
+ toastElement.appendChild(contentRow);
173
+ } else {
174
+ toastElement.appendChild(toastBody);
175
+ }
176
+
177
+ // Actions (for confirm mode)
178
+ let actionsContainer = null;
179
+ let resultResolver = null;
180
+ if (isConfirm) {
181
+ actionsContainer = document.createElement('div');
182
+ actionsContainer.className = 'ts-toast-actions';
183
+
184
+ const cancelBtn = document.createElement('button');
185
+ cancelBtn.className = 'ts-toast-btn cancel';
186
+ cancelBtn.textContent = cancelText;
187
+
188
+ const confirmBtn = document.createElement('button');
189
+ confirmBtn.className = 'ts-toast-btn confirm';
190
+ confirmBtn.textContent = confirmText;
191
+
192
+ // Apply custom button colors if provided (inline style overrides theme defaults)
193
+ if (cancelButtonBg) cancelBtn.style.background = cancelButtonBg;
194
+ if (cancelButtonColor) cancelBtn.style.color = cancelButtonColor;
195
+ if (confirmButtonBg) confirmBtn.style.background = confirmButtonBg;
196
+ if (confirmButtonColor) confirmBtn.style.color = confirmButtonColor;
197
+
198
+ actionsContainer.appendChild(cancelBtn);
199
+ actionsContainer.appendChild(confirmBtn);
200
+ toastElement.appendChild(actionsContainer);
201
+
202
+ // Create a Promise that resolves on user choice; expose via property
203
+ toastElement.result = new Promise((resolve) => { resultResolver = resolve; });
204
+
205
+ const resolveAndClose = (value) => {
206
+ if (resultResolver) resultResolver(value);
207
+ if (value && typeof onConfirm === 'function') onConfirm(toastElement);
208
+ if (!value && typeof onCancel === 'function') onCancel(toastElement);
209
+ if (typeof onResult === 'function') onResult(value, toastElement);
210
+ removeWithAnimation(toastElement, () => {
211
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
212
+ // Remove overlay if present
213
+ if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);
214
+ });
215
+ };
216
+
217
+ cancelBtn.addEventListener('click', (e) => { e.stopPropagation(); resolveAndClose(false); });
218
+ confirmBtn.addEventListener('click', (e) => { e.stopPropagation(); resolveAndClose(true); });
219
+ }
63
220
 
64
221
  // Loader Element
65
222
  let loader = null;
@@ -69,16 +226,55 @@
69
226
  toastElement.appendChild(loader);
70
227
  }
71
228
 
72
- // Container
73
- let container = document.querySelector(`.ts-toast-container.${position}`);
74
- if (!container) {
75
- container = document.createElement('div');
76
- container.className = `ts-toast-container ${position}`;
77
- document.body.appendChild(container);
229
+ // Container/Overlay
230
+ let overlay = null;
231
+ if (isConfirm && useOverlay) {
232
+ overlay = document.createElement('div');
233
+ overlay.className = 'ts-toast-overlay';
234
+ document.body.appendChild(overlay);
235
+ overlay.appendChild(toastElement);
236
+ if (showClose) {
237
+ const closeBtn = document.createElement('button');
238
+ closeBtn.className = 'ts-toast-close';
239
+ closeBtn.setAttribute('aria-label', 'Close');
240
+ closeBtn.innerHTML = '&times;';
241
+ closeBtn.addEventListener('click', (e) => {
242
+ e.stopPropagation();
243
+ removeWithAnimation(toastElement, () => {
244
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
245
+ if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);
246
+ });
247
+ });
248
+ toastElement.appendChild(closeBtn);
249
+ }
250
+ if (closeOnOverlayClick) {
251
+ overlay.addEventListener('click', (e) => {
252
+ if (e.target === overlay) {
253
+ // Overlay background click -> cancel
254
+ if (toastElement.result) {
255
+ // let the confirm logic close and cleanup
256
+ if (typeof resultResolver === 'function') {
257
+ resultResolver(false);
258
+ }
259
+ }
260
+ removeWithAnimation(toastElement, () => {
261
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
262
+ if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);
263
+ });
264
+ }
265
+ });
266
+ }
267
+ } else {
268
+ // Standard positioned container
269
+ let container = document.querySelector(`.ts-toast-container.${position}`);
270
+ if (!container) {
271
+ container = document.createElement('div');
272
+ container.className = `ts-toast-container ${position}`;
273
+ document.body.appendChild(container);
274
+ }
275
+ container.appendChild(toastElement);
78
276
  }
79
277
 
80
- container.appendChild(toastElement);
81
-
82
278
  // Trigger the onShow event if provided
83
279
  if (onShow && typeof onShow === 'function') {
84
280
  onShow(toastElement);
@@ -92,88 +288,63 @@
92
288
  // Handle Loader and Icon
93
289
  if (showLoader && loader) {
94
290
  setTimeout(() => {
291
+ // Skip auto-complete if controlled by toast.loading()
292
+ if (toastElement._managedByLoading) return;
95
293
  loader.classList.add('done');
96
294
  loader.remove();
97
- if (!toastElement.querySelector('.ts-toast-icon img')) {
98
- toastElement.appendChild(iconElement); // Add icon only if not present
295
+ if (!toastElement.contains(iconElement)) {
296
+ if (isConfirm && contentRow) contentRow.appendChild(iconElement);
297
+ else toastElement.appendChild(iconElement); // Add icon only if not present
99
298
  }
100
299
  }, 2000); // Simulate a loading period of 2 seconds
101
300
  }
102
301
  if (!showLoader) {
103
- toastElement.appendChild(iconElement);
104
- }
105
-
106
- // Auto remove after the duration
107
- const autoRemove = setTimeout(() => {
108
- // Get the current animation applied to the toast
109
- const currentAnimation = toastElement.style.animation || '';
110
-
111
- // Determine the reverse animation based on the current animation
112
- let reverseAnimation = '';
113
- if (currentAnimation.includes('slide-top')) {
114
- reverseAnimation = 'slide-top-reverse';
115
- } else if (currentAnimation.includes('slide-bottom')) {
116
- reverseAnimation = 'slide-bottom-reverse';
117
- } else if (currentAnimation.includes('slide-left')) {
118
- reverseAnimation = 'slide-left-reverse';
119
- } else if (currentAnimation.includes('slide-right')) {
120
- reverseAnimation = 'slide-right-reverse';
121
- } else if (currentAnimation.includes('zoom-in')) {
122
- reverseAnimation = 'zoom-out'; // You could define a zoom-out animation if needed
302
+ // For confirm, icon already added above inside contentRow; avoid moving it
303
+ if (!isConfirm && !toastElement.contains(iconElement)) {
304
+ toastElement.appendChild(iconElement);
123
305
  }
306
+ }
124
307
 
125
- // Apply the reverse animation dynamically
126
- toastElement.classList.add('slide-out');
127
- toastElement.style.animation = `${reverseAnimation} 0.5s ease`; // Dynamically apply the reverse animation
128
-
129
- // Wait for the reverse animation to finish before removing the toast
130
- setTimeout(() => {
131
- toastElement.classList.remove('show', 'slide-out');
132
- toastElement.style.animation = ''; // Reset the animation property
133
- if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
134
- if (onDismiss && typeof onDismiss === 'function') {
135
- onDismiss(toastElement); // Trigger the onDismiss event if provided
136
- }
137
- }, 500); // Match the duration of the reverse animation
138
- }, duration);
139
-
140
- toastElement._autoRemove = autoRemove;
141
-
142
- // Add event listener for closing the toast when clicked
143
- toastElement.addEventListener('click', () => {
144
- clearTimeout(toastElement._autoRemove); // Clear the auto-remove timeout
145
- toastElement.classList.remove('show');
146
- setTimeout(() => {
147
- if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
148
- }, 500); // Match the duration of the closing animation
308
+ // Auto remove after the duration (skip for confirm mode or when duration <= 0)
309
+ if (!isConfirm && duration > 0) {
310
+ const autoRemove = setTimeout(() => {
311
+ removeWithAnimation(toastElement, () => {
312
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
313
+ });
314
+ }, duration);
315
+ toastElement._autoRemove = autoRemove;
316
+ }
149
317
 
150
- if (onClick && typeof onClick === 'function') {
151
- onClick(toastElement); // Trigger the onClick event if provided
152
- }
153
- });
318
+ // Add event listener for closing the toast when clicked (disabled in confirm mode)
319
+ if (!isConfirm && dismissOnClick) {
320
+ toastElement.addEventListener('click', () => {
321
+ if (toastElement._autoRemove) clearTimeout(toastElement._autoRemove); // Clear the auto-remove timeout
322
+ removeWithAnimation(toastElement, () => {
323
+ if (onClick && typeof onClick === 'function') onClick(toastElement);
324
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
325
+ });
326
+ });
327
+ }
154
328
 
155
329
  // Add swipe event listeners for mobile dismissal
156
- let touchStartX = 0;
157
- let touchEndX = 0;
158
-
159
- toastElement.addEventListener('touchstart', (e) => {
160
- touchStartX = e.changedTouches[0].screenX;
161
- });
162
-
163
- toastElement.addEventListener('touchend', (e) => {
164
- touchEndX = e.changedTouches[0].screenX;
165
- if (Math.abs(touchStartX - touchEndX) > 50) { // Swipe distance threshold
166
- clearTimeout(toastElement._autoRemove); // Clear the auto-remove timeout
167
- toastElement.classList.remove('show');
168
- setTimeout(() => {
169
- if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
170
- }, 500); // Match the duration of the closing animation
171
-
172
- if (onDismiss && typeof onDismiss === 'function') {
173
- onDismiss(toastElement); // Trigger the onDismiss event if provided
330
+ if (!isConfirm) {
331
+ let touchStartX = 0;
332
+ let touchEndX = 0;
333
+
334
+ toastElement.addEventListener('touchstart', (e) => {
335
+ touchStartX = e.changedTouches[0].screenX;
336
+ });
337
+
338
+ toastElement.addEventListener('touchend', (e) => {
339
+ touchEndX = e.changedTouches[0].screenX;
340
+ if (Math.abs(touchStartX - touchEndX) > 50) { // Swipe distance threshold
341
+ if (toastElement._autoRemove) clearTimeout(toastElement._autoRemove);
342
+ removeWithAnimation(toastElement, () => {
343
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
344
+ });
174
345
  }
175
- }
176
- });
346
+ });
347
+ }
177
348
 
178
349
  return toastElement;
179
350
  };
@@ -205,7 +376,10 @@
205
376
  if (oldLoader) oldLoader.remove();
206
377
 
207
378
  // Update toast class and message
208
- toastElement.className = `toast toast-${type} show ${position}`;
379
+ if (type) {
380
+ // keep ts- prefix consistent
381
+ toastElement.className = `ts-toast ts-toast-${type} show ${position}`;
382
+ }
209
383
  const toastBody = toastElement.querySelector('.ts-toast-body');
210
384
  if (toastBody) {
211
385
  toastBody.innerHTML = message;
@@ -216,8 +390,9 @@
216
390
  oldIcon.remove(); // Remove the old icon first
217
391
  }
218
392
 
219
- const iconElement = document.createElement('span');
220
- iconElement.className = 'toast-icon';
393
+ const iconElement = document.createElement('span');
394
+ iconElement.className = 'ts-toast-icon';
395
+ iconElement.style.display = 'flex';
221
396
 
222
397
  if (icon) {
223
398
  iconElement.textContent = icon;
@@ -228,13 +403,13 @@
228
403
  img.style.objectFit = 'contain';
229
404
 
230
405
  if (type === 'success') {
231
- img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/success.gif';
406
+ img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/success.gif';
232
407
  } else if (type === 'error') {
233
- img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/error.gif';
408
+ img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/error.gif';
234
409
  } else if (type === 'info') {
235
- img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/info.gif';
410
+ img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/info.gif';
236
411
  } else if (type === 'warning') {
237
- img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/warning.gif';
412
+ img.src = 'https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/warning.gif';
238
413
  }
239
414
 
240
415
  iconElement.appendChild(img);
@@ -246,7 +421,7 @@
246
421
  // Handle loader if requested
247
422
  if (showLoader) {
248
423
  const loader = document.createElement('div');
249
- loader.className = 'toast-loader';
424
+ loader.className = 'ts-toast-loader';
250
425
  toastElement.appendChild(loader);
251
426
  setTimeout(() => {
252
427
  loader.classList.add('done');
@@ -260,36 +435,29 @@
260
435
 
261
436
  // Set the auto-remove timer again to ensure toast disappears after the duration
262
437
  const autoRemove = setTimeout(() => {
263
- // Get the current animation applied to the toast
264
- const currentAnimation = toastElement.style.animation || '';
265
-
266
- // Determine the reverse animation based on the current animation
267
- let reverseAnimation = '';
268
- if (currentAnimation.includes('slide-top')) {
269
- reverseAnimation = 'slide-top-reverse';
270
- } else if (currentAnimation.includes('slide-bottom')) {
271
- reverseAnimation = 'slide-bottom-reverse';
272
- } else if (currentAnimation.includes('slide-left')) {
273
- reverseAnimation = 'slide-left-reverse';
274
- } else if (currentAnimation.includes('slide-right')) {
275
- reverseAnimation = 'slide-right-reverse';
276
- } else if (currentAnimation.includes('zoom-in')) {
277
- reverseAnimation = 'zoom-out'; // You could define a zoom-out animation if needed
278
- }
279
-
280
- // Apply the reverse animation dynamically
281
- toastElement.classList.add('slide-out');
282
- toastElement.style.animation = `${reverseAnimation} 0.5s ease`; // Dynamically apply the reverse animation
438
+ // Use the same helper removal used above
439
+ // Re-create the helper here in case update() is used alone
440
+ const removeWithAnimation = (el, cb) => {
441
+ const currentAnimation = el.style.animation || '';
442
+ let reverseAnimation = '';
443
+ if (currentAnimation.includes('slide-top')) reverseAnimation = 'slide-top-reverse';
444
+ else if (currentAnimation.includes('slide-bottom')) reverseAnimation = 'slide-bottom-reverse';
445
+ else if (currentAnimation.includes('slide-left')) reverseAnimation = 'slide-left-reverse';
446
+ else if (currentAnimation.includes('slide-right')) reverseAnimation = 'slide-right-reverse';
447
+ else if (currentAnimation.includes('zoom-in')) reverseAnimation = 'zoom-out';
448
+ el.classList.add('slide-out');
449
+ el.style.animation = `${reverseAnimation} 0.5s ease`;
450
+ setTimeout(() => {
451
+ el.classList.remove('show', 'slide-out');
452
+ el.style.animation = '';
453
+ if (el.parentNode) el.parentNode.removeChild(el);
454
+ if (typeof cb === 'function') cb();
455
+ }, 500);
456
+ };
283
457
 
284
- // Wait for the reverse animation to finish before removing the toast
285
- setTimeout(() => {
286
- toastElement.classList.remove('show', 'slide-out');
287
- toastElement.style.animation = ''; // Reset the animation property
288
- if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
289
- if (onDismiss && typeof onDismiss === 'function') {
290
- onDismiss(toastElement); // Trigger the onDismiss event if provided
291
- }
292
- }, 500); // Match the duration of the reverse animation
458
+ removeWithAnimation(toastElement, () => {
459
+ if (onDismiss && typeof onDismiss === 'function') onDismiss(toastElement);
460
+ });
293
461
  }, duration);
294
462
 
295
463
  toastElement._autoRemove = autoRemove; // Re-set the auto-remove timer
@@ -299,7 +467,7 @@
299
467
  const toastElement = toast(message, {
300
468
  ...options,
301
469
  type: options.type || 'info', // Default type is 'info'
302
- duration: 1000, // Long duration for manual closing
470
+ duration: 0, // Sticky until manually updated/closed
303
471
  showLoader: true, // Always show loader during loading
304
472
  icon: null
305
473
  });
@@ -316,32 +484,67 @@
316
484
  if (!iconElement) {
317
485
  iconElement = document.createElement('span');
318
486
  iconElement.className = 'ts-toast-icon';
487
+ iconElement.style.display = 'flex';
319
488
  toastElement.appendChild(iconElement);
320
489
  }
321
490
 
491
+ // mark as managed by loading flow to avoid internal auto-complete
492
+ toastElement._managedByLoading = true;
493
+
322
494
  // Ensure loader is handled properly
323
495
  if (loader) {
324
496
  setTimeout(() => {
325
- loader.classList.add('done');
497
+ // Keep spinning until update() decides otherwise
498
+ if (!toastElement._managedByLoading) loader.classList.add('done');
326
499
  }, 2000); // Simulate a loading period of 2 seconds
327
500
  }
328
501
 
329
502
  return {
330
503
  update: (newMessage, newOptions = {}) => {
504
+ // Let update manage completion: stop managing/finish loader
505
+ toastElement._managedByLoading = false;
331
506
  toast.update(toastElement, newMessage, {
332
507
  ...newOptions,
333
508
  showLoader: false // Disable loader when updating the message
334
509
  });
335
510
  },
336
511
  close: () => {
337
- toastElement.classList.remove('show');
512
+ if (toastElement._autoRemove) clearTimeout(toastElement._autoRemove);
513
+ const currentAnimation = toastElement.style.animation || '';
514
+ let reverseAnimation = '';
515
+ if (currentAnimation.includes('slide-top')) reverseAnimation = 'slide-top-reverse';
516
+ else if (currentAnimation.includes('slide-bottom')) reverseAnimation = 'slide-bottom-reverse';
517
+ else if (currentAnimation.includes('slide-left')) reverseAnimation = 'slide-left-reverse';
518
+ else if (currentAnimation.includes('slide-right')) reverseAnimation = 'slide-right-reverse';
519
+ else if (currentAnimation.includes('zoom-in')) reverseAnimation = 'zoom-out';
520
+ toastElement.classList.add('slide-out');
521
+ toastElement.style.animation = `${reverseAnimation} 0.5s ease`;
338
522
  setTimeout(() => {
523
+ toastElement.classList.remove('show', 'slide-out');
524
+ toastElement.style.animation = '';
339
525
  if (toastElement.parentNode) toastElement.parentNode.removeChild(toastElement);
340
526
  }, 500);
341
527
  }
342
528
  };
343
529
  };
344
530
 
531
+ // Convenience API: swal-like confirm dialog
532
+ // Usage: toast.confirm('Are you sure?', { type: 'warning', confirmText: 'Yes', cancelText: 'No' }).then(ok => {...})
533
+ toast.confirm = function (message, options = {}) {
534
+ return new Promise((resolve) => {
535
+ const el = toast(message, {
536
+ ...options,
537
+ mode: 'confirm',
538
+ duration: 0, // prevent auto-dismiss
539
+ dismissOnClick: false,
540
+ onResult: (val) => resolve(!!val)
541
+ });
542
+ // If consumer needs the element, it is returned by toast() but we ignore here.
543
+ // They can still call toast(...) with mode: 'confirm' to get the element and read el.result
544
+ void el; // no-op
545
+ });
546
+ };
547
+
345
548
  // Expose globally
346
549
  window.toast = toast;
347
550
  })();
package/toast.min.js CHANGED
@@ -1 +1 @@
1
- !function(){"use strict";const e=document.createElement("link");e.rel="stylesheet",e.href="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.0.7/assets/css/toast.min.css",document.head.appendChild(e);const t=function(e,t={}){const{position:s="top-right",animation:o="slide-right",type:n="info",duration:i=3e3,icon:a=null,showLoader:l=!1,onClick:c=null,onShow:r=null,onDismiss:d=null}=t,m=document.createElement("div");m.className=`ts-toast ts-toast-${n}`,m.style.animation=`${o} 0.5s ease`,m.style.flexDirection="row-reverse",m.style.justifyContent="flex-end";const u=document.createElement("span");if(u.className="ts-toast-icon",a)u.textContent=a;else{const e=document.createElement("img");e.src="",e.style.width="30px",e.style.height="30px",e.style.objectFit="contain";const t="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/",s=(new Date).getTime();"success"===n?e.src=`${t}success.gif?t=${s}`:"error"===n?e.src=`${t}error.gif?t=${s}`:"info"===n?e.src=`${t}info.gif?t=${s}`:"warning"===n&&(e.src=`${t}warning.gif?t=${s}`),u.appendChild(e)}const p=document.createElement("div");p.className="ts-toast-body",p.innerHTML=e,m.appendChild(p);let h=null;l&&(h=document.createElement("div"),h.className="ts-toast-loader",m.appendChild(h));let f=document.querySelector(`.ts-toast-container.${s}`);f||(f=document.createElement("div"),f.className=`ts-toast-container ${s}`,document.body.appendChild(f)),f.appendChild(m),r&&"function"==typeof r&&r(m),setTimeout((()=>{m.classList.add("show")}),100),l&&h&&setTimeout((()=>{h.classList.add("done"),h.remove(),m.querySelector(".ts-toast-icon img")||m.appendChild(u)}),2e3),l||m.appendChild(u);const g=setTimeout((()=>{const e=m.style.animation||"";let t="";e.includes("slide-top")?t="slide-top-reverse":e.includes("slide-bottom")?t="slide-bottom-reverse":e.includes("slide-left")?t="slide-left-reverse":e.includes("slide-right")?t="slide-right-reverse":e.includes("zoom-in")&&(t="zoom-out"),m.classList.add("slide-out"),m.style.animation=`${t} 0.5s ease`,setTimeout((()=>{m.classList.remove("show","slide-out"),m.style.animation="",m.parentNode&&m.parentNode.removeChild(m),d&&"function"==typeof d&&d(m)}),500)}),i);m._autoRemove=g,m.addEventListener("click",(()=>{clearTimeout(m._autoRemove),m.classList.remove("show"),setTimeout((()=>{m.parentNode&&m.parentNode.removeChild(m)}),500),c&&"function"==typeof c&&c(m)}));let v=0,y=0;return m.addEventListener("touchstart",(e=>{v=e.changedTouches[0].screenX})),m.addEventListener("touchend",(e=>{y=e.changedTouches[0].screenX,Math.abs(v-y)>50&&(clearTimeout(m._autoRemove),m.classList.remove("show"),setTimeout((()=>{m.parentNode&&m.parentNode.removeChild(m)}),500),d&&"function"==typeof d&&d(m))})),m};t.success=function(e,s){t(e,{...s,type:"success"})},t.error=function(e,s){t(e,{...s,type:"error"})},t.update=function(e,t,s={}){const{type:o=null,icon:n=null,showLoader:i=!1,duration:a=3e3,position:l="top-right",onClick:c=null,onShow:r=null,onDismiss:d=null}=s,m=e.querySelector(".ts-toast-loader"),u=e.querySelector(".ts-toast-icon");m&&m.remove(),e.className=`toast toast-${o} show ${l}`;const p=e.querySelector(".ts-toast-body");p&&(p.innerHTML=t),u&&u.remove();const h=document.createElement("span");if(h.className="toast-icon",n)h.textContent=n;else{const e=document.createElement("img");e.style.width="30px",e.style.height="30px",e.style.objectFit="contain","success"===o?e.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/success.gif":"error"===o?e.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/error.gif":"info"===o?e.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/info.gif":"warning"===o&&(e.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@latest/assets/img/warning.gif"),h.appendChild(e)}if(e.appendChild(h),i){const t=document.createElement("div");t.className="toast-loader",e.appendChild(t),setTimeout((()=>{t.classList.add("done")}),2e3)}e._autoRemove&&clearTimeout(e._autoRemove);const f=setTimeout((()=>{const t=e.style.animation||"";let s="";t.includes("slide-top")?s="slide-top-reverse":t.includes("slide-bottom")?s="slide-bottom-reverse":t.includes("slide-left")?s="slide-left-reverse":t.includes("slide-right")?s="slide-right-reverse":t.includes("zoom-in")&&(s="zoom-out"),e.classList.add("slide-out"),e.style.animation=`${s} 0.5s ease`,setTimeout((()=>{e.classList.remove("show","slide-out"),e.style.animation="",e.parentNode&&e.parentNode.removeChild(e),d&&"function"==typeof d&&d(e)}),500)}),a);e._autoRemove=f},t.loading=function(e,s={}){const o=t(e,{...s,type:s.type||"info",duration:1e3,showLoader:!0,icon:null});requestAnimationFrame((()=>{o.classList.add("show")}));const n=o.querySelector(".ts-toast-loader");let i=o.querySelector(".ts-toast-icon");return i||(i=document.createElement("span"),i.className="ts-toast-icon",o.appendChild(i)),n&&setTimeout((()=>{n.classList.add("done")}),2e3),{update:(e,s={})=>{t.update(o,e,{...s,showLoader:!1})},close:()=>{o.classList.remove("show"),setTimeout((()=>{o.parentNode&&o.parentNode.removeChild(o)}),500)}}},window.toast=t}();
1
+ !function(){"use strict";const t=document.createElement("link");t.rel="stylesheet",t.href="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/css/toast.min.css",document.head.appendChild(t),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-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 e=function(t,e={}){const{position:o="top-right",animation:s="slide-right",type:n="info",duration:i=3e3,icon:a=null,showLoader:l=!1,mode:r="alert",title:c=null,confirmText:d="Yes",cancelText:m="No",confirmButtonBg:u=null,confirmButtonColor:p=null,cancelButtonBg:f=null,cancelButtonColor:g=null,onConfirm:h=null,onCancel:y=null,onResult:v=null,useOverlay:x=!0,closeOnOverlayClick:b=!0,showClose:C=!1,dismissOnClick:w=!0,onClick:L=null,onShow:N=null,onDismiss:E=null}=e,k="confirm"===r||"swal"===r,T="string"==typeof e.animation&&e.animation.trim()?e.animation.trim():k?"zoom-in":o.startsWith("top")?"slide-top":o.startsWith("bottom")?"slide-bottom":o.endsWith("left")?"slide-left":"slide-right",$=(t,e)=>{const o=t.style.animation||"";let s="";o.includes("slide-top")?s="slide-top-reverse":o.includes("slide-bottom")?s="slide-bottom-reverse":o.includes("slide-left")?s="slide-left-reverse":o.includes("slide-right")?s="slide-right-reverse":o.includes("zoom-in")&&(s="zoom-out"),t.classList.add("slide-out"),t.style.animation=`${s} 0.5s ease`,setTimeout((()=>{t.classList.remove("show","slide-out"),t.style.animation="",t.parentNode&&t.parentNode.removeChild(t),"function"==typeof e&&e()}),500)},j=document.createElement("div");j.className=`ts-toast ts-toast-${n}${k?" ts-toast-confirm":""}`,j.style.animation=`${T} 0.5s ease`,k||(j.style.flexDirection="row-reverse",j.style.justifyContent="flex-end");const _=document.createElement("span");if(_.className="ts-toast-icon",_.style.display="flex",a)_.textContent=a;else{const t=document.createElement("img");t.src="",t.style.width="30px",t.style.height="30px",t.style.objectFit="contain";const e="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/",o=(new Date).getTime();"success"===n?t.src=`${e}success.gif?t=${o}`:"error"===n?t.src=`${e}error.gif?t=${o}`:"info"===n?t.src=`${e}info.gif?t=${o}`:"warning"===n&&(t.src=`${e}warning.gif?t=${o}`),_.appendChild(t)}const R=document.createElement("div");R.className="ts-toast-body",R.innerHTML=t;let B=null;if(k){if(B=document.createElement("div"),B.className="ts-toast-content",B.appendChild(_),c){const t=document.createElement("div");t.className="ts-toast-title",t.textContent=c,B.appendChild(t)}B.appendChild(R),j.appendChild(B)}else j.appendChild(R);let z=null,S=null;if(k){z=document.createElement("div"),z.className="ts-toast-actions";const t=document.createElement("button");t.className="ts-toast-btn cancel",t.textContent=m;const e=document.createElement("button");e.className="ts-toast-btn confirm",e.textContent=d,f&&(t.style.background=f),g&&(t.style.color=g),u&&(e.style.background=u),p&&(e.style.color=p),z.appendChild(t),z.appendChild(e),j.appendChild(z),j.result=new Promise((t=>{S=t}));const o=t=>{S&&S(t),t&&"function"==typeof h&&h(j),t||"function"!=typeof y||y(j),"function"==typeof v&&v(t,j),$(j,(()=>{E&&"function"==typeof E&&E(j),O&&O.parentNode&&O.parentNode.removeChild(O)}))};t.addEventListener("click",(t=>{t.stopPropagation(),o(!1)})),e.addEventListener("click",(t=>{t.stopPropagation(),o(!0)}))}let q=null;l&&(q=document.createElement("div"),q.className="ts-toast-loader",j.appendChild(q));let O=null;if(k&&x){if(O=document.createElement("div"),O.className="ts-toast-overlay",document.body.appendChild(O),O.appendChild(j),C){const t=document.createElement("button");t.className="ts-toast-close",t.setAttribute("aria-label","Close"),t.innerHTML="&times;",t.addEventListener("click",(t=>{t.stopPropagation(),$(j,(()=>{E&&"function"==typeof E&&E(j),O&&O.parentNode&&O.parentNode.removeChild(O)}))})),j.appendChild(t)}b&&O.addEventListener("click",(t=>{t.target===O&&(j.result&&"function"==typeof S&&S(!1),$(j,(()=>{E&&"function"==typeof E&&E(j),O&&O.parentNode&&O.parentNode.removeChild(O)})))}))}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.appendChild(j)}if(N&&"function"==typeof N&&N(j),setTimeout((()=>{j.classList.add("show")}),100),l&&q&&setTimeout((()=>{j._managedByLoading||(q.classList.add("done"),q.remove(),j.contains(_)||(k&&B?B.appendChild(_):j.appendChild(_)))}),2e3),l||k||j.contains(_)||j.appendChild(_),!k&&i>0){const t=setTimeout((()=>{$(j,(()=>{E&&"function"==typeof E&&E(j)}))}),i);j._autoRemove=t}if(!k&&w&&j.addEventListener("click",(()=>{j._autoRemove&&clearTimeout(j._autoRemove),$(j,(()=>{L&&"function"==typeof L&&L(j),E&&"function"==typeof E&&E(j)}))})),!k){let t=0,e=0;j.addEventListener("touchstart",(e=>{t=e.changedTouches[0].screenX})),j.addEventListener("touchend",(o=>{e=o.changedTouches[0].screenX,Math.abs(t-e)>50&&(j._autoRemove&&clearTimeout(j._autoRemove),$(j,(()=>{E&&"function"==typeof E&&E(j)})))}))}return j};e.success=function(t,o){e(t,{...o,type:"success"})},e.error=function(t,o){e(t,{...o,type:"error"})},e.update=function(t,e,o={}){const{type:s=null,icon:n=null,showLoader:i=!1,duration:a=3e3,position:l="top-right",onClick:r=null,onShow:c=null,onDismiss:d=null}=o,m=t.querySelector(".ts-toast-loader"),u=t.querySelector(".ts-toast-icon");m&&m.remove(),s&&(t.className=`ts-toast ts-toast-${s} show ${l}`);const p=t.querySelector(".ts-toast-body");p&&(p.innerHTML=e),u&&u.remove();const f=document.createElement("span");if(f.className="ts-toast-icon",f.style.display="flex",n)f.textContent=n;else{const t=document.createElement("img");t.style.width="30px",t.style.height="30px",t.style.objectFit="contain","success"===s?t.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/success.gif":"error"===s?t.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/error.gif":"info"===s?t.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/info.gif":"warning"===s&&(t.src="https://cdn.jsdelivr.net/npm/@tsirosgeorge/toastnotification@5.1.1/assets/img/warning.gif"),f.appendChild(t)}if(t.appendChild(f),i){const e=document.createElement("div");e.className="ts-toast-loader",t.appendChild(e),setTimeout((()=>{e.classList.add("done")}),2e3)}t._autoRemove&&clearTimeout(t._autoRemove);const g=setTimeout((()=>{((t,e)=>{const o=t.style.animation||"";let s="";o.includes("slide-top")?s="slide-top-reverse":o.includes("slide-bottom")?s="slide-bottom-reverse":o.includes("slide-left")?s="slide-left-reverse":o.includes("slide-right")?s="slide-right-reverse":o.includes("zoom-in")&&(s="zoom-out"),t.classList.add("slide-out"),t.style.animation=`${s} 0.5s ease`,setTimeout((()=>{t.classList.remove("show","slide-out"),t.style.animation="",t.parentNode&&t.parentNode.removeChild(t),"function"==typeof e&&e()}),500)})(t,(()=>{d&&"function"==typeof d&&d(t)}))}),a);t._autoRemove=g},e.loading=function(t,o={}){const s=e(t,{...o,type:o.type||"info",duration:0,showLoader:!0,icon:null});requestAnimationFrame((()=>{s.classList.add("show")}));const n=s.querySelector(".ts-toast-loader");let i=s.querySelector(".ts-toast-icon");return i||(i=document.createElement("span"),i.className="ts-toast-icon",i.style.display="flex",s.appendChild(i)),s._managedByLoading=!0,n&&setTimeout((()=>{s._managedByLoading||n.classList.add("done")}),2e3),{update:(t,o={})=>{s._managedByLoading=!1,e.update(s,t,{...o,showLoader:!1})},close:()=>{s._autoRemove&&clearTimeout(s._autoRemove);const t=s.style.animation||"";let e="";t.includes("slide-top")?e="slide-top-reverse":t.includes("slide-bottom")?e="slide-bottom-reverse":t.includes("slide-left")?e="slide-left-reverse":t.includes("slide-right")?e="slide-right-reverse":t.includes("zoom-in")&&(e="zoom-out"),s.classList.add("slide-out"),s.style.animation=`${e} 0.5s ease`,setTimeout((()=>{s.classList.remove("show","slide-out"),s.style.animation="",s.parentNode&&s.parentNode.removeChild(s)}),500)}}},e.confirm=function(t,o={}){return new Promise((s=>{e(t,{...o,mode:"confirm",duration:0,dismissOnClick:!1,onResult:t=>s(!!t)})}))},window.toast=e}();