toastify-pro 1.1.0 → 1.2.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.
@@ -1,11 +1,44 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1
+ (function (factory) {
3
2
  typeof define === 'function' && define.amd ? define(factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ToastifyPro = factory());
5
- })(this, (function () { 'use strict';
3
+ factory();
4
+ })((function () { 'use strict';
6
5
 
6
+ /**
7
+ * ToastifyPro - Modern Toast Notification Library
8
+ * A beautiful, customizable toast notification library with glassmorphism design,
9
+ * Apple AirDrop-style animations, and car swipe exit effects.
10
+ *
11
+ * Features:
12
+ * - Glassmorphism design with backdrop-filter effects
13
+ * - Apple AirDrop-style entrance animations
14
+ * - Position-aware car swipe exit animations
15
+ * - Description support for enhanced messaging
16
+ * - Six theme variants (success, error, info, warning, dark, light)
17
+ * - Progress bar with shimmer effects
18
+ * - Responsive design for mobile devices
19
+ * - Framework agnostic (works with React, Vue, Angular, etc.)
20
+ *
21
+ * @version 1.2.0
22
+ * @author ToastifyPro Team
23
+ * @license MIT
24
+ */
7
25
  class ToastifyPro {
26
+ /**
27
+ * Creates a new ToastifyPro instance
28
+ * @param {Object} options - Configuration options
29
+ * @param {string} options.position - Toast position (top-left, top-right, bottom-left, bottom-right, top-center, bottom-center)
30
+ * @param {number} options.timeout - Auto-dismiss timeout in milliseconds (0 to disable)
31
+ * @param {boolean} options.allowClose - Whether to show close button
32
+ * @param {number} options.maxLength - Maximum message length
33
+ */
8
34
  constructor(options = {}) {
35
+ // Validate options parameter
36
+ if (typeof options !== 'object' || options === null) {
37
+ console.warn('ToastifyPro: Invalid options parameter. Using defaults.');
38
+ options = {};
39
+ }
40
+
41
+ // Merge with default options
9
42
  this.defaultOptions = {
10
43
  position: options.position || "bottom-center", // top-left, top-right, bottom-left, bottom-right, top-center, bottom-center
11
44
  timeout: options.timeout || 3000,
@@ -13,153 +46,710 @@
13
46
  maxLength: options.maxLength || 100,
14
47
  };
15
48
 
16
- // create container only once
49
+ // Validate position
50
+ const validPositions = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top-center', 'bottom-center'];
51
+ if (!validPositions.includes(this.defaultOptions.position)) {
52
+ console.warn(`ToastifyPro: Invalid position "${this.defaultOptions.position}". Using "bottom-center".`);
53
+ this.defaultOptions.position = "bottom-center";
54
+ }
55
+
56
+ // Check if we're in a browser environment
57
+ if (typeof document === 'undefined') {
58
+ throw new Error('ToastifyPro: This library requires a DOM environment (browser).');
59
+ }
60
+
61
+ // Create or reuse container for this position
17
62
  const existing = document.querySelector(
18
63
  `.toastify-pro-container.${this.defaultOptions.position}`
19
64
  );
65
+
20
66
  if (existing) {
21
67
  this.container = existing;
22
68
  } else {
23
- this.container = document.createElement("div");
24
- this.container.className = `toastify-pro-container ${this.defaultOptions.position}`;
25
- document.body.appendChild(this.container);
69
+ try {
70
+ this.container = document.createElement("div");
71
+ this.container.className = `toastify-pro-container ${this.defaultOptions.position}`;
72
+ document.body.appendChild(this.container);
73
+ } catch (error) {
74
+ throw new Error('ToastifyPro: Failed to create container element. DOM may not be ready.');
75
+ }
26
76
  }
27
77
 
78
+ // Inject styles once
28
79
  this.injectStyles();
29
80
  }
30
81
 
82
+ /**
83
+ * Returns the SVG icon for a given toast type
84
+ * @param {string} type - Toast type (success, error, info, warning, dark, light)
85
+ * @returns {string} SVG icon markup
86
+ */
87
+ getIconSVG(type) {
88
+ // Validate type parameter
89
+ if (typeof type !== 'string') {
90
+ console.warn('ToastifyPro: Invalid icon type. Using default info icon.');
91
+ type = 'info';
92
+ }
93
+
94
+ const icons = {
95
+ success: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
96
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="currentColor"/>
97
+ </svg>`,
98
+ error: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
99
+ <path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" fill="currentColor"/>
100
+ </svg>`,
101
+ info: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
102
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" fill="currentColor"/>
103
+ </svg>`,
104
+ warning: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
105
+ <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" fill="currentColor"/>
106
+ </svg>`,
107
+ dark: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
108
+ <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" fill="currentColor"/>
109
+ </svg>`,
110
+ light: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
111
+ <path d="M9 11H7v6h2v-6zm4 0h-2v6h2v-6zm4 0h-2v6h2v-6zm2.5-9H19V1h-2v1H7V1H5v1H4.5C3.11 2 2 3.11 2 4.5v14C2 19.89 3.11 21 4.5 21h15c1.39 0 2.5-1.11 2.5-2.5v-14C22 3.11 20.89 2 19.5 2zm0 16h-15v-11h15v11z" fill="currentColor"/>
112
+ </svg>`
113
+ };
114
+
115
+ return icons[type] || icons.info;
116
+ }
117
+
118
+ /**
119
+ * Injects the CSS styles into the document head
120
+ * Styles include glassmorphism design, animations, and responsive layout
121
+ */
31
122
  injectStyles() {
32
- if (document.getElementById("toastify-pro-styles")) return; // load once
33
- const style = document.createElement("style");
34
- style.id = "toastify-pro-styles";
35
- style.textContent = `
123
+ // Prevent duplicate style injection
124
+ if (document.getElementById("toastify-pro-styles")) return;
125
+
126
+ try {
127
+ const style = document.createElement("style");
128
+ style.id = "toastify-pro-styles";
129
+ style.textContent = `
130
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
131
+
36
132
  .toastify-pro-container {
37
133
  position: fixed;
38
134
  z-index: 9999;
39
135
  display: flex;
40
136
  flex-direction: column;
41
- gap: 10px;
137
+ gap: 16px;
42
138
  pointer-events: none;
43
139
  }
44
- .toastify-pro-container.top-left { top: 20px; left: 20px; align-items: flex-start; }
45
- .toastify-pro-container.top-right { top: 20px; right: 20px; align-items: flex-end; }
46
- .toastify-pro-container.bottom-left { bottom: 20px; left: 20px; align-items: flex-start; }
47
- .toastify-pro-container.bottom-right { bottom: 20px; right: 20px; align-items: flex-end; }
48
- .toastify-pro-container.top-center { top: 20px; left: 50%; transform: translateX(-50%); }
49
- .toastify-pro-container.bottom-center { bottom: 150px; left: 50%; transform: translateX(-50%); }
140
+ .toastify-pro-container.top-left { top: 50px; left: 24px; align-items: flex-start; }
141
+ .toastify-pro-container.top-right { top: 50px; right: 24px; align-items: flex-end; }
142
+ .toastify-pro-container.bottom-left { bottom: 50px; left: 24px; align-items: flex-start; }
143
+ .toastify-pro-container.bottom-right { bottom: 50px; right: 24px; align-items: flex-end; }
144
+ .toastify-pro-container.top-center { top: 50px; left: 50%; transform: translateX(-50%); }
145
+ .toastify-pro-container.bottom-center { bottom: 50px; left: 50%; transform: translateX(-50%); }
50
146
 
51
147
  .toastify-pro {
52
- min-width: 220px;
53
- max-width: 320px;
54
- padding: 12px 18px;
55
- border-radius: 20px;
56
- font-size: 14px;
57
- font-family: sans-serif;
148
+ min-width: 280px;
149
+ max-width: 400px;
150
+ padding: 20px 24px;
151
+ border-radius: 16px;
152
+ font-size: 15px;
153
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
154
+ font-weight: 500;
58
155
  color: white;
59
156
  opacity: 0;
60
- transform: translateY(20px);
61
- transition: all 0.3s ease;
157
+ transform: scale(0.3);
158
+ transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
62
159
  pointer-events: auto;
63
160
  position: relative;
64
161
  display: flex;
65
162
  align-items: center;
66
- justify-content: space-between;
67
- gap: 12px;
163
+ gap: 16px;
164
+ backdrop-filter: blur(20px);
165
+ border: 1px solid rgba(255, 255, 255, 0.1);
166
+ box-shadow:
167
+ 0 20px 25px -5px rgba(0, 0, 0, 0.1),
168
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04),
169
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
170
+ overflow: hidden;
171
+ }
172
+
173
+ .toastify-pro::before {
174
+ content: '';
175
+ position: absolute;
176
+ top: 0;
177
+ left: 0;
178
+ right: 0;
179
+ height: 3px;
180
+ background: linear-gradient(90deg,
181
+ rgba(255, 255, 255, 0.8) 0%,
182
+ rgba(255, 255, 255, 0.4) 50%,
183
+ rgba(255, 255, 255, 0.8) 100%);
184
+ animation: shimmer 2s infinite;
185
+ transition: opacity 0.8s ease;
186
+ }
187
+
188
+ .toastify-pro::after {
189
+ content: '';
190
+ position: absolute;
191
+ bottom: 0;
192
+ left: 0;
193
+ height: 3px;
194
+ background: rgba(255, 255, 255, 0.6);
195
+ animation: progress var(--duration, 5s) linear;
196
+ border-radius: 0 0 16px 16px;
197
+ }
198
+
199
+ @keyframes airdropPop {
200
+ 0% {
201
+ opacity: 0;
202
+ transform: scale(0.3) rotateY(-20deg);
203
+ }
204
+ 30% {
205
+ opacity: 0.8;
206
+ transform: scale(1.1) rotateY(10deg);
207
+ }
208
+ 60% {
209
+ opacity: 1;
210
+ transform: scale(0.98) rotateY(-3deg);
211
+ }
212
+ 100% {
213
+ opacity: 1;
214
+ transform: scale(1) rotateY(0deg);
215
+ }
216
+ }
217
+
218
+ @keyframes carSwipeBottom {
219
+ 0% {
220
+ opacity: 1;
221
+ transform: scale(1) translateY(0);
222
+ }
223
+ 15% {
224
+ opacity: 1;
225
+ transform: scale(1.02) translateY(-8px);
226
+ }
227
+ 100% {
228
+ opacity: 0;
229
+ transform: scale(0.8) translateY(200px);
230
+ }
231
+ }
232
+
233
+ @keyframes carSwipeTop {
234
+ 0% {
235
+ opacity: 1;
236
+ transform: scale(1) translateY(0);
237
+ }
238
+ 15% {
239
+ opacity: 1;
240
+ transform: scale(1.02) translateY(8px);
241
+ }
242
+ 100% {
243
+ opacity: 0;
244
+ transform: scale(0.8) translateY(-200px);
245
+ }
246
+ }
247
+
248
+ @keyframes carSwipeLeft {
249
+ 0% {
250
+ opacity: 1;
251
+ transform: scale(1) translateX(0);
252
+ }
253
+ 15% {
254
+ opacity: 1;
255
+ transform: scale(1.02) translateX(8px);
256
+ }
257
+ 100% {
258
+ opacity: 0;
259
+ transform: scale(0.8) translateX(-300px);
260
+ }
261
+ }
262
+
263
+ @keyframes carSwipeRight {
264
+ 0% {
265
+ opacity: 1;
266
+ transform: scale(1) translateX(0);
267
+ }
268
+ 15% {
269
+ opacity: 1;
270
+ transform: scale(1.02) translateX(-8px);
271
+ }
272
+ 100% {
273
+ opacity: 0;
274
+ transform: scale(0.8) translateX(300px);
275
+ }
276
+ }
277
+
278
+ @keyframes carSwipeCenter {
279
+ 0% {
280
+ opacity: 1;
281
+ transform: scale(1) translateY(0);
282
+ }
283
+ 15% {
284
+ opacity: 1;
285
+ transform: scale(1.02) translateY(-5px);
286
+ }
287
+ 100% {
288
+ opacity: 0;
289
+ transform: scale(0.6) translateY(150px);
290
+ }
291
+ }
292
+
293
+ @keyframes progress {
294
+ 0% { width: 100%; }
295
+ 100% { width: 0%; }
296
+ }
297
+
298
+ @keyframes shimmer {
299
+ 0% { transform: translateX(-100%); }
300
+ 100% { transform: translateX(100%); }
301
+ }
302
+
303
+ .toastify-pro.show {
304
+ opacity: 1;
305
+ transform: scale(1);
306
+ animation: airdropPop 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
307
+ }
308
+
309
+ .toastify-pro.success {
310
+ background: linear-gradient(135deg,
311
+ rgba(34, 197, 94, 0.9) 0%,
312
+ rgba(21, 128, 61, 0.9) 100%);
313
+ border-color: rgba(34, 197, 94, 0.3);
314
+ }
315
+
316
+ .toastify-pro.error {
317
+ background: linear-gradient(135deg,
318
+ rgba(239, 68, 68, 0.9) 0%,
319
+ rgba(185, 28, 28, 0.9) 100%);
320
+ border-color: rgba(239, 68, 68, 0.3);
321
+ }
322
+
323
+ .toastify-pro.info {
324
+ background: linear-gradient(135deg,
325
+ rgba(59, 130, 246, 0.9) 0%,
326
+ rgba(29, 78, 216, 0.9) 100%);
327
+ border-color: rgba(59, 130, 246, 0.3);
328
+ }
329
+
330
+ .toastify-pro.warning {
331
+ background: linear-gradient(135deg,
332
+ rgba(245, 158, 11, 0.9) 0%,
333
+ rgba(217, 119, 6, 0.9) 100%);
334
+ border-color: rgba(245, 158, 11, 0.3);
335
+ }
336
+
337
+ .toastify-pro.dark {
338
+ background: linear-gradient(135deg,
339
+ rgba(15, 23, 42, 0.95) 0%,
340
+ rgba(30, 41, 59, 0.95) 100%);
341
+ border-color: rgba(148, 163, 184, 0.2);
342
+ }
343
+
344
+ .toastify-pro.light {
345
+ background: linear-gradient(135deg,
346
+ rgba(255, 255, 255, 0.95) 0%,
347
+ rgba(248, 250, 252, 0.95) 100%);
348
+ color: #1e293b;
349
+ border-color: rgba(226, 232, 240, 0.8);
350
+ box-shadow:
351
+ 0 20px 25px -5px rgba(0, 0, 0, 0.08),
352
+ 0 10px 10px -5px rgba(0, 0, 0, 0.03);
353
+ }
354
+
355
+ .toastify-pro.light::before {
356
+ background: linear-gradient(90deg,
357
+ rgba(30, 41, 59, 0.8) 0%,
358
+ rgba(30, 41, 59, 0.4) 50%,
359
+ rgba(30, 41, 59, 0.8) 100%);
360
+ }
361
+
362
+ .toastify-pro.light::after {
363
+ background: rgba(30, 41, 59, 0.6);
364
+ }
365
+
366
+ .toastify-pro .toast-icon {
367
+ flex-shrink: 0;
368
+ display: flex;
369
+ align-items: center;
370
+ justify-content: center;
371
+ width: 28px;
372
+ height: 28px;
373
+ border-radius: 50%;
374
+ background: rgba(255, 255, 255, 0.2);
375
+ backdrop-filter: blur(10px);
376
+ animation: iconPulse 2s infinite;
377
+ }
378
+
379
+ @keyframes iconPulse {
380
+ 0%, 100% { transform: scale(1); }
381
+ 50% { transform: scale(1.05); }
382
+ }
383
+
384
+ @keyframes iconBounce {
385
+ 0% { transform: scale(0.2) rotate(-15deg); }
386
+ 40% { transform: scale(1.2) rotate(8deg); }
387
+ 70% { transform: scale(0.95) rotate(-3deg); }
388
+ 100% { transform: scale(1) rotate(0deg); }
389
+ }
390
+
391
+ @keyframes iconCarExit {
392
+ 0% {
393
+ transform: scale(1) rotate(0deg);
394
+ opacity: 1;
395
+ }
396
+ 20% {
397
+ transform: scale(1.1) rotate(-10deg);
398
+ opacity: 0.9;
399
+ }
400
+ 100% {
401
+ transform: scale(0.3) rotate(180deg);
402
+ opacity: 0;
403
+ }
404
+ }
405
+
406
+ .toastify-pro .toast-icon svg {
407
+ width: 18px;
408
+ height: 18px;
409
+ color: inherit;
410
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
411
+ }
412
+
413
+ .toastify-pro.light .toast-icon {
414
+ background: rgba(15, 23, 42, 0.1);
68
415
  }
69
- .toastify-pro.show { opacity: 1; transform: translateY(0); }
70
- .toastify-pro.success { background: rgba(76, 175, 80, 0.9); }
71
- .toastify-pro.error { background: rgba(244, 67, 54, 0.9); }
72
- .toastify-pro.info { background: rgba(33, 150, 243, 0.9); }
73
- .toastify-pro.warning { background: rgba(255, 152, 0, 0.9); }
74
- .toastify-pro.dark { background: rgba(0,0,0,0.85); }
75
- .toastify-pro.light { background: rgba(255,255,255,0.9); color: #000; }
76
416
 
77
417
  .toastify-pro .toast-content {
78
418
  flex: 1;
79
- padding-right: 8px;
419
+ line-height: 1.5;
420
+ font-weight: 500;
421
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
422
+ }
423
+
424
+ .toastify-pro .toast-message {
425
+ font-size: 15px;
426
+ font-weight: 500;
427
+ margin-bottom: 0;
428
+ }
429
+
430
+ .toastify-pro .toast-description {
431
+ font-size: 13px;
432
+ font-weight: 400;
433
+ opacity: 0.85;
434
+ margin-top: 4px;
80
435
  line-height: 1.4;
81
436
  }
82
437
 
83
438
  .toastify-pro .close-btn {
84
439
  cursor: pointer;
85
- font-size: 18px;
440
+ font-size: 20px;
86
441
  color: inherit;
87
- opacity: 0.8;
88
- padding: 2px 4px;
89
- border-radius: 3px;
90
- transition: opacity 0.2s ease, background-color 0.2s ease;
442
+ opacity: 0.7;
443
+ padding: 8px;
444
+ border-radius: 50%;
445
+ transition: all 0.2s ease;
91
446
  flex-shrink: 0;
92
- min-width: 20px;
93
- text-align: center;
447
+ width: 32px;
448
+ height: 32px;
449
+ display: flex;
450
+ align-items: center;
451
+ justify-content: center;
452
+ background: rgba(255, 255, 255, 0.1);
453
+ backdrop-filter: blur(10px);
454
+ font-weight: 300;
94
455
  line-height: 1;
95
456
  }
457
+
96
458
  .toastify-pro .close-btn:hover {
97
459
  opacity: 1;
98
- background-color: rgba(0,0,0,0.1);
460
+ background: rgba(255, 255, 255, 0.2);
461
+ transform: scale(1.1);
99
462
  }
463
+
464
+ .toastify-pro.light .close-btn {
465
+ background: rgba(15, 23, 42, 0.08);
466
+ }
467
+
100
468
  .toastify-pro.light .close-btn:hover {
101
- background-color: rgba(0,0,0,0.05);
469
+ background: rgba(15, 23, 42, 0.15);
470
+ }
471
+
472
+ @media (max-width: 640px) {
473
+ .toastify-pro {
474
+ min-width: 260px;
475
+ max-width: calc(100vw - 48px);
476
+ margin: 0 8px;
477
+ }
478
+
479
+ .toastify-pro-container.top-left,
480
+ .toastify-pro-container.bottom-left { left: 16px; }
481
+ .toastify-pro-container.top-right,
482
+ .toastify-pro-container.bottom-right { right: 16px; }
102
483
  }
103
484
  `;
104
- document.head.appendChild(style);
485
+ document.head.appendChild(style);
486
+ } catch (error) {
487
+ console.error('ToastifyPro: Failed to inject styles:', error);
488
+ }
105
489
  }
106
490
 
491
+ /**
492
+ * Creates and displays a toast notification
493
+ * @param {string} message - Main message text
494
+ * @param {string} type - Toast type (success, error, info, warning, dark, light)
495
+ * @param {Object} opts - Additional options
496
+ * @param {string} opts.description - Optional description text
497
+ * @param {number} opts.timeout - Override default timeout
498
+ * @param {boolean} opts.allowClose - Override close button setting
499
+ * @param {number} opts.maxLength - Override max message length
500
+ */
107
501
  show(message, type = "dark", opts = {}) {
108
- const options = { ...this.defaultOptions, ...opts };
502
+ // Input validation
503
+ if (typeof message !== 'string') {
504
+ console.warn('ToastifyPro: Message must be a string. Converting to string.');
505
+ message = String(message);
506
+ }
109
507
 
110
- const toast = document.createElement("div");
111
- toast.className = `toastify-pro ${type}`;
508
+ if (!message.trim()) {
509
+ console.warn('ToastifyPro: Empty message provided.');
510
+ return;
511
+ }
112
512
 
113
- // Create content wrapper for the message
114
- const contentWrapper = document.createElement("div");
115
- contentWrapper.className = "toast-content";
116
- contentWrapper.textContent = message.substring(0, options.maxLength);
117
- toast.appendChild(contentWrapper);
513
+ // Validate type
514
+ const validTypes = ['success', 'error', 'info', 'warning', 'dark', 'light'];
515
+ if (!validTypes.includes(type)) {
516
+ console.warn(`ToastifyPro: Invalid type "${type}". Using "dark".`);
517
+ type = 'dark';
518
+ }
118
519
 
119
- if (options.allowClose) {
120
- const closeBtn = document.createElement("span");
121
- closeBtn.className = "close-btn";
122
- closeBtn.innerHTML = "&times;";
123
- closeBtn.onclick = () => this.removeToast(toast);
124
- toast.appendChild(closeBtn);
520
+ // Validate and merge options
521
+ if (typeof opts !== 'object' || opts === null) {
522
+ console.warn('ToastifyPro: Invalid options parameter. Using defaults.');
523
+ opts = {};
125
524
  }
126
525
 
127
- this.container.appendChild(toast);
526
+ const options = { ...this.defaultOptions, ...opts };
128
527
 
129
- // show animation
130
- setTimeout(() => toast.classList.add("show"), 50);
528
+ try {
529
+ // Create toast element
530
+ const toast = document.createElement("div");
531
+ toast.className = `toastify-pro ${type}`;
532
+
533
+ // Set duration for progress bar animation
534
+ if (options.timeout > 0) {
535
+ toast.style.setProperty('--duration', `${options.timeout}ms`);
536
+ }
131
537
 
132
- // auto remove
133
- if (options.timeout > 0) {
134
- setTimeout(() => this.removeToast(toast), options.timeout);
538
+ // Create icon wrapper
539
+ const iconWrapper = document.createElement("div");
540
+ iconWrapper.className = "toast-icon";
541
+ iconWrapper.innerHTML = this.getIconSVG(type);
542
+ toast.appendChild(iconWrapper);
543
+
544
+ // Create content wrapper for the message and description
545
+ const contentWrapper = document.createElement("div");
546
+ contentWrapper.className = "toast-content";
547
+
548
+ // Main message
549
+ const messageElement = document.createElement("div");
550
+ messageElement.className = "toast-message";
551
+ messageElement.textContent = message.substring(0, options.maxLength);
552
+ contentWrapper.appendChild(messageElement);
553
+
554
+ // Optional description (if provided)
555
+ if (options.description && typeof options.description === 'string') {
556
+ const descriptionElement = document.createElement("div");
557
+ descriptionElement.className = "toast-description";
558
+ descriptionElement.textContent = options.description.substring(0, options.maxLength * 2);
559
+ contentWrapper.appendChild(descriptionElement);
560
+ }
561
+
562
+ toast.appendChild(contentWrapper);
563
+
564
+ // Add close button if enabled
565
+ if (options.allowClose) {
566
+ const closeBtn = document.createElement("span");
567
+ closeBtn.className = "close-btn";
568
+ closeBtn.innerHTML = "&times;";
569
+ closeBtn.setAttribute('aria-label', 'Close notification');
570
+ closeBtn.onclick = () => this.removeToast(toast);
571
+ toast.appendChild(closeBtn);
572
+ }
573
+
574
+ // Add toast to container
575
+ this.container.appendChild(toast);
576
+
577
+ // Apple AirDrop-style entrance animation
578
+ setTimeout(() => {
579
+ toast.classList.add("show");
580
+ // Add icon bounce effect with Apple-style timing
581
+ const icon = toast.querySelector('.toast-icon');
582
+ if (icon) {
583
+ icon.style.animation = 'iconBounce 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275)';
584
+ }
585
+ }, 10);
586
+
587
+ // Auto-remove after timeout
588
+ if (options.timeout > 0) {
589
+ setTimeout(() => this.removeToast(toast), options.timeout);
590
+ }
591
+
592
+ return toast; // Return element for potential future manipulation
593
+ } catch (error) {
594
+ console.error('ToastifyPro: Failed to create toast:', error);
135
595
  }
136
596
  }
137
597
 
598
+ /**
599
+ * Removes a toast with position-aware car swipe animation
600
+ * @param {HTMLElement} toast - Toast element to remove
601
+ */
138
602
  removeToast(toast) {
139
- toast.classList.remove("show");
140
- setTimeout(() => toast.remove(), 300);
603
+ if (!toast || !toast.parentNode) {
604
+ console.warn('ToastifyPro: Invalid toast element for removal.');
605
+ return;
606
+ }
607
+
608
+ try {
609
+ // Detect position to choose the right swipe direction
610
+ const container = toast.parentNode;
611
+ const position = container.className.split(' ')[1]; // get position class
612
+
613
+ let swipeAnimation = 'carSwipeBottom'; // default fallback
614
+
615
+ // Choose animation based on position - car swipes away from screen edge
616
+ if (position.includes('bottom')) {
617
+ swipeAnimation = 'carSwipeBottom'; // swipe down off screen
618
+ } else if (position.includes('top')) {
619
+ swipeAnimation = 'carSwipeTop'; // swipe up off screen
620
+ } else if (position.includes('left')) {
621
+ swipeAnimation = 'carSwipeLeft'; // swipe left off screen
622
+ } else if (position.includes('right')) {
623
+ swipeAnimation = 'carSwipeRight'; // swipe right off screen
624
+ } else if (position.includes('center')) {
625
+ swipeAnimation = 'carSwipeCenter'; // swipe down for center
626
+ }
627
+
628
+ // Apply fast car swipe animation with improved easing
629
+ toast.style.animation = `${swipeAnimation} 0.4s cubic-bezier(0.4, 0.0, 1, 1) forwards`;
630
+
631
+ // Add spinning icon animation for extra polish
632
+ const icon = toast.querySelector('.toast-icon');
633
+ if (icon) {
634
+ icon.style.animation = 'iconCarExit 0.4s cubic-bezier(0.4, 0.0, 1, 1) forwards';
635
+ }
636
+
637
+ // Remove element after animation completes
638
+ setTimeout(() => {
639
+ if (toast.parentNode) {
640
+ toast.remove();
641
+ }
642
+ }, 400);
643
+ } catch (error) {
644
+ console.error('ToastifyPro: Error removing toast:', error);
645
+ // Fallback: remove immediately if animation fails
646
+ if (toast.parentNode) {
647
+ toast.remove();
648
+ }
649
+ }
141
650
  }
142
651
 
652
+ /**
653
+ * Shows a success toast notification
654
+ * @param {string} msg - Main message
655
+ * @param {string|Object} opts - Description string or options object
656
+ */
143
657
  success(msg, opts) {
658
+ // Handle both (message) and (message, description) formats
659
+ if (typeof opts === 'string') {
660
+ opts = { description: opts };
661
+ }
144
662
  this.show(msg, "success", opts);
145
663
  }
664
+
665
+ /**
666
+ * Shows an error toast notification
667
+ * @param {string} msg - Main message
668
+ * @param {string|Object} opts - Description string or options object
669
+ */
146
670
  error(msg, opts) {
671
+ if (typeof opts === 'string') {
672
+ opts = { description: opts };
673
+ }
147
674
  this.show(msg, "error", opts);
148
675
  }
676
+
677
+ /**
678
+ * Shows an info toast notification
679
+ * @param {string} msg - Main message
680
+ * @param {string|Object} opts - Description string or options object
681
+ */
149
682
  info(msg, opts) {
683
+ if (typeof opts === 'string') {
684
+ opts = { description: opts };
685
+ }
150
686
  this.show(msg, "info", opts);
151
687
  }
688
+
689
+ /**
690
+ * Shows a warning toast notification
691
+ * @param {string} msg - Main message
692
+ * @param {string|Object} opts - Description string or options object
693
+ */
152
694
  warning(msg, opts) {
695
+ if (typeof opts === 'string') {
696
+ opts = { description: opts };
697
+ }
153
698
  this.show(msg, "warning", opts);
154
699
  }
700
+
701
+ /**
702
+ * Shows a dark-themed toast notification
703
+ * @param {string} msg - Main message
704
+ * @param {string|Object} opts - Description string or options object
705
+ */
155
706
  dark(msg, opts) {
707
+ if (typeof opts === 'string') {
708
+ opts = { description: opts };
709
+ }
156
710
  this.show(msg, "dark", opts);
157
711
  }
712
+
713
+ /**
714
+ * Shows a light-themed toast notification
715
+ * @param {string} msg - Main message
716
+ * @param {string|Object} opts - Description string or options object
717
+ */
158
718
  light(msg, opts) {
719
+ if (typeof opts === 'string') {
720
+ opts = { description: opts };
721
+ }
159
722
  this.show(msg, "light", opts);
160
723
  }
724
+ }
725
+
726
+ /**
727
+ * Export for different environments
728
+ * Supports CommonJS (Node.js), AMD, and browser globals
729
+ */
730
+
731
+ // CommonJS export (Node.js/npm)
732
+ if (typeof module !== 'undefined' && module.exports) {
733
+ module.exports = ToastifyPro;
734
+ }
735
+
736
+ // ES6 module export
737
+ if (typeof exports !== 'undefined') {
738
+ exports.ToastifyPro = ToastifyPro;
739
+ exports.default = ToastifyPro;
740
+ }
741
+
742
+ // AMD export (RequireJS)
743
+ if (typeof define === 'function' && define.amd) {
744
+ define(function() {
745
+ return ToastifyPro;
746
+ });
747
+ }
748
+
749
+ // Browser global
750
+ if (typeof window !== 'undefined') {
751
+ window.ToastifyPro = ToastifyPro;
161
752
  }
162
753
 
163
- return ToastifyPro;
164
-
165
754
  }));
755
+ //# sourceMappingURL=toastify-pro.umd.js.map