toastify-pro 1.2.0 → 1.3.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.
@@ -12,8 +12,11 @@
12
12
  * - Progress bar with shimmer effects
13
13
  * - Responsive design for mobile devices
14
14
  * - Framework agnostic (works with React, Vue, Angular, etc.)
15
+ * - Confirmation dialogs with customizable buttons and callbacks
16
+ * - Center position support for enhanced focus
17
+ * - Independent positioning for confirmations
15
18
  *
16
- * @version 1.2.0
19
+ * @version 1.3.0
17
20
  * @author ToastifyPro Team
18
21
  * @license MIT
19
22
  */
@@ -21,7 +24,7 @@ class ToastifyPro {
21
24
  /**
22
25
  * Creates a new ToastifyPro instance
23
26
  * @param {Object} options - Configuration options
24
- * @param {string} options.position - Toast position (top-left, top-right, bottom-left, bottom-right, top-center, bottom-center)
27
+ * @param {string} options.position - Toast position (top-left, top-right, bottom-left, bottom-right, top-center, bottom-center, center)
25
28
  * @param {number} options.timeout - Auto-dismiss timeout in milliseconds (0 to disable)
26
29
  * @param {boolean} options.allowClose - Whether to show close button
27
30
  * @param {number} options.maxLength - Maximum message length
@@ -35,14 +38,14 @@ class ToastifyPro {
35
38
 
36
39
  // Merge with default options
37
40
  this.defaultOptions = {
38
- position: options.position || "bottom-center", // top-left, top-right, bottom-left, bottom-right, top-center, bottom-center
41
+ position: options.position || "bottom-center", // top-left, top-right, bottom-left, bottom-right, top-center, bottom-center, center
39
42
  timeout: options.timeout || 3000,
40
43
  allowClose: options.allowClose !== false, // default true
41
44
  maxLength: options.maxLength || 100,
42
45
  };
43
46
 
44
47
  // Validate position
45
- const validPositions = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top-center', 'bottom-center'];
48
+ const validPositions = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top-center', 'bottom-center', 'center'];
46
49
  if (!validPositions.includes(this.defaultOptions.position)) {
47
50
  console.warn(`ToastifyPro: Invalid position "${this.defaultOptions.position}". Using "bottom-center".`);
48
51
  this.defaultOptions.position = "bottom-center";
@@ -138,6 +141,7 @@ class ToastifyPro {
138
141
  .toastify-pro-container.bottom-right { bottom: 50px; right: 24px; align-items: flex-end; }
139
142
  .toastify-pro-container.top-center { top: 50px; left: 50%; transform: translateX(-50%); }
140
143
  .toastify-pro-container.bottom-center { bottom: 50px; left: 50%; transform: translateX(-50%); }
144
+ .toastify-pro-container.center { top: 50%; left: 50%; transform: translate(-50%, -50%); }
141
145
 
142
146
  .toastify-pro {
143
147
  min-width: 280px;
@@ -476,6 +480,196 @@ class ToastifyPro {
476
480
  .toastify-pro-container.top-right,
477
481
  .toastify-pro-container.bottom-right { right: 16px; }
478
482
  }
483
+
484
+ /* Confirmation Toast Styles */
485
+ .toastify-pro.confirmation {
486
+ min-width: 320px;
487
+ max-width: 450px;
488
+ padding: 24px;
489
+ flex-direction: column;
490
+ align-items: stretch;
491
+ gap: 20px;
492
+ position: relative;
493
+ }
494
+
495
+ /* Hide progress bar for confirmation toasts */
496
+ .toastify-pro.confirmation::after {
497
+ display: none;
498
+ }
499
+
500
+ /* Close button for confirmation dialogs */
501
+ .toastify-pro.confirmation .conf-close-btn {
502
+ position: absolute;
503
+ top: 12px;
504
+ right: 12px;
505
+ cursor: pointer;
506
+ font-size: 18px;
507
+ color: inherit;
508
+ opacity: 0.6;
509
+ padding: 4px;
510
+ border-radius: 50%;
511
+ transition: all 0.2s ease;
512
+ width: 24px;
513
+ height: 24px;
514
+ display: flex;
515
+ align-items: center;
516
+ justify-content: center;
517
+ background: rgba(255, 255, 255, 0.1);
518
+ backdrop-filter: blur(10px);
519
+ font-weight: 300;
520
+ line-height: 1;
521
+ border: 1px solid rgba(255, 255, 255, 0.1);
522
+ }
523
+
524
+ .toastify-pro.confirmation .conf-close-btn:hover {
525
+ opacity: 1;
526
+ background: rgba(255, 255, 255, 0.2);
527
+ transform: scale(1.1);
528
+ border-color: rgba(255, 255, 255, 0.2);
529
+ }
530
+
531
+ .toastify-pro.confirmation.light .conf-close-btn {
532
+ background: rgba(15, 23, 42, 0.08);
533
+ border-color: rgba(15, 23, 42, 0.1);
534
+ }
535
+
536
+ .toastify-pro.confirmation.light .conf-close-btn:hover {
537
+ background: rgba(15, 23, 42, 0.15);
538
+ border-color: rgba(15, 23, 42, 0.2);
539
+ }
540
+
541
+ .toastify-pro.confirmation .toast-content {
542
+ text-align: center;
543
+ margin-bottom: 8px;
544
+ }
545
+
546
+ .toastify-pro.confirmation .toast-message {
547
+ font-weight: 600;
548
+ font-size: 16px;
549
+ margin-bottom: 6px;
550
+ }
551
+
552
+ .toastify-pro.confirmation .toast-description {
553
+ font-size: 14px;
554
+ opacity: 0.9;
555
+ margin-top: 6px;
556
+ }
557
+
558
+ /* Fix text visibility for dark/light variants */
559
+ .toastify-pro.confirmation.dark .toast-message,
560
+ .toastify-pro.confirmation.dark .toast-description {
561
+ color: white;
562
+ }
563
+
564
+ .toastify-pro.confirmation.light .toast-message,
565
+ .toastify-pro.confirmation.light .toast-description {
566
+ color: #1e293b;
567
+ }
568
+
569
+ .toast-actions {
570
+ display: flex;
571
+ gap: 12px;
572
+ margin-top: 8px;
573
+ }
574
+
575
+ .toast-btn {
576
+ flex: 1;
577
+ padding: 10px 16px;
578
+ border: none;
579
+ border-radius: 8px;
580
+ font-weight: 600;
581
+ font-size: 14px;
582
+ cursor: pointer;
583
+ transition: all 0.2s ease;
584
+ backdrop-filter: blur(10px);
585
+ border: 1px solid rgba(255, 255, 255, 0.2);
586
+ }
587
+
588
+ .toast-btn:hover {
589
+ transform: translateY(-1px);
590
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
591
+ }
592
+
593
+ .toast-btn:active {
594
+ transform: translateY(0);
595
+ }
596
+
597
+ .toast-btn-cancel {
598
+ background: rgba(255, 255, 255, 0.1);
599
+ color: rgba(255, 255, 255, 0.8);
600
+ border: 1px solid rgba(255, 255, 255, 0.3);
601
+ font-weight: 500;
602
+ }
603
+
604
+ .toast-btn-cancel:hover {
605
+ background: rgba(255, 255, 255, 0.15);
606
+ color: rgba(255, 255, 255, 0.9);
607
+ border-color: rgba(255, 255, 255, 0.4);
608
+ }
609
+
610
+ .toast-btn-confirm {
611
+ color: white;
612
+ font-weight: 700;
613
+ border: 2px solid rgba(255, 255, 255, 0.3);
614
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
615
+ position: relative;
616
+ overflow: hidden;
617
+ background: linear-gradient(135deg, rgba(15, 23, 42, 0.9), rgba(30, 41, 59, 0.9));
618
+ border-color: rgba(148, 163, 184, 0.5);
619
+ }
620
+
621
+ .toast-btn-confirm::before {
622
+ content: '';
623
+ position: absolute;
624
+ top: 0;
625
+ left: -100%;
626
+ width: 100%;
627
+ height: 100%;
628
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
629
+ transition: left 0.5s;
630
+ }
631
+
632
+ .toast-btn-confirm:hover::before {
633
+ left: 100%;
634
+ }
635
+
636
+ .toast-btn-confirm:hover {
637
+ background: linear-gradient(135deg, rgba(15, 23, 42, 1), rgba(30, 41, 59, 1));
638
+ border-color: rgba(148, 163, 184, 0.7);
639
+ box-shadow: 0 6px 20px rgba(15, 23, 42, 0.4);
640
+ }
641
+
642
+ .toastify-pro.light .toast-btn-cancel {
643
+ background: rgba(15, 23, 42, 0.08);
644
+ color: rgba(15, 23, 42, 0.8);
645
+ border-color: rgba(15, 23, 42, 0.2);
646
+ }
647
+
648
+ .toastify-pro.light .toast-btn-cancel:hover {
649
+ background: rgba(15, 23, 42, 0.12);
650
+ color: rgba(15, 23, 42, 1);
651
+ border-color: rgba(15, 23, 42, 0.3);
652
+ }
653
+
654
+ /* Enhanced light theme confirm buttons */
655
+ .toastify-pro.light .toast-btn-confirm {
656
+ border-color: rgba(15, 23, 42, 0.3);
657
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 250, 252, 0.9));
658
+ color: #1e293b;
659
+ }
660
+
661
+ .toastify-pro.light .toast-btn-confirm:hover {
662
+ background: linear-gradient(135deg, rgba(255, 255, 255, 1), rgba(248, 250, 252, 1));
663
+ border-color: rgba(15, 23, 42, 0.4);
664
+ box-shadow: 0 6px 20px rgba(15, 23, 42, 0.2);
665
+ }
666
+
667
+ @media (max-width: 640px) {
668
+ .toastify-pro.confirmation {
669
+ min-width: 280px;
670
+ max-width: calc(100vw - 32px);
671
+ }
672
+ }
479
673
  `;
480
674
  document.head.appendChild(style);
481
675
  } catch (error) {
@@ -716,6 +910,212 @@ class ToastifyPro {
716
910
  }
717
911
  this.show(msg, "light", opts);
718
912
  }
913
+
914
+ /**
915
+ * Shows a confirmation toast with confirm/cancel buttons
916
+ * @param {string} message - Main confirmation question
917
+ * @param {string|Function|Object} descriptionOrCallback - Description text, callback function, or options object
918
+ * @param {Function} callback - Callback function (if description provided)
919
+ */
920
+ conf(message, descriptionOrCallback, callback) {
921
+ // Parse arguments to support multiple usage patterns
922
+ let description = '';
923
+ let options = {};
924
+ let resultCallback = null;
925
+
926
+ // Pattern 1: conf('message', callback)
927
+ if (typeof descriptionOrCallback === 'function' && !callback) {
928
+ resultCallback = descriptionOrCallback;
929
+ }
930
+ // Pattern 2: conf('message', 'description', callback)
931
+ else if (typeof descriptionOrCallback === 'string' && typeof callback === 'function') {
932
+ description = descriptionOrCallback;
933
+ resultCallback = callback;
934
+ }
935
+ // Pattern 3: conf('message', options) with onConfirm/onCancel
936
+ else if (typeof descriptionOrCallback === 'object' && descriptionOrCallback !== null) {
937
+ options = descriptionOrCallback;
938
+ description = options.description || '';
939
+
940
+ // Use onConfirm/onCancel if provided, otherwise use callback parameter
941
+ if (options.onConfirm || options.onCancel) {
942
+ // Don't use the callback parameter if onConfirm/onCancel are provided
943
+ resultCallback = null;
944
+ } else if (typeof callback === 'function') {
945
+ resultCallback = callback;
946
+ }
947
+ }
948
+ // Pattern 4: conf('message', 'description', options) - legacy support
949
+ else if (typeof descriptionOrCallback === 'string' && typeof callback === 'object') {
950
+ description = descriptionOrCallback;
951
+ options = callback || {};
952
+ // In this case, no unified callback, rely on onConfirm/onCancel
953
+ resultCallback = null;
954
+ }
955
+
956
+ // Default options for confirmation
957
+ const confirmOptions = {
958
+ timeout: 0, // No auto-dismiss for confirmations
959
+ allowClose: false, // No close button, must choose
960
+ confirmText: options.confirmText || 'Confirm',
961
+ cancelText: options.cancelText || 'Cancel',
962
+ theme: options.theme || options.color || 'dark', // Support both theme and color for backward compatibility
963
+ position: options.position || 'center', // Default to center for confirmations
964
+ ...options
965
+ };
966
+
967
+ // Validate and set theme to only dark or light
968
+ if (confirmOptions.theme === 'light' || confirmOptions.theme === 'white') {
969
+ confirmOptions.theme = 'light';
970
+ } else {
971
+ confirmOptions.theme = 'dark'; // Default to dark for all other values
972
+ }
973
+
974
+ // Validate position for confirmation toast
975
+ const validPositions = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top-center', 'bottom-center', 'center'];
976
+ if (!validPositions.includes(confirmOptions.position)) {
977
+ console.warn(`ToastifyPro: Invalid confirmation position "${confirmOptions.position}". Using default position.`);
978
+ confirmOptions.position = this.defaultOptions.position;
979
+ }
980
+
981
+ // Get or create container for the specified position
982
+ let confirmContainer = document.querySelector(`.toastify-pro-container.${confirmOptions.position}`);
983
+
984
+ if (!confirmContainer) {
985
+ try {
986
+ confirmContainer = document.createElement("div");
987
+ confirmContainer.className = `toastify-pro-container ${confirmOptions.position}`;
988
+ document.body.appendChild(confirmContainer);
989
+ } catch (error) {
990
+ console.warn('ToastifyPro: Failed to create confirmation container. Using default container.');
991
+ confirmContainer = this.container;
992
+ }
993
+ }
994
+
995
+ // Helper function to handle confirmation result
996
+ const handleConfirmation = (confirmed) => {
997
+ if (confirmed) {
998
+ // Call onConfirm if provided
999
+ if (options.onConfirm && typeof options.onConfirm === 'function') {
1000
+ try {
1001
+ options.onConfirm();
1002
+ } catch (error) {
1003
+ console.error('ToastifyPro: Error in onConfirm callback:', error);
1004
+ }
1005
+ }
1006
+ // Call unified callback if provided
1007
+ if (resultCallback && typeof resultCallback === 'function') {
1008
+ try {
1009
+ resultCallback(true);
1010
+ } catch (error) {
1011
+ console.error('ToastifyPro: Error in confirmation callback:', error);
1012
+ }
1013
+ }
1014
+ } else {
1015
+ // Call onCancel if provided
1016
+ if (options.onCancel && typeof options.onCancel === 'function') {
1017
+ try {
1018
+ options.onCancel();
1019
+ } catch (error) {
1020
+ console.error('ToastifyPro: Error in onCancel callback:', error);
1021
+ }
1022
+ }
1023
+ // Call unified callback if provided
1024
+ if (resultCallback && typeof resultCallback === 'function') {
1025
+ try {
1026
+ resultCallback(false);
1027
+ } catch (error) {
1028
+ console.error('ToastifyPro: Error in confirmation callback:', error);
1029
+ }
1030
+ }
1031
+ }
1032
+ };
1033
+
1034
+ try {
1035
+ // Create confirmation toast element
1036
+ const toast = document.createElement("div");
1037
+ toast.className = `toastify-pro confirmation ${confirmOptions.theme}`;
1038
+
1039
+ // Create close button for confirmation
1040
+ const closeBtn = document.createElement("span");
1041
+ closeBtn.className = "conf-close-btn";
1042
+ closeBtn.innerHTML = "×";
1043
+ closeBtn.setAttribute('aria-label', 'Cancel confirmation');
1044
+ closeBtn.onclick = () => {
1045
+ handleConfirmation(false);
1046
+ this.removeToast(toast);
1047
+ };
1048
+ toast.appendChild(closeBtn);
1049
+
1050
+ // Create icon wrapper
1051
+ const iconWrapper = document.createElement("div");
1052
+ iconWrapper.className = "toast-icon";
1053
+ iconWrapper.innerHTML = this.getIconSVG('info'); // Default to info icon
1054
+ toast.appendChild(iconWrapper);
1055
+
1056
+ // Create content wrapper
1057
+ const contentWrapper = document.createElement("div");
1058
+ contentWrapper.className = "toast-content";
1059
+
1060
+ // Main message
1061
+ const messageElement = document.createElement("div");
1062
+ messageElement.className = "toast-message";
1063
+ messageElement.textContent = message.substring(0, this.defaultOptions.maxLength);
1064
+ contentWrapper.appendChild(messageElement);
1065
+
1066
+ // Optional description
1067
+ if (description) {
1068
+ const descriptionElement = document.createElement("div");
1069
+ descriptionElement.className = "toast-description";
1070
+ descriptionElement.textContent = description.substring(0, this.defaultOptions.maxLength * 2);
1071
+ contentWrapper.appendChild(descriptionElement);
1072
+ }
1073
+
1074
+ toast.appendChild(contentWrapper);
1075
+
1076
+ // Create action buttons container
1077
+ const actionsWrapper = document.createElement("div");
1078
+ actionsWrapper.className = "toast-actions";
1079
+
1080
+ // Cancel button
1081
+ const cancelBtn = document.createElement("button");
1082
+ cancelBtn.className = "toast-btn toast-btn-cancel";
1083
+ cancelBtn.textContent = confirmOptions.cancelText;
1084
+ cancelBtn.onclick = () => {
1085
+ handleConfirmation(false);
1086
+ this.removeToast(toast);
1087
+ };
1088
+
1089
+ // Confirm button
1090
+ const confirmBtn = document.createElement("button");
1091
+ confirmBtn.className = `toast-btn toast-btn-confirm`;
1092
+ confirmBtn.textContent = confirmOptions.confirmText;
1093
+ confirmBtn.onclick = () => {
1094
+ handleConfirmation(true);
1095
+ this.removeToast(toast);
1096
+ };
1097
+
1098
+ actionsWrapper.appendChild(cancelBtn);
1099
+ actionsWrapper.appendChild(confirmBtn);
1100
+ toast.appendChild(actionsWrapper);
1101
+
1102
+ // Add toast to the specified container (not default container)
1103
+ confirmContainer.appendChild(toast);
1104
+
1105
+ // Entrance animation
1106
+ setTimeout(() => {
1107
+ toast.classList.add("show");
1108
+ const icon = toast.querySelector('.toast-icon');
1109
+ if (icon) {
1110
+ icon.style.animation = 'iconBounce 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275)';
1111
+ }
1112
+ }, 10);
1113
+
1114
+ return toast;
1115
+ } catch (error) {
1116
+ console.error('ToastifyPro: Failed to create confirmation toast:', error);
1117
+ }
1118
+ }
719
1119
  }
720
1120
 
721
1121
  /**