toastify-pro 1.3.0 → 1.4.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 +115 -57
- package/dist/toastify-pro.esm.js +427 -72
- package/dist/toastify-pro.esm.js.map +1 -1
- package/dist/toastify-pro.umd.js +427 -72
- package/dist/toastify-pro.umd.js.map +1 -1
- package/dist/toastify-pro.umd.min.js +5 -2
- package/dist/toastify-pro.umd.min.js.map +1 -1
- package/package.json +2 -2
- package/src/toastify-pro.js +427 -72
package/src/toastify-pro.js
CHANGED
|
@@ -15,11 +15,18 @@
|
|
|
15
15
|
* - Confirmation dialogs with customizable buttons and callbacks
|
|
16
16
|
* - Center position support for enhanced focus
|
|
17
17
|
* - Independent positioning for confirmations
|
|
18
|
+
* - Loading states for async operations
|
|
19
|
+
* - Custom gradient colors with primaryColor/secondaryColor
|
|
20
|
+
* - Single instance mode with shake animation
|
|
18
21
|
*
|
|
19
|
-
* @version 1.
|
|
22
|
+
* @version 1.4.0
|
|
20
23
|
* @author ToastifyPro Team
|
|
21
24
|
* @license MIT
|
|
22
25
|
*/
|
|
26
|
+
|
|
27
|
+
// Global active confirmation tracker (shared across all instances)
|
|
28
|
+
let globalActiveConfirmation = null;
|
|
29
|
+
|
|
23
30
|
class ToastifyPro {
|
|
24
31
|
/**
|
|
25
32
|
* Creates a new ToastifyPro instance
|
|
@@ -299,6 +306,26 @@ class ToastifyPro {
|
|
|
299
306
|
100% { transform: translateX(100%); }
|
|
300
307
|
}
|
|
301
308
|
|
|
309
|
+
@keyframes shake {
|
|
310
|
+
0%, 100% { transform: translate(0, 0); }
|
|
311
|
+
10%, 30%, 50%, 70%, 90% { transform: translate(-10px, 0); }
|
|
312
|
+
20%, 40%, 60%, 80% { transform: translate(10px, 0); }
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
@keyframes shakeCenter {
|
|
316
|
+
0%, 100% { transform: scale(1) translateX(0); }
|
|
317
|
+
10%, 30%, 50%, 70%, 90% { transform: scale(1) translateX(-10px); }
|
|
318
|
+
20%, 40%, 60%, 80% { transform: scale(1) translateX(10px); }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.toastify-pro.shake {
|
|
322
|
+
animation: shake 0.6s cubic-bezier(0.36, 0.07, 0.19, 0.97) !important;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.toastify-pro-container.center .toastify-pro.shake {
|
|
326
|
+
animation: shakeCenter 0.6s cubic-bezier(0.36, 0.07, 0.19, 0.97) !important;
|
|
327
|
+
}
|
|
328
|
+
|
|
302
329
|
.toastify-pro.show {
|
|
303
330
|
opacity: 1;
|
|
304
331
|
transform: scale(1);
|
|
@@ -401,6 +428,11 @@ class ToastifyPro {
|
|
|
401
428
|
opacity: 0;
|
|
402
429
|
}
|
|
403
430
|
}
|
|
431
|
+
|
|
432
|
+
@keyframes spin {
|
|
433
|
+
0% { transform: rotate(0deg); }
|
|
434
|
+
100% { transform: rotate(360deg); }
|
|
435
|
+
}
|
|
404
436
|
|
|
405
437
|
.toastify-pro .toast-icon svg {
|
|
406
438
|
width: 18px;
|
|
@@ -481,15 +513,23 @@ class ToastifyPro {
|
|
|
481
513
|
.toastify-pro-container.bottom-right { right: 16px; }
|
|
482
514
|
}
|
|
483
515
|
|
|
484
|
-
/* Confirmation Toast Styles */
|
|
516
|
+
/* Confirmation Toast Styles - Enhanced Modern Design */
|
|
485
517
|
.toastify-pro.confirmation {
|
|
486
|
-
min-width:
|
|
487
|
-
max-width:
|
|
488
|
-
padding:
|
|
518
|
+
min-width: 380px;
|
|
519
|
+
max-width: 500px;
|
|
520
|
+
padding: 32px 28px 28px;
|
|
489
521
|
flex-direction: column;
|
|
490
522
|
align-items: stretch;
|
|
491
|
-
gap:
|
|
523
|
+
gap: 24px;
|
|
492
524
|
position: relative;
|
|
525
|
+
backdrop-filter: blur(24px) saturate(180%);
|
|
526
|
+
box-shadow:
|
|
527
|
+
0 24px 48px -12px rgba(0, 0, 0, 0.25),
|
|
528
|
+
0 12px 24px -8px rgba(0, 0, 0, 0.15),
|
|
529
|
+
0 0 0 1px rgba(255, 255, 255, 0.08),
|
|
530
|
+
inset 0 1px 0 0 rgba(255, 255, 255, 0.1);
|
|
531
|
+
border: 1.5px solid rgba(255, 255, 255, 0.15);
|
|
532
|
+
border-radius: 20px;
|
|
493
533
|
}
|
|
494
534
|
|
|
495
535
|
/* Hide progress bar for confirmation toasts */
|
|
@@ -497,62 +537,94 @@ class ToastifyPro {
|
|
|
497
537
|
display: none;
|
|
498
538
|
}
|
|
499
539
|
|
|
540
|
+
/* Shimmer effect for confirmation toasts */
|
|
541
|
+
.toastify-pro.confirmation::before {
|
|
542
|
+
opacity: 0.5;
|
|
543
|
+
}
|
|
544
|
+
|
|
500
545
|
/* Close button for confirmation dialogs */
|
|
501
546
|
.toastify-pro.confirmation .conf-close-btn {
|
|
502
547
|
position: absolute;
|
|
503
|
-
top:
|
|
504
|
-
right:
|
|
548
|
+
top: 14px;
|
|
549
|
+
right: 14px;
|
|
505
550
|
cursor: pointer;
|
|
506
|
-
font-size:
|
|
551
|
+
font-size: 20px;
|
|
507
552
|
color: inherit;
|
|
508
|
-
opacity: 0.
|
|
509
|
-
padding:
|
|
510
|
-
border-radius:
|
|
511
|
-
transition: all 0.
|
|
512
|
-
width:
|
|
513
|
-
height:
|
|
553
|
+
opacity: 0.5;
|
|
554
|
+
padding: 6px;
|
|
555
|
+
border-radius: 8px;
|
|
556
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
557
|
+
width: 32px;
|
|
558
|
+
height: 32px;
|
|
514
559
|
display: flex;
|
|
515
560
|
align-items: center;
|
|
516
561
|
justify-content: center;
|
|
517
|
-
background: rgba(255, 255, 255, 0.
|
|
562
|
+
background: rgba(255, 255, 255, 0.08);
|
|
518
563
|
backdrop-filter: blur(10px);
|
|
519
564
|
font-weight: 300;
|
|
520
565
|
line-height: 1;
|
|
521
|
-
border: 1px solid rgba(255, 255, 255, 0.
|
|
566
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
522
567
|
}
|
|
523
568
|
|
|
524
569
|
.toastify-pro.confirmation .conf-close-btn:hover {
|
|
525
|
-
opacity:
|
|
526
|
-
background: rgba(255, 255, 255, 0.
|
|
527
|
-
transform: scale(1.1);
|
|
528
|
-
border-color: rgba(255, 255, 255, 0.
|
|
570
|
+
opacity: 0.9;
|
|
571
|
+
background: rgba(255, 255, 255, 0.15);
|
|
572
|
+
transform: scale(1.1) rotate(90deg);
|
|
573
|
+
border-color: rgba(255, 255, 255, 0.25);
|
|
529
574
|
}
|
|
530
575
|
|
|
531
576
|
.toastify-pro.confirmation.light .conf-close-btn {
|
|
532
|
-
background: rgba(15, 23, 42, 0.
|
|
533
|
-
border-color: rgba(15, 23, 42, 0.
|
|
577
|
+
background: rgba(15, 23, 42, 0.06);
|
|
578
|
+
border-color: rgba(15, 23, 42, 0.12);
|
|
579
|
+
opacity: 0.6;
|
|
534
580
|
}
|
|
535
581
|
|
|
536
582
|
.toastify-pro.confirmation.light .conf-close-btn:hover {
|
|
537
|
-
background: rgba(15, 23, 42, 0.
|
|
583
|
+
background: rgba(15, 23, 42, 0.12);
|
|
538
584
|
border-color: rgba(15, 23, 42, 0.2);
|
|
585
|
+
opacity: 1;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/* Icon styling for confirmation */
|
|
589
|
+
.toastify-pro.confirmation .toast-icon {
|
|
590
|
+
width: 56px;
|
|
591
|
+
height: 56px;
|
|
592
|
+
margin: 0 auto 8px;
|
|
593
|
+
background: rgba(255, 255, 255, 0.15);
|
|
594
|
+
backdrop-filter: blur(12px);
|
|
595
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
596
|
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.toastify-pro.confirmation .toast-icon svg {
|
|
600
|
+
width: 28px;
|
|
601
|
+
height: 28px;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.toastify-pro.confirmation.light .toast-icon {
|
|
605
|
+
background: rgba(15, 23, 42, 0.08);
|
|
606
|
+
border-color: rgba(15, 23, 42, 0.15);
|
|
539
607
|
}
|
|
540
608
|
|
|
541
609
|
.toastify-pro.confirmation .toast-content {
|
|
542
610
|
text-align: center;
|
|
543
|
-
margin-bottom:
|
|
611
|
+
margin-bottom: 4px;
|
|
544
612
|
}
|
|
545
613
|
|
|
546
614
|
.toastify-pro.confirmation .toast-message {
|
|
547
|
-
font-weight:
|
|
548
|
-
font-size:
|
|
549
|
-
margin-bottom:
|
|
615
|
+
font-weight: 700;
|
|
616
|
+
font-size: 20px;
|
|
617
|
+
margin-bottom: 8px;
|
|
618
|
+
letter-spacing: -0.02em;
|
|
619
|
+
line-height: 1.3;
|
|
550
620
|
}
|
|
551
621
|
|
|
552
622
|
.toastify-pro.confirmation .toast-description {
|
|
553
|
-
font-size:
|
|
554
|
-
opacity: 0.
|
|
555
|
-
margin-top:
|
|
623
|
+
font-size: 15px;
|
|
624
|
+
opacity: 0.85;
|
|
625
|
+
margin-top: 8px;
|
|
626
|
+
line-height: 1.5;
|
|
627
|
+
font-weight: 400;
|
|
556
628
|
}
|
|
557
629
|
|
|
558
630
|
/* Fix text visibility for dark/light variants */
|
|
@@ -568,54 +640,80 @@ class ToastifyPro {
|
|
|
568
640
|
|
|
569
641
|
.toast-actions {
|
|
570
642
|
display: flex;
|
|
571
|
-
gap:
|
|
572
|
-
margin-top:
|
|
643
|
+
gap: 14px;
|
|
644
|
+
margin-top: 4px;
|
|
573
645
|
}
|
|
574
646
|
|
|
575
647
|
.toast-btn {
|
|
576
648
|
flex: 1;
|
|
577
|
-
padding:
|
|
649
|
+
padding: 14px 20px;
|
|
578
650
|
border: none;
|
|
579
|
-
border-radius:
|
|
651
|
+
border-radius: 12px;
|
|
580
652
|
font-weight: 600;
|
|
581
|
-
font-size:
|
|
653
|
+
font-size: 15px;
|
|
582
654
|
cursor: pointer;
|
|
583
|
-
transition: all 0.
|
|
655
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
584
656
|
backdrop-filter: blur(10px);
|
|
585
|
-
|
|
657
|
+
position: relative;
|
|
658
|
+
overflow: hidden;
|
|
659
|
+
letter-spacing: 0.01em;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.toast-btn::after {
|
|
663
|
+
content: '';
|
|
664
|
+
position: absolute;
|
|
665
|
+
top: 50%;
|
|
666
|
+
left: 50%;
|
|
667
|
+
width: 0;
|
|
668
|
+
height: 0;
|
|
669
|
+
border-radius: 50%;
|
|
670
|
+
background: rgba(255, 255, 255, 0.3);
|
|
671
|
+
transform: translate(-50%, -50%);
|
|
672
|
+
transition: width 0.6s, height 0.6s;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.toast-btn:hover::after {
|
|
676
|
+
width: 300px;
|
|
677
|
+
height: 300px;
|
|
586
678
|
}
|
|
587
679
|
|
|
588
680
|
.toast-btn:hover {
|
|
589
|
-
transform: translateY(-
|
|
590
|
-
box-shadow: 0
|
|
681
|
+
transform: translateY(-2px);
|
|
682
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
591
683
|
}
|
|
592
684
|
|
|
593
685
|
.toast-btn:active {
|
|
594
686
|
transform: translateY(0);
|
|
687
|
+
transition: all 0.1s;
|
|
595
688
|
}
|
|
596
689
|
|
|
597
690
|
.toast-btn-cancel {
|
|
598
691
|
background: rgba(255, 255, 255, 0.1);
|
|
599
|
-
color: rgba(255, 255, 255, 0.
|
|
600
|
-
border:
|
|
601
|
-
font-weight:
|
|
692
|
+
color: rgba(255, 255, 255, 0.9);
|
|
693
|
+
border: 1.5px solid rgba(255, 255, 255, 0.25);
|
|
694
|
+
font-weight: 600;
|
|
602
695
|
}
|
|
603
696
|
|
|
604
697
|
.toast-btn-cancel:hover {
|
|
605
698
|
background: rgba(255, 255, 255, 0.15);
|
|
606
|
-
color:
|
|
607
|
-
border-color: rgba(255, 255, 255, 0.
|
|
699
|
+
color: white;
|
|
700
|
+
border-color: rgba(255, 255, 255, 0.35);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.toast-btn-cancel:disabled {
|
|
704
|
+
opacity: 0.5;
|
|
705
|
+
cursor: not-allowed;
|
|
706
|
+
pointer-events: none;
|
|
608
707
|
}
|
|
609
708
|
|
|
610
709
|
.toast-btn-confirm {
|
|
611
710
|
color: white;
|
|
612
711
|
font-weight: 700;
|
|
613
|
-
border: 2px solid rgba(255, 255, 255, 0.
|
|
614
|
-
box-shadow: 0
|
|
712
|
+
border: 2px solid rgba(255, 255, 255, 0.4);
|
|
713
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
|
|
615
714
|
position: relative;
|
|
616
715
|
overflow: hidden;
|
|
617
|
-
background: linear-gradient(135deg, rgba(15, 23, 42, 0.
|
|
618
|
-
border-color: rgba(148, 163, 184, 0.5);
|
|
716
|
+
background: linear-gradient(135deg, rgba(15, 23, 42, 0.95), rgba(30, 41, 59, 0.95));
|
|
619
717
|
}
|
|
620
718
|
|
|
621
719
|
.toast-btn-confirm::before {
|
|
@@ -625,8 +723,8 @@ class ToastifyPro {
|
|
|
625
723
|
left: -100%;
|
|
626
724
|
width: 100%;
|
|
627
725
|
height: 100%;
|
|
628
|
-
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.
|
|
629
|
-
transition: left 0.
|
|
726
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent);
|
|
727
|
+
transition: left 0.6s;
|
|
630
728
|
}
|
|
631
729
|
|
|
632
730
|
.toast-btn-confirm:hover::before {
|
|
@@ -635,13 +733,38 @@ class ToastifyPro {
|
|
|
635
733
|
|
|
636
734
|
.toast-btn-confirm:hover {
|
|
637
735
|
background: linear-gradient(135deg, rgba(15, 23, 42, 1), rgba(30, 41, 59, 1));
|
|
638
|
-
border-color: rgba(
|
|
639
|
-
box-shadow: 0
|
|
736
|
+
border-color: rgba(255, 255, 255, 0.5);
|
|
737
|
+
box-shadow: 0 8px 28px rgba(15, 23, 42, 0.5);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.toast-btn-confirm.loading {
|
|
741
|
+
opacity: 0.7;
|
|
742
|
+
cursor: not-allowed;
|
|
743
|
+
pointer-events: none;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.toast-btn-confirm .btn-spinner {
|
|
747
|
+
display: none;
|
|
748
|
+
width: 16px;
|
|
749
|
+
height: 16px;
|
|
750
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
751
|
+
border-top-color: white;
|
|
752
|
+
border-radius: 50%;
|
|
753
|
+
animation: spin 0.6s linear infinite;
|
|
754
|
+
margin-right: 8px;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
.toast-btn-confirm.loading .btn-spinner {
|
|
758
|
+
display: inline-block;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.toast-btn-confirm.loading .btn-text {
|
|
762
|
+
opacity: 0.7;
|
|
640
763
|
}
|
|
641
764
|
|
|
642
765
|
.toastify-pro.light .toast-btn-cancel {
|
|
643
766
|
background: rgba(15, 23, 42, 0.08);
|
|
644
|
-
color: rgba(15, 23, 42, 0.
|
|
767
|
+
color: rgba(15, 23, 42, 0.85);
|
|
645
768
|
border-color: rgba(15, 23, 42, 0.2);
|
|
646
769
|
}
|
|
647
770
|
|
|
@@ -653,15 +776,15 @@ class ToastifyPro {
|
|
|
653
776
|
|
|
654
777
|
/* Enhanced light theme confirm buttons */
|
|
655
778
|
.toastify-pro.light .toast-btn-confirm {
|
|
656
|
-
border-color: rgba(15, 23, 42, 0.
|
|
657
|
-
background: linear-gradient(135deg,
|
|
658
|
-
color:
|
|
779
|
+
border-color: rgba(15, 23, 42, 0.35);
|
|
780
|
+
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
|
781
|
+
color: white;
|
|
659
782
|
}
|
|
660
783
|
|
|
661
784
|
.toastify-pro.light .toast-btn-confirm:hover {
|
|
662
|
-
background: linear-gradient(135deg,
|
|
663
|
-
border-color: rgba(15, 23, 42, 0.
|
|
664
|
-
box-shadow: 0
|
|
785
|
+
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
786
|
+
border-color: rgba(15, 23, 42, 0.5);
|
|
787
|
+
box-shadow: 0 8px 28px rgba(15, 23, 42, 0.3);
|
|
665
788
|
}
|
|
666
789
|
|
|
667
790
|
@media (max-width: 640px) {
|
|
@@ -918,6 +1041,25 @@ class ToastifyPro {
|
|
|
918
1041
|
* @param {Function} callback - Callback function (if description provided)
|
|
919
1042
|
*/
|
|
920
1043
|
conf(message, descriptionOrCallback, callback) {
|
|
1044
|
+
// Check if there's already an active confirmation (GLOBAL CHECK)
|
|
1045
|
+
if (globalActiveConfirmation && globalActiveConfirmation.element && globalActiveConfirmation.element.parentNode) {
|
|
1046
|
+
// Trigger shake animation on existing confirmation toast element
|
|
1047
|
+
const existingToast = globalActiveConfirmation.element;
|
|
1048
|
+
existingToast.classList.remove('shake');
|
|
1049
|
+
// Force reflow to restart animation
|
|
1050
|
+
void existingToast.offsetWidth;
|
|
1051
|
+
existingToast.classList.add('shake');
|
|
1052
|
+
|
|
1053
|
+
// Remove shake class after animation completes
|
|
1054
|
+
setTimeout(() => {
|
|
1055
|
+
if (existingToast && existingToast.parentNode) {
|
|
1056
|
+
existingToast.classList.remove('shake');
|
|
1057
|
+
}
|
|
1058
|
+
}, 600);
|
|
1059
|
+
|
|
1060
|
+
return globalActiveConfirmation;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
921
1063
|
// Parse arguments to support multiple usage patterns
|
|
922
1064
|
let description = '';
|
|
923
1065
|
let options = {};
|
|
@@ -961,6 +1103,9 @@ class ToastifyPro {
|
|
|
961
1103
|
cancelText: options.cancelText || 'Cancel',
|
|
962
1104
|
theme: options.theme || options.color || 'dark', // Support both theme and color for backward compatibility
|
|
963
1105
|
position: options.position || 'center', // Default to center for confirmations
|
|
1106
|
+
primaryColor: options.primaryColor || null,
|
|
1107
|
+
secondaryColor: options.secondaryColor || null,
|
|
1108
|
+
loading: options.loading || false, // Support external loading state (for React/Vue)
|
|
964
1109
|
...options
|
|
965
1110
|
};
|
|
966
1111
|
|
|
@@ -971,6 +1116,23 @@ class ToastifyPro {
|
|
|
971
1116
|
confirmOptions.theme = 'dark'; // Default to dark for all other values
|
|
972
1117
|
}
|
|
973
1118
|
|
|
1119
|
+
// Helper function to determine if a color is light or dark
|
|
1120
|
+
const isLightColor = (color) => {
|
|
1121
|
+
if (!color) return false;
|
|
1122
|
+
const hex = color.replace('#', '');
|
|
1123
|
+
const r = parseInt(hex.substr(0, 2), 16);
|
|
1124
|
+
const g = parseInt(hex.substr(2, 2), 16);
|
|
1125
|
+
const b = parseInt(hex.substr(4, 2), 16);
|
|
1126
|
+
const brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000;
|
|
1127
|
+
return brightness > 155;
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
// Determine text color based on background
|
|
1131
|
+
let textColor = confirmOptions.theme === 'light' ? '#1e293b' : 'white';
|
|
1132
|
+
if (confirmOptions.primaryColor) {
|
|
1133
|
+
textColor = isLightColor(confirmOptions.primaryColor) ? '#1e293b' : 'white';
|
|
1134
|
+
}
|
|
1135
|
+
|
|
974
1136
|
// Validate position for confirmation toast
|
|
975
1137
|
const validPositions = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top-center', 'bottom-center', 'center'];
|
|
976
1138
|
if (!validPositions.includes(confirmOptions.position)) {
|
|
@@ -992,26 +1154,108 @@ class ToastifyPro {
|
|
|
992
1154
|
}
|
|
993
1155
|
}
|
|
994
1156
|
|
|
1157
|
+
// Create control functions for loading state
|
|
1158
|
+
let confirmBtnElement = null;
|
|
1159
|
+
let cancelBtnElement = null;
|
|
1160
|
+
let closeBtnElement = null;
|
|
1161
|
+
let isLoading = false;
|
|
1162
|
+
let useLoading = false; // Track if user wants loading behavior
|
|
1163
|
+
let toastElement = null; // Reference to toast element
|
|
1164
|
+
|
|
1165
|
+
const setLoading = (loading) => {
|
|
1166
|
+
useLoading = true; // User is manually controlling loading
|
|
1167
|
+
isLoading = loading;
|
|
1168
|
+
if (confirmBtnElement) {
|
|
1169
|
+
if (loading) {
|
|
1170
|
+
confirmBtnElement.classList.add('loading');
|
|
1171
|
+
confirmBtnElement.disabled = true;
|
|
1172
|
+
} else {
|
|
1173
|
+
confirmBtnElement.classList.remove('loading');
|
|
1174
|
+
confirmBtnElement.disabled = false;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
// Disable/enable cancel and close buttons during loading
|
|
1178
|
+
if (cancelBtnElement) {
|
|
1179
|
+
cancelBtnElement.disabled = loading;
|
|
1180
|
+
cancelBtnElement.style.opacity = loading ? '0.5' : '1';
|
|
1181
|
+
cancelBtnElement.style.cursor = loading ? 'not-allowed' : 'pointer';
|
|
1182
|
+
}
|
|
1183
|
+
if (closeBtnElement) {
|
|
1184
|
+
closeBtnElement.style.opacity = loading ? '0.3' : '0.5';
|
|
1185
|
+
closeBtnElement.style.cursor = loading ? 'not-allowed' : 'pointer';
|
|
1186
|
+
closeBtnElement.style.pointerEvents = loading ? 'none' : 'auto';
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
const closeConfirmation = () => {
|
|
1191
|
+
if (toastElement && toastElement.parentNode) {
|
|
1192
|
+
globalActiveConfirmation = null;
|
|
1193
|
+
this.removeToast(toastElement);
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
|
|
995
1197
|
// Helper function to handle confirmation result
|
|
996
|
-
const handleConfirmation = (confirmed) => {
|
|
1198
|
+
const handleConfirmation = async (confirmed) => {
|
|
997
1199
|
if (confirmed) {
|
|
998
1200
|
// Call onConfirm if provided
|
|
999
1201
|
if (options.onConfirm && typeof options.onConfirm === 'function') {
|
|
1000
1202
|
try {
|
|
1001
|
-
options.onConfirm();
|
|
1203
|
+
const result = options.onConfirm({ setLoading, close: closeConfirmation });
|
|
1204
|
+
// Check if it's a promise
|
|
1205
|
+
if (result && typeof result.then === 'function') {
|
|
1206
|
+
// If user didn't manually set loading, auto-set it
|
|
1207
|
+
if (!useLoading) {
|
|
1208
|
+
setLoading(true);
|
|
1209
|
+
}
|
|
1210
|
+
await result;
|
|
1211
|
+
// Auto-close after promise resolves if user didn't manually close
|
|
1212
|
+
if (toastElement && toastElement.parentNode) {
|
|
1213
|
+
setLoading(false);
|
|
1214
|
+
closeConfirmation();
|
|
1215
|
+
}
|
|
1216
|
+
} else {
|
|
1217
|
+
// Synchronous callback - only close if user didn't start loading
|
|
1218
|
+
if (!useLoading) {
|
|
1219
|
+
closeConfirmation();
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1002
1222
|
} catch (error) {
|
|
1003
1223
|
console.error('ToastifyPro: Error in onConfirm callback:', error);
|
|
1224
|
+
setLoading(false);
|
|
1225
|
+
closeConfirmation();
|
|
1004
1226
|
}
|
|
1005
1227
|
}
|
|
1006
1228
|
// Call unified callback if provided
|
|
1007
|
-
if (resultCallback && typeof resultCallback === 'function') {
|
|
1229
|
+
else if (resultCallback && typeof resultCallback === 'function') {
|
|
1008
1230
|
try {
|
|
1009
|
-
resultCallback(true);
|
|
1231
|
+
const result = resultCallback(true, { setLoading, close: closeConfirmation });
|
|
1232
|
+
if (result && typeof result.then === 'function') {
|
|
1233
|
+
if (!useLoading) {
|
|
1234
|
+
setLoading(true);
|
|
1235
|
+
}
|
|
1236
|
+
await result;
|
|
1237
|
+
if (toastElement && toastElement.parentNode) {
|
|
1238
|
+
setLoading(false);
|
|
1239
|
+
closeConfirmation();
|
|
1240
|
+
}
|
|
1241
|
+
} else {
|
|
1242
|
+
if (!useLoading) {
|
|
1243
|
+
closeConfirmation();
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1010
1246
|
} catch (error) {
|
|
1011
1247
|
console.error('ToastifyPro: Error in confirmation callback:', error);
|
|
1248
|
+
setLoading(false);
|
|
1249
|
+
closeConfirmation();
|
|
1012
1250
|
}
|
|
1251
|
+
} else {
|
|
1252
|
+
// No callback - just close
|
|
1253
|
+
closeConfirmation();
|
|
1013
1254
|
}
|
|
1014
1255
|
} else {
|
|
1256
|
+
// Cancel - no loading needed, check if not currently loading
|
|
1257
|
+
if (isLoading) return; // Don't allow cancel while loading
|
|
1258
|
+
|
|
1015
1259
|
// Call onCancel if provided
|
|
1016
1260
|
if (options.onCancel && typeof options.onCancel === 'function') {
|
|
1017
1261
|
try {
|
|
@@ -1028,6 +1272,7 @@ class ToastifyPro {
|
|
|
1028
1272
|
console.error('ToastifyPro: Error in confirmation callback:', error);
|
|
1029
1273
|
}
|
|
1030
1274
|
}
|
|
1275
|
+
closeConfirmation();
|
|
1031
1276
|
}
|
|
1032
1277
|
};
|
|
1033
1278
|
|
|
@@ -1035,6 +1280,30 @@ class ToastifyPro {
|
|
|
1035
1280
|
// Create confirmation toast element
|
|
1036
1281
|
const toast = document.createElement("div");
|
|
1037
1282
|
toast.className = `toastify-pro confirmation ${confirmOptions.theme}`;
|
|
1283
|
+
|
|
1284
|
+
// Store reference to toast element
|
|
1285
|
+
toastElement = toast;
|
|
1286
|
+
|
|
1287
|
+
// Apply custom colors if provided
|
|
1288
|
+
if (confirmOptions.primaryColor) {
|
|
1289
|
+
const primary = confirmOptions.primaryColor;
|
|
1290
|
+
const secondary = confirmOptions.secondaryColor;
|
|
1291
|
+
|
|
1292
|
+
if (secondary) {
|
|
1293
|
+
// Both colors provided - create gradient
|
|
1294
|
+
toast.style.background = `linear-gradient(135deg, ${primary} 0%, ${secondary} 100%)`;
|
|
1295
|
+
} else {
|
|
1296
|
+
// Only primary color - solid with slight transparency
|
|
1297
|
+
toast.style.background = primary;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// Set text color based on background brightness
|
|
1301
|
+
toast.style.color = textColor;
|
|
1302
|
+
|
|
1303
|
+
// Adjust border color to match
|
|
1304
|
+
const borderOpacity = isLightColor(primary) ? '0.2' : '0.15';
|
|
1305
|
+
toast.style.borderColor = `rgba(255, 255, 255, ${borderOpacity})`;
|
|
1306
|
+
}
|
|
1038
1307
|
|
|
1039
1308
|
// Create close button for confirmation
|
|
1040
1309
|
const closeBtn = document.createElement("span");
|
|
@@ -1042,15 +1311,23 @@ class ToastifyPro {
|
|
|
1042
1311
|
closeBtn.innerHTML = "×";
|
|
1043
1312
|
closeBtn.setAttribute('aria-label', 'Cancel confirmation');
|
|
1044
1313
|
closeBtn.onclick = () => {
|
|
1045
|
-
|
|
1046
|
-
|
|
1314
|
+
if (!isLoading) {
|
|
1315
|
+
handleConfirmation(false);
|
|
1316
|
+
}
|
|
1047
1317
|
};
|
|
1318
|
+
if (confirmOptions.primaryColor) {
|
|
1319
|
+
closeBtn.style.color = textColor;
|
|
1320
|
+
}
|
|
1321
|
+
closeBtnElement = closeBtn;
|
|
1048
1322
|
toast.appendChild(closeBtn);
|
|
1049
1323
|
|
|
1050
1324
|
// Create icon wrapper
|
|
1051
1325
|
const iconWrapper = document.createElement("div");
|
|
1052
1326
|
iconWrapper.className = "toast-icon";
|
|
1053
1327
|
iconWrapper.innerHTML = this.getIconSVG('info'); // Default to info icon
|
|
1328
|
+
if (confirmOptions.primaryColor) {
|
|
1329
|
+
iconWrapper.style.color = textColor;
|
|
1330
|
+
}
|
|
1054
1331
|
toast.appendChild(iconWrapper);
|
|
1055
1332
|
|
|
1056
1333
|
// Create content wrapper
|
|
@@ -1061,6 +1338,9 @@ class ToastifyPro {
|
|
|
1061
1338
|
const messageElement = document.createElement("div");
|
|
1062
1339
|
messageElement.className = "toast-message";
|
|
1063
1340
|
messageElement.textContent = message.substring(0, this.defaultOptions.maxLength);
|
|
1341
|
+
if (confirmOptions.primaryColor) {
|
|
1342
|
+
messageElement.style.color = textColor;
|
|
1343
|
+
}
|
|
1064
1344
|
contentWrapper.appendChild(messageElement);
|
|
1065
1345
|
|
|
1066
1346
|
// Optional description
|
|
@@ -1068,6 +1348,9 @@ class ToastifyPro {
|
|
|
1068
1348
|
const descriptionElement = document.createElement("div");
|
|
1069
1349
|
descriptionElement.className = "toast-description";
|
|
1070
1350
|
descriptionElement.textContent = description.substring(0, this.defaultOptions.maxLength * 2);
|
|
1351
|
+
if (confirmOptions.primaryColor) {
|
|
1352
|
+
descriptionElement.style.color = textColor;
|
|
1353
|
+
}
|
|
1071
1354
|
contentWrapper.appendChild(descriptionElement);
|
|
1072
1355
|
}
|
|
1073
1356
|
|
|
@@ -1082,18 +1365,64 @@ class ToastifyPro {
|
|
|
1082
1365
|
cancelBtn.className = "toast-btn toast-btn-cancel";
|
|
1083
1366
|
cancelBtn.textContent = confirmOptions.cancelText;
|
|
1084
1367
|
cancelBtn.onclick = () => {
|
|
1085
|
-
|
|
1086
|
-
|
|
1368
|
+
if (!isLoading) {
|
|
1369
|
+
handleConfirmation(false);
|
|
1370
|
+
}
|
|
1087
1371
|
};
|
|
1372
|
+
|
|
1373
|
+
// Store cancel button reference
|
|
1374
|
+
cancelBtnElement = cancelBtn;
|
|
1375
|
+
|
|
1376
|
+
// Style cancel button with custom colors
|
|
1377
|
+
if (confirmOptions.primaryColor) {
|
|
1378
|
+
const isLight = isLightColor(confirmOptions.primaryColor);
|
|
1379
|
+
cancelBtn.style.background = isLight ? 'rgba(15, 23, 42, 0.08)' : 'rgba(255, 255, 255, 0.1)';
|
|
1380
|
+
cancelBtn.style.color = textColor;
|
|
1381
|
+
cancelBtn.style.borderColor = isLight ? 'rgba(15, 23, 42, 0.2)' : 'rgba(255, 255, 255, 0.25)';
|
|
1382
|
+
}
|
|
1088
1383
|
|
|
1089
1384
|
// Confirm button
|
|
1090
1385
|
const confirmBtn = document.createElement("button");
|
|
1091
1386
|
confirmBtn.className = `toast-btn toast-btn-confirm`;
|
|
1092
|
-
|
|
1387
|
+
|
|
1388
|
+
// Create spinner element
|
|
1389
|
+
const spinner = document.createElement("span");
|
|
1390
|
+
spinner.className = "btn-spinner";
|
|
1391
|
+
confirmBtn.appendChild(spinner);
|
|
1392
|
+
|
|
1393
|
+
// Create text wrapper
|
|
1394
|
+
const textWrapper = document.createElement("span");
|
|
1395
|
+
textWrapper.className = "btn-text";
|
|
1396
|
+
textWrapper.textContent = confirmOptions.confirmText;
|
|
1397
|
+
confirmBtn.appendChild(textWrapper);
|
|
1398
|
+
|
|
1093
1399
|
confirmBtn.onclick = () => {
|
|
1094
|
-
|
|
1095
|
-
|
|
1400
|
+
if (!isLoading) {
|
|
1401
|
+
handleConfirmation(true);
|
|
1402
|
+
}
|
|
1096
1403
|
};
|
|
1404
|
+
|
|
1405
|
+
// Store reference for loading state control
|
|
1406
|
+
confirmBtnElement = confirmBtn;
|
|
1407
|
+
|
|
1408
|
+
// Style confirm button with custom colors
|
|
1409
|
+
if (confirmOptions.primaryColor) {
|
|
1410
|
+
const primary = confirmOptions.primaryColor;
|
|
1411
|
+
const secondary = confirmOptions.secondaryColor;
|
|
1412
|
+
const isLight = isLightColor(primary);
|
|
1413
|
+
|
|
1414
|
+
if (secondary) {
|
|
1415
|
+
// Gradient confirm button
|
|
1416
|
+
confirmBtn.style.background = `linear-gradient(135deg, ${primary} 0%, ${secondary} 100%)`;
|
|
1417
|
+
} else {
|
|
1418
|
+
// Solid color confirm button with enhanced styling
|
|
1419
|
+
confirmBtn.style.background = primary;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// Determine button text color (always use contrasting color for readability)
|
|
1423
|
+
confirmBtn.style.color = isLight ? '#1e293b' : 'white';
|
|
1424
|
+
confirmBtn.style.borderColor = isLight ? 'rgba(15, 23, 42, 0.3)' : 'rgba(255, 255, 255, 0.4)';
|
|
1425
|
+
}
|
|
1097
1426
|
|
|
1098
1427
|
actionsWrapper.appendChild(cancelBtn);
|
|
1099
1428
|
actionsWrapper.appendChild(confirmBtn);
|
|
@@ -1101,6 +1430,21 @@ class ToastifyPro {
|
|
|
1101
1430
|
|
|
1102
1431
|
// Add toast to the specified container (not default container)
|
|
1103
1432
|
confirmContainer.appendChild(toast);
|
|
1433
|
+
|
|
1434
|
+
// Create control object
|
|
1435
|
+
const controlObject = {
|
|
1436
|
+
element: toast,
|
|
1437
|
+
setLoading: setLoading,
|
|
1438
|
+
close: closeConfirmation
|
|
1439
|
+
};
|
|
1440
|
+
|
|
1441
|
+
// Store as global active confirmation (with control object)
|
|
1442
|
+
globalActiveConfirmation = controlObject;
|
|
1443
|
+
|
|
1444
|
+
// Apply initial loading state if provided (for React/Vue)
|
|
1445
|
+
if (confirmOptions.loading) {
|
|
1446
|
+
setLoading(true);
|
|
1447
|
+
}
|
|
1104
1448
|
|
|
1105
1449
|
// Entrance animation
|
|
1106
1450
|
setTimeout(() => {
|
|
@@ -1111,11 +1455,22 @@ class ToastifyPro {
|
|
|
1111
1455
|
}
|
|
1112
1456
|
}, 10);
|
|
1113
1457
|
|
|
1114
|
-
|
|
1458
|
+
// Return control object with toast element and control functions
|
|
1459
|
+
return controlObject;
|
|
1115
1460
|
} catch (error) {
|
|
1116
1461
|
console.error('ToastifyPro: Failed to create confirmation toast:', error);
|
|
1117
1462
|
}
|
|
1118
1463
|
}
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* Alias for conf() method - shows a confirmation toast
|
|
1467
|
+
* @param {string} message - Main confirmation question
|
|
1468
|
+
* @param {string|Function|Object} descriptionOrCallback - Description text, callback function, or options object
|
|
1469
|
+
* @param {Function} callback - Callback function (if description provided)
|
|
1470
|
+
*/
|
|
1471
|
+
confirm(message, descriptionOrCallback, callback) {
|
|
1472
|
+
return this.conf(message, descriptionOrCallback, callback);
|
|
1473
|
+
}
|
|
1119
1474
|
}
|
|
1120
1475
|
|
|
1121
1476
|
/**
|