toastify-pro 1.4.0 → 1.5.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.
@@ -14,17 +14,16 @@
14
14
  * - Position-aware car swipe exit animations
15
15
  * - Description support for enhanced messaging
16
16
  * - Six theme variants (success, error, info, warning, dark, light)
17
+ * - Custom color toasts with gradient support (custom method)
17
18
  * - Progress bar with shimmer effects
18
19
  * - Responsive design for mobile devices
19
20
  * - Framework agnostic (works with React, Vue, Angular, etc.)
20
21
  * - Confirmation dialogs with customizable buttons and callbacks
22
+ * - Confirmation overlay with blur effect for focus
21
23
  * - Center position support for enhanced focus
22
24
  * - Independent positioning for confirmations
23
- * - Loading states for async operations
24
- * - Custom gradient colors with primaryColor/secondaryColor
25
- * - Single instance mode with shake animation
26
25
  *
27
- * @version 1.4.0
26
+ * @version 1.5.0
28
27
  * @author ToastifyPro Team
29
28
  * @license MIT
30
29
  */
@@ -40,6 +39,8 @@
40
39
  * @param {number} options.timeout - Auto-dismiss timeout in milliseconds (0 to disable)
41
40
  * @param {boolean} options.allowClose - Whether to show close button
42
41
  * @param {number} options.maxLength - Maximum message length
42
+ * @param {string} options.primaryColor - Primary color for custom() method
43
+ * @param {string} options.secondaryColor - Secondary color for gradient in custom() method
43
44
  */
44
45
  constructor(options = {}) {
45
46
  // Validate options parameter
@@ -54,6 +55,8 @@
54
55
  timeout: options.timeout || 3000,
55
56
  allowClose: options.allowClose !== false, // default true
56
57
  maxLength: options.maxLength || 100,
58
+ primaryColor: options.primaryColor || null, // Custom primary color for custom() method
59
+ secondaryColor: options.secondaryColor || null, // Custom secondary color for gradient
57
60
  };
58
61
 
59
62
  // Validate position
@@ -798,6 +801,58 @@
798
801
  max-width: calc(100vw - 32px);
799
802
  }
800
803
  }
804
+
805
+ /* Custom toast type */
806
+ .toastify-pro.custom {
807
+ border-color: rgba(255, 255, 255, 0.2);
808
+ }
809
+
810
+ .toastify-pro.custom.light-text {
811
+ color: #1e293b;
812
+ }
813
+
814
+ .toastify-pro.custom.light-text .toast-icon {
815
+ background: rgba(15, 23, 42, 0.1);
816
+ }
817
+
818
+ .toastify-pro.custom.light-text .close-btn {
819
+ background: rgba(15, 23, 42, 0.08);
820
+ }
821
+
822
+ .toastify-pro.custom.light-text .close-btn:hover {
823
+ background: rgba(15, 23, 42, 0.15);
824
+ }
825
+
826
+ .toastify-pro.custom.light-text::before {
827
+ background: linear-gradient(90deg,
828
+ rgba(30, 41, 59, 0.8) 0%,
829
+ rgba(30, 41, 59, 0.4) 50%,
830
+ rgba(30, 41, 59, 0.8) 100%);
831
+ }
832
+
833
+ .toastify-pro.custom.light-text::after {
834
+ background: rgba(30, 41, 59, 0.6);
835
+ }
836
+
837
+ /* Confirmation Overlay */
838
+ .toastify-pro-overlay {
839
+ position: fixed;
840
+ top: 0;
841
+ left: 0;
842
+ right: 0;
843
+ bottom: 0;
844
+ background: rgba(0, 0, 0, 0.5);
845
+ backdrop-filter: blur(8px);
846
+ -webkit-backdrop-filter: blur(8px);
847
+ z-index: 9998;
848
+ opacity: 0;
849
+ transition: opacity 0.3s ease;
850
+ pointer-events: auto;
851
+ }
852
+
853
+ .toastify-pro-overlay.show {
854
+ opacity: 1;
855
+ }
801
856
  `;
802
857
  document.head.appendChild(style);
803
858
  } catch (error) {
@@ -1039,6 +1094,168 @@
1039
1094
  this.show(msg, "light", opts);
1040
1095
  }
1041
1096
 
1097
+ /**
1098
+ * Shows a custom-colored toast notification with gradient support
1099
+ * @param {string} msg - Main message
1100
+ * @param {string|Object} opts - Description string or options object
1101
+ * @param {string} opts.primaryColor - Primary color for the toast
1102
+ * @param {string} opts.secondaryColor - Secondary color for gradient (optional)
1103
+ */
1104
+ custom(msg, opts) {
1105
+ if (typeof opts === 'string') {
1106
+ opts = { description: opts };
1107
+ }
1108
+
1109
+ opts = opts || {};
1110
+
1111
+ // Get colors from options or use default options
1112
+ const primaryColor = opts.primaryColor || this.defaultOptions.primaryColor;
1113
+ const secondaryColor = opts.secondaryColor || this.defaultOptions.secondaryColor;
1114
+
1115
+ // If no custom colors provided, fallback to success style
1116
+ if (!primaryColor) {
1117
+ return this.success(msg, opts);
1118
+ }
1119
+
1120
+ // Helper function to determine if a color is light
1121
+ const isLightColor = (color) => {
1122
+ if (!color) return false;
1123
+ const hex = color.replace('#', '');
1124
+ const r = parseInt(hex.substr(0, 2), 16);
1125
+ const g = parseInt(hex.substr(2, 2), 16);
1126
+ const b = parseInt(hex.substr(4, 2), 16);
1127
+ const brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000;
1128
+ return brightness > 155;
1129
+ };
1130
+
1131
+ // Helper function to lighten or darken a color
1132
+ const adjustColor = (color, percent) => {
1133
+ const hex = color.replace('#', '');
1134
+ const r = parseInt(hex.substr(0, 2), 16);
1135
+ const g = parseInt(hex.substr(2, 2), 16);
1136
+ const b = parseInt(hex.substr(4, 2), 16);
1137
+
1138
+ const adjust = (c) => {
1139
+ const adjusted = Math.round(c + (percent / 100) * (percent > 0 ? (255 - c) : c));
1140
+ return Math.max(0, Math.min(255, adjusted));
1141
+ };
1142
+
1143
+ const newR = adjust(r).toString(16).padStart(2, '0');
1144
+ const newG = adjust(g).toString(16).padStart(2, '0');
1145
+ const newB = adjust(b).toString(16).padStart(2, '0');
1146
+
1147
+ return `#${newR}${newG}${newB}`;
1148
+ };
1149
+
1150
+ // Determine gradient colors
1151
+ let gradientStart = primaryColor;
1152
+ let gradientEnd;
1153
+
1154
+ if (secondaryColor) {
1155
+ // Both colors provided
1156
+ gradientEnd = secondaryColor;
1157
+ } else {
1158
+ // Only primary color - create gradient with lighter/darker shade
1159
+ const isLight = isLightColor(primaryColor);
1160
+ gradientEnd = isLight ? adjustColor(primaryColor, -25) : adjustColor(primaryColor, 25);
1161
+ }
1162
+
1163
+ // Determine text color
1164
+ const needsLightText = isLightColor(primaryColor);
1165
+
1166
+ // Create custom options
1167
+ const customOpts = {
1168
+ ...opts,
1169
+ customGradient: `linear-gradient(135deg, ${gradientStart} 0%, ${gradientEnd} 100%)`,
1170
+ customTextLight: needsLightText
1171
+ };
1172
+
1173
+ this.showCustom(msg, customOpts);
1174
+ }
1175
+
1176
+ /**
1177
+ * Internal method to show a custom-styled toast
1178
+ * @param {string} message - Main message text
1179
+ * @param {Object} opts - Options including customGradient and customTextLight
1180
+ */
1181
+ showCustom(message, opts = {}) {
1182
+ if (typeof message !== 'string') {
1183
+ message = String(message);
1184
+ }
1185
+
1186
+ if (!message.trim()) {
1187
+ console.warn('ToastifyPro: Empty message provided.');
1188
+ return;
1189
+ }
1190
+
1191
+ const options = { ...this.defaultOptions, ...opts };
1192
+
1193
+ try {
1194
+ const toast = document.createElement("div");
1195
+ toast.className = `toastify-pro custom${options.customTextLight ? ' light-text' : ''}`;
1196
+
1197
+ // Apply custom gradient
1198
+ if (options.customGradient) {
1199
+ toast.style.background = options.customGradient;
1200
+ }
1201
+
1202
+ if (options.timeout > 0) {
1203
+ toast.style.setProperty('--duration', `${options.timeout}ms`);
1204
+ }
1205
+
1206
+ // Create icon wrapper
1207
+ const iconWrapper = document.createElement("div");
1208
+ iconWrapper.className = "toast-icon";
1209
+ iconWrapper.innerHTML = this.getIconSVG('success'); // Use success icon for custom
1210
+ toast.appendChild(iconWrapper);
1211
+
1212
+ // Create content wrapper
1213
+ const contentWrapper = document.createElement("div");
1214
+ contentWrapper.className = "toast-content";
1215
+
1216
+ const messageElement = document.createElement("div");
1217
+ messageElement.className = "toast-message";
1218
+ messageElement.textContent = message.substring(0, options.maxLength);
1219
+ contentWrapper.appendChild(messageElement);
1220
+
1221
+ if (options.description && typeof options.description === 'string') {
1222
+ const descriptionElement = document.createElement("div");
1223
+ descriptionElement.className = "toast-description";
1224
+ descriptionElement.textContent = options.description.substring(0, options.maxLength * 2);
1225
+ contentWrapper.appendChild(descriptionElement);
1226
+ }
1227
+
1228
+ toast.appendChild(contentWrapper);
1229
+
1230
+ if (options.allowClose) {
1231
+ const closeBtn = document.createElement("span");
1232
+ closeBtn.className = "close-btn";
1233
+ closeBtn.innerHTML = "×";
1234
+ closeBtn.setAttribute('aria-label', 'Close notification');
1235
+ closeBtn.onclick = () => this.removeToast(toast);
1236
+ toast.appendChild(closeBtn);
1237
+ }
1238
+
1239
+ this.container.appendChild(toast);
1240
+
1241
+ setTimeout(() => {
1242
+ toast.classList.add("show");
1243
+ const icon = toast.querySelector('.toast-icon');
1244
+ if (icon) {
1245
+ icon.style.animation = 'iconBounce 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275)';
1246
+ }
1247
+ }, 10);
1248
+
1249
+ if (options.timeout > 0) {
1250
+ setTimeout(() => this.removeToast(toast), options.timeout);
1251
+ }
1252
+
1253
+ return toast;
1254
+ } catch (error) {
1255
+ console.error('ToastifyPro: Failed to create custom toast:', error);
1256
+ }
1257
+ }
1258
+
1042
1259
  /**
1043
1260
  * Shows a confirmation toast with confirm/cancel buttons
1044
1261
  * @param {string} message - Main confirmation question
@@ -1166,6 +1383,34 @@
1166
1383
  let isLoading = false;
1167
1384
  let useLoading = false; // Track if user wants loading behavior
1168
1385
  let toastElement = null; // Reference to toast element
1386
+ let overlayElement = null; // Reference to overlay element
1387
+
1388
+ // Create overlay for confirmation
1389
+ const createOverlay = () => {
1390
+ overlayElement = document.createElement("div");
1391
+ overlayElement.className = "toastify-pro-overlay";
1392
+ document.body.appendChild(overlayElement);
1393
+
1394
+ // Trigger show animation
1395
+ setTimeout(() => {
1396
+ overlayElement.classList.add("show");
1397
+ }, 10);
1398
+
1399
+ return overlayElement;
1400
+ };
1401
+
1402
+ // Remove overlay
1403
+ const removeOverlay = () => {
1404
+ if (overlayElement && overlayElement.parentNode) {
1405
+ overlayElement.classList.remove("show");
1406
+ setTimeout(() => {
1407
+ if (overlayElement && overlayElement.parentNode) {
1408
+ overlayElement.remove();
1409
+ }
1410
+ overlayElement = null;
1411
+ }, 300);
1412
+ }
1413
+ };
1169
1414
 
1170
1415
  const setLoading = (loading) => {
1171
1416
  useLoading = true; // User is manually controlling loading
@@ -1195,6 +1440,7 @@
1195
1440
  const closeConfirmation = () => {
1196
1441
  if (toastElement && toastElement.parentNode) {
1197
1442
  globalActiveConfirmation = null;
1443
+ removeOverlay(); // Remove the overlay when closing
1198
1444
  this.removeToast(toastElement);
1199
1445
  }
1200
1446
  };
@@ -1282,6 +1528,9 @@
1282
1528
  };
1283
1529
 
1284
1530
  try {
1531
+ // Create overlay first
1532
+ createOverlay();
1533
+
1285
1534
  // Create confirmation toast element
1286
1535
  const toast = document.createElement("div");
1287
1536
  toast.className = `toastify-pro confirmation ${confirmOptions.theme}`;