mypgs 1.6.0 → 2.0.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.
Files changed (88) hide show
  1. package/AGENTS.md +2 -2
  2. package/assets/javascript/components/_accordion.js +2 -2
  3. package/assets/javascript/components/_modals.js +159 -136
  4. package/assets/javascript/components/_notifications.js +19 -9
  5. package/assets/javascript/components/_search.js +2 -2
  6. package/assets/javascript/components/_slides.js +66 -32
  7. package/assets/javascript/components/_stepTabs.js +4 -4
  8. package/assets/javascript/components/_steps.js +2 -2
  9. package/assets/javascript/components/_summary.js +2 -2
  10. package/assets/javascript/functions/_formValidate.js +97 -53
  11. package/assets/javascript/functions/_scrollY.js +10 -10
  12. package/assets/javascript/layout/_header.js +3 -0
  13. package/assets/scss/base/_html.scss +2 -2
  14. package/assets/scss/base/_variables.scss +2 -2
  15. package/assets/scss/components/_form.scss +2 -2
  16. package/assets/scss/components/_notification.scss +23 -30
  17. package/assets/scss/components/_search.scss +27 -21
  18. package/assets/scss/layout/_pageShell.scss +18 -15
  19. package/assets/scss/mixin/_mx-form.scss +7 -7
  20. package/{templates/html → demo}/demo.html +1 -1
  21. package/demo/demo.js +240 -0
  22. package/dist/css/index.css +86 -92
  23. package/dist/css/index.css.map +1 -1
  24. package/dist/css/index.min.css +1 -1
  25. package/dist/javascript/index.js +356 -255
  26. package/dist/javascript/index.js.map +1 -1
  27. package/dist/javascript/index.min.js +1 -1
  28. package/docs/componenti-e-markup.md +26 -27
  29. package/docs/components/accordion.md +61 -0
  30. package/docs/components/badges.md +67 -0
  31. package/docs/components/breadcumbs.md +43 -0
  32. package/docs/components/button.md +59 -0
  33. package/docs/components/card.md +50 -0
  34. package/docs/components/dropdown.md +135 -0
  35. package/docs/components/form.md +113 -0
  36. package/docs/components/logo.md +36 -0
  37. package/docs/components/menu.md +90 -0
  38. package/docs/components/modal.md +131 -0
  39. package/docs/components/notification.md +81 -0
  40. package/docs/components/search.md +117 -0
  41. package/docs/components/slides.md +85 -0
  42. package/docs/components/stepTabs.md +93 -0
  43. package/docs/components/steps.md +56 -0
  44. package/docs/components/summary.md +49 -0
  45. package/docs/components/table.md +42 -0
  46. package/docs/components/tooltip.md +53 -0
  47. package/docs/helper-javascript.md +68 -3
  48. package/docs/layout/body.md +41 -0
  49. package/docs/layout/flex.md +116 -0
  50. package/docs/layout/footer.md +71 -0
  51. package/docs/layout/grid.md +116 -0
  52. package/docs/layout/header.md +116 -0
  53. package/docs/layout/pageShell.md +94 -0
  54. package/docs/layout/section.md +69 -0
  55. package/docs/patterns/cookieConsent.md +89 -0
  56. package/package.json +2 -1
  57. package/scripts/generate-component-docs.js +557 -0
  58. package/templates/html/components/accordion.html +33 -4
  59. package/templates/html/components/badges.html +23 -0
  60. package/templates/html/components/breadcumbs.html +14 -0
  61. package/templates/html/components/button.html +22 -0
  62. package/templates/html/components/card.html +20 -0
  63. package/templates/html/components/dropdown.html +34 -0
  64. package/templates/html/components/form.html +82 -4
  65. package/templates/html/components/logo.html +21 -0
  66. package/templates/html/components/menu.html +33 -6
  67. package/templates/html/components/modal.html +44 -0
  68. package/templates/html/components/notification.html +68 -32
  69. package/templates/html/components/search.html +76 -0
  70. package/templates/html/components/slides.html +43 -0
  71. package/templates/html/components/stepTabs.html +47 -0
  72. package/templates/html/components/steps.html +24 -0
  73. package/templates/html/components/summary.html +27 -0
  74. package/templates/html/components/table.html +12 -0
  75. package/templates/html/components/tooltip.html +35 -0
  76. package/templates/html/layout/body.html +20 -5
  77. package/templates/html/layout/flex.html +20 -0
  78. package/templates/html/layout/footer.html +29 -1
  79. package/templates/html/layout/grid.html +20 -0
  80. package/templates/html/layout/header.html +41 -0
  81. package/templates/html/layout/pageShell.html +19 -0
  82. package/templates/html/layout/section.html +32 -10
  83. package/templates/html/patterns/cookieConsent.html +31 -0
  84. package/templates/react/components/form.jsx +3 -3
  85. package/templates/react/components/notification.jsx +4 -4
  86. package/templates/react/patterns/footer.jsx +1 -1
  87. package/templates/html/demo.js +0 -130
  88. /package/{templates/html → demo}/demo.css +0 -0
@@ -643,9 +643,7 @@ const PGS_svg = {
643
643
  "use strict";
644
644
  __webpack_require__.r(__webpack_exports__);
645
645
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
646
- /* harmony export */ PGS_accordion: () => (/* binding */ PGS_accordion),
647
- /* harmony export */ PGS_accordion_api: () => (/* binding */ PGS_accordion_api),
648
- /* harmony export */ PGS_accordion_init: () => (/* binding */ PGS_accordion_init)
646
+ /* harmony export */ PGS_accordion: () => (/* binding */ PGS_accordion)
649
647
  /* harmony export */ });
650
648
  //= ACCORDION
651
649
  const API = new WeakMap();
@@ -1079,168 +1077,189 @@ const PGS_menu = {
1079
1077
  "use strict";
1080
1078
  __webpack_require__.r(__webpack_exports__);
1081
1079
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1082
- /* harmony export */ PGS_modal: () => (/* binding */ PGS_modal),
1083
- /* harmony export */ PGS_modal_api: () => (/* binding */ PGS_modal_api),
1084
- /* harmony export */ PGS_modal_init: () => (/* binding */ PGS_modal_init)
1080
+ /* harmony export */ PGS_modal: () => (/* binding */ PGS_modal)
1085
1081
  /* harmony export */ });
1086
1082
  //# MODAL
1087
1083
  const API = new WeakMap();
1088
1084
 
1089
- function PGS_modal_init(selector = "modal") {
1090
- pgs(document).querySelectorAll(selector).forEach(MODAL => {
1091
- if (API.has(MODAL)) return;
1085
+ function getModals(root) {
1086
+ const modals = root instanceof Element && pgs(root).contains("modal") ? [root] : [];
1087
+ modals.push(...pgs(root).querySelectorAll("modal"));
1088
+ return modals;
1089
+ }
1092
1090
 
1093
- const BUTTON_OPEN = pgs(MODAL).querySelector("modal-button");
1094
- const DIALOG = MODAL.querySelector("dialog");
1095
- if (!BUTTON_OPEN || !DIALOG) return;
1091
+ function initializeModal(MODAL, existingDialog = null) {
1092
+ if (API.has(MODAL)) return;
1096
1093
 
1097
- //== SELECTOR
1098
- const DOMButtonClose = '<button pgs="buttonClose modal-close" type="button" tabindex="0" aria-label="Chiudi"><i class="fa-solid fa-close"></i></button>';
1099
- const modalContentHeader = pgs(MODAL)?.querySelector("modal-dialog-content-header")
1100
-
1101
-
1102
- //== OPTION ATTRIBUTES MODAL
1103
- const disableBackdropClose = pgs(MODAL).option.contains("disableBackdropClose")
1104
- const data_history = pgs(MODAL).option.contains("history");
1105
- const data_container = pgs(MODAL).option.getValueBrackets("containerID");
1106
- const data_containerPGS = pgs(MODAL).option.getValueBrackets("containerPGS");
1107
-
1108
- //== OPTION ATTRIBUTES DIALOG
1109
- const topLevel = pgs(DIALOG).option.contains("topLevel")
1094
+ const BUTTON_OPEN = pgs(MODAL).querySelector("modal-button");
1095
+ const DIALOG = existingDialog || MODAL.querySelector("dialog");
1096
+ if (!BUTTON_OPEN || !DIALOG) return;
1097
+ const eventController = new AbortController();
1098
+ const { signal } = eventController;
1099
+ let historyObserver = null;
1100
+ let historyTimeout = null;
1110
1101
 
1111
-
1112
- //== BUTTON CLOSE
1113
- if (pgs(MODAL).querySelector("modal-close")) null
1114
- else if (modalContentHeader) modalContentHeader.insertAdjacentHTML("beforeend", DOMButtonClose)
1115
- else DIALOG.insertAdjacentHTML("beforeend", DOMButtonClose)
1116
- const BUTTON_CLOSE = pgs(MODAL).querySelector("modal-close")
1102
+ //== SELECTOR
1103
+ const DOMButtonClose = '<button pgs="buttonClose modal-close" type="button" tabindex="0" aria-label="Chiudi"><i class="fa-solid fa-close"></i></button>';
1104
+ const modalContentHeader = pgs(DIALOG).querySelector("modal-dialog-content-header");
1117
1105
 
1118
1106
 
1119
- //== SET
1120
- pgs(DIALOG).add("dialog modal-dialog");
1107
+ //== OPTION ATTRIBUTES MODAL
1108
+ const disableBackdropClose = pgs(MODAL).option.contains("disableBackdropClose");
1109
+ const data_history = pgs(MODAL).option.contains("history");
1110
+ const data_container = pgs(MODAL).option.getValueBrackets("containerID");
1111
+ const data_containerPGS = pgs(MODAL).option.getValueBrackets("containerPGS");
1121
1112
 
1122
- //== BUTTON OPEN
1123
- BUTTON_OPEN.setAttribute("role", "button");
1124
- BUTTON_OPEN.setAttribute("aria-label", "apri modale");
1113
+ //== OPTION ATTRIBUTES DIALOG
1114
+ const topLevel = pgs(DIALOG).option.contains("topLevel");
1125
1115
 
1126
1116
 
1127
- //== POSITION
1128
- if(!topLevel){
1129
- if (data_container) document.querySelector("#" + data_container)?.append(DIALOG);
1130
- else if (data_containerPGS) pgs(document).querySelector(data_containerPGS)?.append(DIALOG);
1131
- else document.body.append(DIALOG);
1132
- }
1117
+ //== BUTTON CLOSE
1118
+ if (!pgs(DIALOG).querySelector("modal-close") && !pgs(MODAL).querySelector("modal-close")) {
1119
+ if (modalContentHeader) modalContentHeader.insertAdjacentHTML("beforeend", DOMButtonClose);
1120
+ else DIALOG.insertAdjacentHTML("beforeend", DOMButtonClose);
1121
+ }
1122
+ const BUTTON_CLOSE = pgs(DIALOG).querySelector("modal-close") || pgs(MODAL).querySelector("modal-close");
1133
1123
 
1134
1124
 
1135
- //+ FN STATUS
1136
- function statusModal(status = true) {
1137
- BUTTON_OPEN?.setAttribute("aria-expanded", status);
1138
- DIALOG?.setAttribute("aria-expanded", status);
1139
- }
1125
+ //== SET
1126
+ pgs(DIALOG).add("dialog modal-dialog");
1140
1127
 
1141
- //+ FN OPEN
1142
- function openModal(e) {
1143
- e?.stopImmediatePropagation();
1144
- if (DIALOG.open) {
1145
- closeModal(e);
1146
- return;
1147
- }
1128
+ //== BUTTON OPEN
1129
+ BUTTON_OPEN.setAttribute("role", "button");
1130
+ BUTTON_OPEN.setAttribute("aria-label", "apri modale");
1148
1131
 
1149
- if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
1150
- statusModal(true);
1151
- topLevel ? DIALOG.showModal() : DIALOG.show();
1152
- // modalCustomEvents('modal:open', { event: e });
1153
- MODAL.dispatchEvent(new CustomEvent('modal:open'));
1154
- DIALOG.dispatchEvent(new CustomEvent('modal:open'));
1155
- }
1156
1132
 
1157
- //+ FN CLOSE
1158
- function closeModal(e) {
1159
- e?.stopImmediatePropagation()
1160
- statusModal(false);
1161
- DIALOG.close();
1162
- // modalCustomEvents('modal:close', { event: e });
1163
- MODAL.dispatchEvent(new CustomEvent('modal:close'));
1164
- DIALOG.dispatchEvent(new CustomEvent('modal:close'));
1165
- }
1133
+ //== POSITION
1134
+ if (topLevel && !MODAL.contains(DIALOG)) MODAL.append(DIALOG);
1135
+ else if (!topLevel) {
1136
+ if (data_container) document.querySelector("#" + data_container)?.append(DIALOG);
1137
+ else if (data_containerPGS) pgs(document).querySelector(data_containerPGS)?.append(DIALOG);
1138
+ else document.body.append(DIALOG);
1139
+ }
1166
1140
 
1167
- function forceOpen(e) {
1168
- if (!DIALOG.open) openModal(e);
1169
- }
1170
1141
 
1171
- function forceClose(e) {
1172
- if (DIALOG.open) closeModal(e);
1173
- }
1142
+ //+ FN STATUS
1143
+ function statusModal(status = true) {
1144
+ BUTTON_OPEN?.setAttribute("aria-expanded", status);
1145
+ DIALOG?.setAttribute("aria-expanded", status);
1146
+ }
1174
1147
 
1175
- //+ fn OPEN ON HISTORY
1176
- function openModalOnHistory() {
1177
- const params = new URLSearchParams(window.location.search);
1178
- if (params.get('modal') !== BUTTON_OPEN.id) return;
1179
- document.getElementById(BUTTON_OPEN.id)?.scrollIntoView({ behavior: 'smooth' });
1180
- openModal();
1148
+ //+ FN OPEN
1149
+ function openModal(e) {
1150
+ e?.stopImmediatePropagation();
1151
+ if (DIALOG.open) {
1152
+ closeModal(e);
1153
+ return;
1181
1154
  }
1182
1155
 
1156
+ if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
1157
+ statusModal(true);
1158
+ topLevel ? DIALOG.showModal() : DIALOG.show();
1159
+ // modalCustomEvents('modal:open', { event: e });
1160
+ MODAL.dispatchEvent(new CustomEvent('modal:open'));
1161
+ DIALOG.dispatchEvent(new CustomEvent('modal:open'));
1162
+ }
1183
1163
 
1184
- //= OPEN
1185
- BUTTON_OPEN.addEventListener("click", (e) => openModal(e));
1186
- BUTTON_OPEN.addEventListener("keypress", (e) => !DIALOG.open && (e.key === "Enter" || e.key === " ") && openModal(e));
1187
-
1188
- //= CLOSE
1189
- DIALOG.addEventListener("close", () => statusModal(false));
1190
- DIALOG.addEventListener("click", e => { if (e.target == DIALOG && !disableBackdropClose) closeModal(e) });
1191
- BUTTON_CLOSE?.addEventListener("click", e => closeModal(e));
1192
-
1193
- //= UPDATE HISTORY
1194
- if (data_history && BUTTON_OPEN.id) {
1195
- setTimeout(openModalOnHistory, 1);
1196
-
1197
- //== Aggiorna URL quando cambia l'attributo "open" del dialog
1198
- const obs = new MutationObserver(() => {
1199
- let isOpen = DIALOG.hasAttribute("open");
1200
- try {
1201
- const url = new URL(window.location.href);
1202
- const params = new URLSearchParams(url.search);
1203
- isOpen ? params.set('modal', BUTTON_OPEN.id) : params.delete('modal');
1204
- url.search = params.toString() ? `?${params.toString()}` : "";
1205
- window.history.pushState({ modal: BUTTON_OPEN.id, open: isOpen }, "", url);
1206
- } catch (_) { }
1207
- });
1208
- obs.observe(DIALOG, { attributes: true, attributeFilter: ["open"] });
1209
-
1210
- //== Gestisce back/forward del browser per aprire/chiudere il dialog coerentemente
1211
- window.addEventListener("popstate", () => {
1212
- try {
1213
- const params = new URLSearchParams(window.location.search);
1214
- const shouldOpen = params.get('modal') === BUTTON_OPEN.id;
1215
- if (shouldOpen && !DIALOG.open) DIALOG.showModal();
1216
- if (!shouldOpen && DIALOG.open) closeModal()
1217
- } catch (_) { }
1218
- });
1219
- }
1164
+ //+ FN CLOSE
1165
+ function closeModal(e) {
1166
+ e?.stopImmediatePropagation()
1167
+ statusModal(false);
1168
+ DIALOG.close();
1169
+ // modalCustomEvents('modal:close', { event: e });
1170
+ MODAL.dispatchEvent(new CustomEvent('modal:close'));
1171
+ DIALOG.dispatchEvent(new CustomEvent('modal:close'));
1172
+ }
1220
1173
 
1221
- API.set(MODAL, {
1222
- element: MODAL,
1223
- button: BUTTON_OPEN,
1224
- dialog: DIALOG,
1225
- closeButton: BUTTON_CLOSE,
1226
- open: forceOpen,
1227
- close: forceClose,
1228
- toggle: openModal,
1229
- refresh: () => {
1230
- PGS_modal_init(selector);
1231
- return API.get(MODAL);
1232
- },
1233
- isOpen: () => DIALOG.open,
1174
+ function forceOpen(e) {
1175
+ if (!DIALOG.open) openModal(e);
1176
+ }
1177
+
1178
+ function forceClose(e) {
1179
+ if (DIALOG.open) closeModal(e);
1180
+ }
1181
+
1182
+ //+ fn OPEN ON HISTORY
1183
+ function openModalOnHistory() {
1184
+ const params = new URLSearchParams(window.location.search);
1185
+ if (params.get('modal') !== BUTTON_OPEN.id) return;
1186
+ document.getElementById(BUTTON_OPEN.id)?.scrollIntoView({ behavior: 'smooth' });
1187
+ openModal();
1188
+ }
1189
+
1190
+
1191
+ //= OPEN
1192
+ BUTTON_OPEN.addEventListener("click", (e) => openModal(e), { signal });
1193
+ BUTTON_OPEN.addEventListener("keypress", (e) => !DIALOG.open && (e.key === "Enter" || e.key === " ") && openModal(e), { signal });
1194
+
1195
+ //= CLOSE
1196
+ DIALOG.addEventListener("close", () => statusModal(false), { signal });
1197
+ DIALOG.addEventListener("click", e => { if (e.target == DIALOG && !disableBackdropClose) closeModal(e) }, { signal });
1198
+ BUTTON_CLOSE?.addEventListener("click", e => closeModal(e), { signal });
1199
+
1200
+ //= UPDATE HISTORY
1201
+ if (data_history && BUTTON_OPEN.id) {
1202
+ historyTimeout = window.setTimeout(openModalOnHistory, 1);
1203
+
1204
+ //== Aggiorna URL quando cambia l'attributo "open" del dialog
1205
+ historyObserver = new MutationObserver(() => {
1206
+ let isOpen = DIALOG.hasAttribute("open");
1207
+ try {
1208
+ const url = new URL(window.location.href);
1209
+ const params = new URLSearchParams(url.search);
1210
+ isOpen ? params.set('modal', BUTTON_OPEN.id) : params.delete('modal');
1211
+ url.search = params.toString() ? `?${params.toString()}` : "";
1212
+ window.history.pushState({ modal: BUTTON_OPEN.id, open: isOpen }, "", url);
1213
+ } catch (_) { }
1234
1214
  });
1215
+ historyObserver.observe(DIALOG, { attributes: true, attributeFilter: ["open"] });
1216
+
1217
+ //== Gestisce back/forward del browser per aprire/chiudere il dialog coerentemente
1218
+ window.addEventListener("popstate", () => {
1219
+ try {
1220
+ const params = new URLSearchParams(window.location.search);
1221
+ const shouldOpen = params.get('modal') === BUTTON_OPEN.id;
1222
+ if (shouldOpen && !DIALOG.open) DIALOG.showModal();
1223
+ if (!shouldOpen && DIALOG.open) closeModal()
1224
+ } catch (_) { }
1225
+ }, { signal });
1226
+ }
1227
+
1228
+ function destroy() {
1229
+ eventController.abort();
1230
+ historyObserver?.disconnect();
1231
+ if (historyTimeout !== null) window.clearTimeout(historyTimeout);
1232
+ API.delete(MODAL);
1233
+ }
1234
+
1235
+ API.set(MODAL, {
1236
+ element: MODAL,
1237
+ button: BUTTON_OPEN,
1238
+ dialog: DIALOG,
1239
+ closeButton: BUTTON_CLOSE,
1240
+ open: forceOpen,
1241
+ close: forceClose,
1242
+ toggle: openModal,
1243
+ refresh: () => {
1244
+ const nextDialog = MODAL.querySelector("dialog") || DIALOG;
1245
+ destroy();
1246
+ initializeModal(MODAL, nextDialog);
1247
+ return API.get(MODAL);
1248
+ },
1249
+ isOpen: () => DIALOG.open,
1235
1250
  });
1236
1251
  }
1237
1252
 
1253
+ function PGS_modal_init(root = document) {
1254
+ getModals(root).forEach(MODAL => initializeModal(MODAL));
1255
+ }
1256
+
1238
1257
  //# INIT PGS_modal
1239
1258
  PGS_modal_init()
1240
1259
 
1241
1260
  //# API
1242
- function PGS_modal_api(selector) {
1243
- return API.get(selector);
1261
+ function PGS_modal_api(element) {
1262
+ return API.get(element);
1244
1263
  }
1245
1264
 
1246
1265
  const PGS_modal = {
@@ -1260,8 +1279,7 @@ const PGS_modal = {
1260
1279
  "use strict";
1261
1280
  __webpack_require__.r(__webpack_exports__);
1262
1281
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1263
- /* harmony export */ PGS_notification: () => (/* binding */ PGS_notification),
1264
- /* harmony export */ PGS_notificationTrigger_init: () => (/* binding */ PGS_notificationTrigger_init)
1282
+ /* harmony export */ PGS_notification: () => (/* binding */ PGS_notification)
1265
1283
  /* harmony export */ });
1266
1284
  //= PGS_notification
1267
1285
  const fn_notification = {
@@ -1289,10 +1307,12 @@ const fn_notification = {
1289
1307
  },
1290
1308
 
1291
1309
  _getData(root) {
1310
+ const rawNotification = pgs(root).option.getValueBrackets("notification") || "{}";
1311
+
1292
1312
  try {
1293
- return JSON.parse(root.dataset.notification || "{}");
1313
+ return JSON.parse(rawNotification);
1294
1314
  } catch (error) {
1295
- console.warn("PGS notification: dati non validi", error);
1315
+ console.warn("PGS notification: configurazione JSON non valida", error);
1296
1316
  return {};
1297
1317
  }
1298
1318
  },
@@ -1311,13 +1331,21 @@ const fn_notification = {
1311
1331
  `;
1312
1332
  },
1313
1333
 
1314
- initNotification(type, containerToken, icon, text, timeout, methodDelete = "replace", link = null) {
1315
- let containerNotification = pgs(document).querySelector(containerToken);
1334
+ _getContainer(containerType) {
1335
+ return Array.from(pgs(document).querySelectorAll("notification")).find(container => {
1336
+ const isToast = pgs(container).option.contains("toast");
1337
+ return containerType === "toast" ? isToast : !isToast;
1338
+ });
1339
+ },
1340
+
1341
+ initNotification(type, containerType, icon, text, timeout, methodDelete = "replace", link = null) {
1342
+ let containerNotification = this._getContainer(containerType);
1316
1343
 
1317
1344
  //== Create Container
1318
1345
  if (!containerNotification) {
1319
1346
  const newContainer = document.createElement("div");
1320
- pgs(newContainer).add(containerToken);
1347
+ pgs(newContainer).add("notification");
1348
+ if (containerType === "toast") pgs(newContainer).option.add("toast");
1321
1349
  newContainer.setAttribute("aria-live", "polite");
1322
1350
  newContainer.setAttribute("aria-relevant", "additions");
1323
1351
  document.body.appendChild(newContainer);
@@ -1363,8 +1391,8 @@ const fn_notification = {
1363
1391
  });
1364
1392
  },
1365
1393
 
1366
- deleteAll(containerToken) {
1367
- let containerNotification = pgs(document).querySelector(containerToken);
1394
+ deleteAll(containerType) {
1395
+ let containerNotification = this._getContainer(containerType);
1368
1396
  if (containerNotification) containerNotification.innerHTML = "";
1369
1397
  },
1370
1398
 
@@ -1398,7 +1426,7 @@ const fn_notification = {
1398
1426
  }
1399
1427
  };
1400
1428
 
1401
- //# EXPORT
1429
+ //# TRIGGER
1402
1430
  function PGS_notificationTrigger_init(root = document) {
1403
1431
  return fn_notification.trigger(root);
1404
1432
  }
@@ -1438,8 +1466,7 @@ else PGS_notificationTrigger_init();
1438
1466
  "use strict";
1439
1467
  __webpack_require__.r(__webpack_exports__);
1440
1468
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1441
- /* harmony export */ PGS_search: () => (/* binding */ PGS_search),
1442
- /* harmony export */ PGS_search_api: () => (/* binding */ PGS_search_api)
1469
+ /* harmony export */ PGS_search: () => (/* binding */ PGS_search)
1443
1470
  /* harmony export */ });
1444
1471
  const API = new WeakMap();
1445
1472
  const OPEN_SEARCHES = new Set();
@@ -1448,7 +1475,7 @@ let searchId = 0;
1448
1475
  const DEFAULT_OPTIONS = {
1449
1476
  minLength: 2,
1450
1477
  debounce: 200,
1451
- limit: 8,
1478
+ limit: 6,
1452
1479
  submitOnSelect: false,
1453
1480
  searchOnFocus: true,
1454
1481
  source: null,
@@ -1845,18 +1872,22 @@ const PGS_search = {
1845
1872
  "use strict";
1846
1873
  __webpack_require__.r(__webpack_exports__);
1847
1874
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1848
- /* harmony export */ PGS_slides: () => (/* binding */ PGS_slides),
1849
- /* harmony export */ PGS_slides_api: () => (/* binding */ PGS_slides_api),
1850
- /* harmony export */ PGS_slides_init: () => (/* binding */ PGS_slides_init)
1875
+ /* harmony export */ PGS_slides: () => (/* binding */ PGS_slides)
1851
1876
  /* harmony export */ });
1852
- /* harmony import */ var _functions_scrollY__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../functions/_scrollY */ "./assets/javascript/functions/_scrollY.js");
1877
+ /* harmony import */ var _functions_scrollY_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../functions/_scrollY.js */ "./assets/javascript/functions/_scrollY.js");
1853
1878
 
1854
1879
  const API = new WeakMap();
1855
1880
 
1881
+ function getSlides(root) {
1882
+ const slides = root instanceof Element && pgs(root).contains("slides") ? [root] : [];
1883
+ slides.push(...pgs(root).querySelectorAll("slides"));
1884
+ return slides;
1885
+ }
1886
+
1856
1887
  class PGS_Slides {
1857
1888
  //- CONSTRUCTOR
1858
- constructor({ selector, viewRatio = 0.97, optionIntersectionObserver = {}, scrollOptions = {} } = {}) {
1859
- this.selector = selector;
1889
+ constructor({ element, viewRatio = 0.97, optionIntersectionObserver = {}, scrollOptions = {} } = {}) {
1890
+ this.element = element;
1860
1891
  this.viewRatio = viewRatio;
1861
1892
 
1862
1893
  this.optionIntersectionObserver = {
@@ -1873,28 +1904,36 @@ class PGS_Slides {
1873
1904
  ...scrollOptions,
1874
1905
  };
1875
1906
 
1876
- this.container = this.selector ? pgs(this.selector).querySelector("slides-container") : null;
1907
+ this.container = this.element ? pgs(this.element).querySelector("slides-container") : null;
1877
1908
  }
1878
1909
 
1879
1910
  //+ CREATE BUTTON
1880
1911
  #createButtonsAndDots() {
1881
- const EL = this.selector
1912
+ const EL = this.element;
1882
1913
 
1883
1914
  //== PULSANTI
1884
- if (!pgs(EL).querySelector('slides-prec') && !pgs(EL).querySelector('slides-next')) {
1915
+ if (!pgs(EL).querySelector('slides-prec')) {
1885
1916
  EL.insertAdjacentHTML("afterbegin", `<button pgs="slides-prec buttonIcon" type="button" class="precButton" aria-label="slide precedente"> <span> <i class="fa-solid fa-arrow-left"></i></span></button>`);
1917
+ }
1918
+ if (!pgs(EL).querySelector('slides-next')) {
1886
1919
  EL.insertAdjacentHTML("beforeend", `<button pgs="slides-next buttonIcon" type="button" class="nextButton" aria-label="prossima slide"> <span> <i class="fa-solid fa-arrow-right"></i></span></button>`);
1887
1920
  }
1888
1921
 
1889
1922
  //== DOTS
1890
1923
  if (!pgs(EL).querySelector('slides-dots')) {
1891
1924
  EL.insertAdjacentHTML("beforeend", `<div pgs="slides-dots" class="slides-dots"></div>`);
1925
+ }
1892
1926
 
1893
- Array.from(this.container.children).forEach(() => {
1894
- pgs(EL).querySelector('slides-dots')
1895
- .insertAdjacentHTML("beforeend", `<button type="button" class="slide-dot" aria-label="vai alla prossima slide"></button>`);
1896
- });
1927
+ const dotsContainer = pgs(EL).querySelector('slides-dots');
1928
+ while (dotsContainer.children.length < this.container.children.length) {
1929
+ dotsContainer.insertAdjacentHTML("beforeend", `<button type="button" class="slide-dot"></button>`);
1930
+ }
1931
+ while (dotsContainer.children.length > this.container.children.length) {
1932
+ dotsContainer.lastElementChild.remove();
1897
1933
  }
1934
+ Array.from(dotsContainer.children).forEach((dot, index) => {
1935
+ dot.setAttribute("aria-label", `vai alla slide ${index + 1}`);
1936
+ });
1898
1937
  }
1899
1938
 
1900
1939
  //+ PREV
@@ -1903,7 +1942,7 @@ class PGS_Slides {
1903
1942
  let current;
1904
1943
 
1905
1944
 
1906
- if (pgs(this.selector).option.contains('singleScroll')) current = currents[currents.length - 1];
1945
+ if (pgs(this.element).option.contains('singleScroll')) current = currents[currents.length - 1];
1907
1946
  else current = currents[0];
1908
1947
 
1909
1948
  const prev = current?.previousElementSibling;
@@ -1919,19 +1958,17 @@ class PGS_Slides {
1919
1958
 
1920
1959
 
1921
1960
 
1922
- if (pgs(this.selector).option.contains('singleScroll')) current = currents[0];
1961
+ if (pgs(this.element).option.contains('singleScroll')) current = currents[0];
1923
1962
  else current = currents[currents.length - 1];
1924
1963
 
1925
1964
  const next = current?.nextElementSibling;
1926
- console.log(current, next);
1927
-
1928
1965
  next?.scrollIntoView(this.scrollOptions);
1929
1966
  next?.focus({ preventScroll: true });
1930
1967
  }
1931
1968
 
1932
1969
  //+ GO TO NUMBER SLIDE
1933
1970
  #goToNumberSlide(index) {
1934
- this.container.children[index].scrollIntoView(this.scrollOptions)
1971
+ this.container.children[index]?.scrollIntoView(this.scrollOptions);
1935
1972
  }
1936
1973
 
1937
1974
  //+ CALLBACK
@@ -1970,8 +2007,10 @@ class PGS_Slides {
1970
2007
 
1971
2008
  //= EXECUTE
1972
2009
  execute() {
1973
- const slides = this.selector;
1974
- if (!this.container) return
2010
+ const slides = this.element;
2011
+ if (!this.container) return;
2012
+ const eventController = new AbortController();
2013
+ const { signal } = eventController;
1975
2014
 
1976
2015
  //== elements
1977
2016
  this.#createButtonsAndDots();
@@ -1983,12 +2022,14 @@ class PGS_Slides {
1983
2022
  const notScrollWithMouse = pgs(slides).option.contains('notScrollWithMouse');
1984
2023
 
1985
2024
  //== scroll
1986
- if (!notScrollWithMouse) (0,_functions_scrollY__WEBPACK_IMPORTED_MODULE_0__.PGS_scrollHorizontal)(this.container, 5);
2025
+ const removeHorizontalScroll = notScrollWithMouse
2026
+ ? null
2027
+ : (0,_functions_scrollY_js__WEBPACK_IMPORTED_MODULE_0__.PGS_scrollHorizontal)(this.container, 5);
1987
2028
 
1988
2029
  //==Listener: DOT, PREC, NEXT
1989
- dots.forEach((dot, index) => dot.addEventListener("click", e => this.#goToNumberSlide(index)));
1990
- precButton.addEventListener("click", e => this.#previousSlide(), { passive: true });
1991
- nextButton.addEventListener("click", e => this.#nextSlide(), { passive: true });
2030
+ dots.forEach((dot, index) => dot.addEventListener("click", () => this.#goToNumberSlide(index), { signal }));
2031
+ precButton.addEventListener("click", () => this.#previousSlide(), { passive: true, signal });
2032
+ nextButton.addEventListener("click", () => this.#nextSlide(), { passive: true, signal });
1992
2033
 
1993
2034
  //== observer
1994
2035
  const observer = new IntersectionObserver(
@@ -1998,9 +2039,18 @@ class PGS_Slides {
1998
2039
  Array.from(this.container.children).forEach(allLi => observer.observe(allLi));
1999
2040
 
2000
2041
 
2042
+ let api;
2043
+ const destroy = () => {
2044
+ if (API.get(this.element) !== api) return;
2045
+ eventController.abort();
2046
+ observer.disconnect();
2047
+ removeHorizontalScroll?.();
2048
+ API.delete(this.element);
2049
+ };
2050
+
2001
2051
  //- API
2002
- API.set(this.selector, {
2003
- element: this.selector,
2052
+ api = {
2053
+ element: this.element,
2004
2054
  container: this.container,
2005
2055
  previous: () => this.#previousSlide(),
2006
2056
  next: () => this.#nextSlide(),
@@ -2015,19 +2065,28 @@ class PGS_Slides {
2015
2065
  return last?.classList.contains("view") || false;
2016
2066
  },
2017
2067
  refresh: () => {
2018
- PGS_slides_init(this.selector.parentNode || document);
2019
- return API.get(this.selector);
2068
+ if (API.get(this.element) !== api) return API.get(this.element);
2069
+ destroy();
2070
+ const instance = new PGS_Slides({
2071
+ element: this.element,
2072
+ viewRatio: this.viewRatio,
2073
+ optionIntersectionObserver: this.optionIntersectionObserver,
2074
+ scrollOptions: this.scrollOptions,
2075
+ });
2076
+ instance.execute();
2077
+ return API.get(this.element);
2020
2078
  },
2021
- });
2079
+ };
2080
+ API.set(this.element, api);
2022
2081
  }
2023
2082
  }
2024
2083
 
2025
2084
  //# INIT
2026
2085
  function PGS_slides_init(root = document) {
2027
- pgs(root).querySelectorAll("slides").forEach(el => {
2028
- if (API.has(el)) return;
2086
+ getSlides(root).forEach(element => {
2087
+ if (API.has(element)) return;
2029
2088
 
2030
- const instance = new PGS_Slides({ selector: el });
2089
+ const instance = new PGS_Slides({ element });
2031
2090
  instance.execute();
2032
2091
  });
2033
2092
  }
@@ -2035,8 +2094,8 @@ function PGS_slides_init(root = document) {
2035
2094
  PGS_slides_init();
2036
2095
 
2037
2096
  //# API
2038
- function PGS_slides_api(selector) {
2039
- return API.get(selector);
2097
+ function PGS_slides_api(element) {
2098
+ return API.get(element);
2040
2099
  }
2041
2100
 
2042
2101
  const PGS_slides = {
@@ -2056,9 +2115,7 @@ const PGS_slides = {
2056
2115
  "use strict";
2057
2116
  __webpack_require__.r(__webpack_exports__);
2058
2117
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2059
- /* harmony export */ PGS_stepTabs: () => (/* binding */ PGS_stepTabs),
2060
- /* harmony export */ PGS_stepTabs_api: () => (/* binding */ PGS_stepTabs_api),
2061
- /* harmony export */ PGS_stepTabs_init: () => (/* binding */ PGS_stepTabs_init)
2118
+ /* harmony export */ PGS_stepTabs: () => (/* binding */ PGS_stepTabs)
2062
2119
  /* harmony export */ });
2063
2120
  const API = new WeakMap();
2064
2121
 
@@ -2094,7 +2151,7 @@ function PGS_stepTabs_init(root = document) {
2094
2151
  const dot = document.createElement("button");
2095
2152
  dot.type = "button";
2096
2153
  pgs(dot).add("stepTabs-dots-dot");
2097
- dot.setAttribute("data-step", index);
2154
+ pgs(dot).option.setValueBrackets("step", index);
2098
2155
  dot.innerHTML = `<i class="fa-solid ${iconClass}"></i>`;
2099
2156
 
2100
2157
  dot.addEventListener("click", () => {
@@ -2159,7 +2216,7 @@ function PGS_stepTabs_init(root = document) {
2159
2216
  //= INIT
2160
2217
  goTo(0, false);
2161
2218
 
2162
- //= data-tab-locked
2219
+ //= tab-locked
2163
2220
  const observer = new MutationObserver(() => {
2164
2221
  if (isRendering) return;
2165
2222
  updateControls();
@@ -2242,9 +2299,7 @@ const PGS_stepTabs = {
2242
2299
  "use strict";
2243
2300
  __webpack_require__.r(__webpack_exports__);
2244
2301
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2245
- /* harmony export */ PGS_steps: () => (/* binding */ PGS_steps),
2246
- /* harmony export */ PGS_steps_api: () => (/* binding */ PGS_steps_api),
2247
- /* harmony export */ PGS_steps_init: () => (/* binding */ PGS_steps_init)
2302
+ /* harmony export */ PGS_steps: () => (/* binding */ PGS_steps)
2248
2303
  /* harmony export */ });
2249
2304
  const API = new WeakMap();
2250
2305
 
@@ -2312,9 +2367,7 @@ const PGS_steps = {
2312
2367
  "use strict";
2313
2368
  __webpack_require__.r(__webpack_exports__);
2314
2369
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2315
- /* harmony export */ PGS_summary: () => (/* binding */ PGS_summary),
2316
- /* harmony export */ PGS_summary_api: () => (/* binding */ PGS_summary_api),
2317
- /* harmony export */ PGS_summary_init: () => (/* binding */ PGS_summary_init)
2370
+ /* harmony export */ PGS_summary: () => (/* binding */ PGS_summary)
2318
2371
  /* harmony export */ });
2319
2372
  //= SUMMARY
2320
2373
  const API = new WeakMap();
@@ -2436,44 +2489,48 @@ __webpack_require__.r(__webpack_exports__);
2436
2489
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2437
2490
  /* harmony export */ PGS_formValidate: () => (/* binding */ PGS_formValidate)
2438
2491
  /* harmony export */ });
2439
- /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/_notifications.js */ "./assets/javascript/components/_notifications.js");
2492
+ /* harmony import */ var _pgs_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_pgs.js */ "./assets/javascript/_pgs.js");
2493
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/_notifications.js */ "./assets/javascript/components/_notifications.js");
2494
+
2440
2495
 
2441
2496
 
2442
2497
 
2443
2498
  class PGS_formValidate {
2444
- constructor({ form } = {}) {
2445
- this.container = form;
2446
- this._rules = [];
2447
- // pgs(this.container).add("formError");
2448
- }
2499
+ #message = {};
2500
+ #insideValidatedCallback = false;
2449
2501
 
2450
- //+ ADD
2451
- addError(field, i) {
2452
- field.setAttribute("data-form-field-status", "error");
2453
- if (i == 0) field.scrollIntoView();
2502
+ constructor(form, options = {}) {
2503
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
2504
+ throw new TypeError("options must be an object");
2505
+ }
2454
2506
 
2455
- let message = field.getAttribute("data-form-field-message");
2507
+ this.container = form;
2508
+ this._rules = [];
2509
+ this.message = {
2510
+ fieldError: "Please complete this field.",
2511
+ fieldsError: "Please complete all required fields.",
2512
+ success: "Submitted successfully."
2513
+ };
2456
2514
 
2457
- if (i == 0 && message) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.error(message);
2458
- else if (i == 0) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.error("Compila tutti i campi!");
2515
+ if (options.message !== undefined) this.message = options.message;
2516
+ this.container?.setAttribute("novalidate", "");
2459
2517
  }
2460
2518
 
2461
- //+ REMOVE
2462
- removeError(field) {
2463
- field.setAttribute("data-form-field-status", "");
2519
+ get message() {
2520
+ return { ...this.#message };
2464
2521
  }
2465
2522
 
2466
- #removeErrorOnClick(allFields) {
2467
- allFields.forEach(element => {
2468
- element.addEventListener("click", e => this.removeError(element))
2469
- });
2523
+ set message(value) {
2524
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2525
+ throw new TypeError("message must be an object");
2526
+ }
2527
+
2528
+ this.#message = { ...this.#message, ...value };
2470
2529
  }
2471
2530
 
2472
- // + --------------------------
2473
- // + Helpers
2474
- // + --------------------------
2475
- help = {
2476
- // supporta sia required nativo, sia data-required="true"
2531
+ // - Helpers
2532
+ #help = {
2533
+ // supporta sia required nativo
2477
2534
  isRequired(field) {
2478
2535
  if (!field) return false;
2479
2536
 
@@ -2516,26 +2573,26 @@ class PGS_formValidate {
2516
2573
  if (input.type === "hidden") return false;
2517
2574
  if (input.type === "checkbox" || input.type === "radio" || input.type === "file") return false;
2518
2575
 
2519
- // valida solo se required (o data-required="true")
2520
- if (!this.help.isRequired(input)) return false;
2576
+ // valida solo se required
2577
+ if (!this.#help.isRequired(input)) return false;
2521
2578
 
2522
- return this.help.isEmptyTextLike(input);
2579
+ return this.#help.isEmptyTextLike(input);
2523
2580
  });
2524
2581
 
2525
2582
  //== TEXTAREA
2526
2583
  // required vuote
2527
2584
  const textareas = Array.from(container.querySelectorAll("textarea")).filter((ta) => {
2528
2585
  if (ta.disabled) return false;
2529
- if (!this.help.isRequired(ta)) return false;
2530
- return this.help.isEmptyTextLike(ta);
2586
+ if (!this.#help.isRequired(ta)) return false;
2587
+ return this.#help.isEmptyTextLike(ta);
2531
2588
  });
2532
2589
 
2533
2590
  //== SELECT
2534
2591
  // required vuoti
2535
2592
  const selects = Array.from(container.querySelectorAll("select")).filter((sel) => {
2536
2593
  if (sel.disabled) return false;
2537
- if (!this.help.isRequired(sel)) return false;
2538
- return this.help.isEmptySelect(sel);
2594
+ if (!this.#help.isRequired(sel)) return false;
2595
+ return this.#help.isEmptySelect(sel);
2539
2596
  });
2540
2597
 
2541
2598
  //== RADIO
@@ -2543,8 +2600,8 @@ class PGS_formValidate {
2543
2600
  const radios = Array.from(container.querySelectorAll('input[type="radio"]')).filter((r) => !r.disabled);
2544
2601
  const requiredRadioGroups = new Map(); // name -> [elements]
2545
2602
  for (const r of radios) {
2546
- if (!this.help.isRequired(r)) continue;
2547
- const name = this.help.getGroupName(r);
2603
+ if (!this.#help.isRequired(r)) continue;
2604
+ const name = this.#help.getGroupName(r);
2548
2605
  if (!name) continue;
2549
2606
  if (!requiredRadioGroups.has(name)) requiredRadioGroups.set(name, []);
2550
2607
  requiredRadioGroups.get(name).push(r);
@@ -2565,9 +2622,9 @@ class PGS_formValidate {
2565
2622
  const requiredCheckboxSingles = [];
2566
2623
  const requiredCheckboxGroups = new Map(); // name -> [elements]
2567
2624
  for (const c of checkboxes) {
2568
- if (!this.help.isRequired(c)) continue;
2625
+ if (!this.#help.isRequired(c)) continue;
2569
2626
 
2570
- const name = this.help.getGroupName(c);
2627
+ const name = this.#help.getGroupName(c);
2571
2628
  if (!name) {
2572
2629
  // checkbox senza name: trattala come singola required
2573
2630
  if (!c.checked) requiredCheckboxSingles.push(c);
@@ -2590,7 +2647,7 @@ class PGS_formValidate {
2590
2647
  // required: se vuoi includerlo
2591
2648
  const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')).filter((f) => {
2592
2649
  if (f.disabled) return false;
2593
- if (!this.help.isRequired(f)) return false;
2650
+ if (!this.#help.isRequired(f)) return false;
2594
2651
  return !(f.files && f.files.length > 0);
2595
2652
  });
2596
2653
 
@@ -2606,12 +2663,37 @@ class PGS_formValidate {
2606
2663
  ruleInvalidFields
2607
2664
  ];
2608
2665
 
2609
- return invalidFields.flat();
2666
+ return [...new Set(invalidFields.flat())];
2667
+ }
2668
+
2669
+ //+ ADD
2670
+ addFieldError(field, i = 0, total = 1) {
2671
+ (0,_pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)(field).option.add("error");
2672
+ if (i === 0) field.scrollIntoView();
2673
+
2674
+ if (i !== 0) return;
2675
+
2676
+ if (total > 1) {
2677
+ _components_notifications_js__WEBPACK_IMPORTED_MODULE_1__.PGS_notification.toast.error(this.message.fieldsError);
2678
+ return;
2679
+ }
2680
+
2681
+ const message = (0,_pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)(field).option.getValueBrackets("message");
2682
+ _components_notifications_js__WEBPACK_IMPORTED_MODULE_1__.PGS_notification.toast.error(message || this.message.fieldError);
2683
+ }
2684
+
2685
+ //+ REMOVE
2686
+ removeFieldError(field) {
2687
+ (0,_pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)(field).option.remove("error");
2688
+ }
2689
+
2690
+ // + SUCCESS
2691
+ success(text = this.message.success) {
2692
+ if (this.#insideValidatedCallback || this.validate() === true) _components_notifications_js__WEBPACK_IMPORTED_MODULE_1__.PGS_notification.toast.success(text)
2610
2693
  }
2611
2694
 
2612
- // + -------------------------
2613
- // + VALIDATE
2614
- // + -------------------------
2695
+
2696
+ // + VALIDATE
2615
2697
  validate() {
2616
2698
  const invalid = this.#inputValue(this.container);
2617
2699
  const allFields = this.container.querySelectorAll("input, textarea, select")
@@ -2622,34 +2704,50 @@ class PGS_formValidate {
2622
2704
 
2623
2705
  //== per radio/checkbox in gruppo:
2624
2706
  // rimuovi l'errore solo sull'elemento che lo ospita (qui: se presente)
2625
- for (const el of allFields) { if (!invalid.includes(el)) this.removeError(el); }
2707
+ for (const el of allFields) { if (!invalid.includes(el)) this.removeFieldError(el); }
2626
2708
 
2627
2709
  //== aggiungo errori dove serve
2628
- invalid.forEach((el, i) => this.addError(el, i))
2710
+ invalid.forEach((el, i) => this.addFieldError(el, i, invalid.length))
2629
2711
 
2630
2712
  //== rimuove l'errore al click
2631
- this.#removeErrorOnClick(allFields)
2713
+ allFields.forEach(element => element.addEventListener("click", e => this.removeFieldError(element)));
2632
2714
 
2633
2715
  //== status form
2634
2716
  if (invalid.length) {
2635
- this.container.setAttribute("data-form-status", "error");
2717
+ (0,_pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)(this.container).option.remove("success").add("error");
2636
2718
  return false;
2637
2719
  } else {
2638
- this.container.setAttribute("data-form-status", "success");
2720
+ (0,_pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)(this.container).option.remove("error").add("success");
2639
2721
  return true;
2640
2722
  }
2641
2723
  }
2642
2724
 
2643
- ifSuccess(text = "Inviato con successo") {
2644
- if (this.validate() == true) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.success(text)
2725
+ // + EVENT VALIDATOR
2726
+ validator(callback, eventName = "submit") {
2727
+ if (typeof callback !== "function") throw new TypeError("callback must be a function");
2728
+ if (typeof eventName !== "string" || !eventName.trim()) throw new TypeError("eventName must be a non-empty string");
2729
+
2730
+ this.container.addEventListener(eventName, event => {
2731
+ event.preventDefault();
2732
+ if (!this.validate()) return;
2733
+
2734
+ this.#insideValidatedCallback = true;
2735
+
2736
+ try {
2737
+ this.success();
2738
+ callback(event);
2739
+ } finally {
2740
+ this.#insideValidatedCallback = false;
2741
+ }
2742
+ });
2743
+
2744
+ return this;
2645
2745
  }
2646
2746
 
2647
- // + -------------------------
2648
- // + ADD RULE
2649
- // + -------------------------
2650
- addNewRule(container) {
2651
- if (typeof container !== "function") throw new Error("Rule must be a function");
2652
- this._rules.push(container);
2747
+ // + ADD RULE
2748
+ addNewRule(rule) {
2749
+ if (typeof rule !== "function") throw new Error("Rule must be a function");
2750
+ this._rules.push(rule);
2653
2751
  return this;
2654
2752
  }
2655
2753
  }
@@ -2668,7 +2766,7 @@ __webpack_require__.r(__webpack_exports__);
2668
2766
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2669
2767
  /* harmony export */ PGS_scrollHorizontal: () => (/* binding */ PGS_scrollHorizontal)
2670
2768
  /* harmony export */ });
2671
- function PGS_scrollHorizontal(querySelector, dataSpeed) {
2769
+ function PGS_scrollHorizontal(element, speed) {
2672
2770
  // Se hai più contenitori, selezionali tutti:
2673
2771
  // Semplice "singleton" per stimare se la sorgente è trackpad
2674
2772
  const TrackpadDetector = (() => {
@@ -2710,10 +2808,7 @@ function PGS_scrollHorizontal(querySelector, dataSpeed) {
2710
2808
 
2711
2809
  //= Scorrimento orizzontale con rotella (evita il trackpad)
2712
2810
 
2713
- let el = querySelector
2714
- el.addEventListener('wheel', (e) => {
2715
- const speed = dataSpeed;
2716
-
2811
+ const onWheel = (e) => {
2717
2812
  //== lascia lo scroll naturale del trackpad
2718
2813
  if (TrackpadDetector.update(e)) return;
2719
2814
 
@@ -2724,11 +2819,11 @@ function PGS_scrollHorizontal(querySelector, dataSpeed) {
2724
2819
  //== Converti delta in px per lo shift orizzontale
2725
2820
  let delta = e.deltaY;
2726
2821
  if (e.deltaMode === 1) delta *= 16;
2727
- else if (e.deltaMode === 2) delta *= el.clientHeight;
2822
+ else if (e.deltaMode === 2) delta *= element.clientHeight;
2728
2823
 
2729
2824
  //== Verifica se il contenitore può ancora scrollare orizzontalmente
2730
- const atStart = el.scrollLeft <= 0;
2731
- const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
2825
+ const atStart = element.scrollLeft <= 0;
2826
+ const atEnd = element.scrollLeft + element.clientWidth >= element.scrollWidth - 1;
2732
2827
  const scrollingRight = delta > 0;
2733
2828
  const scrollingLeft = delta < 0;
2734
2829
  const canScrollHoriz =
@@ -2742,8 +2837,11 @@ function PGS_scrollHorizontal(querySelector, dataSpeed) {
2742
2837
  e.preventDefault();
2743
2838
 
2744
2839
  //== rotella giù => destra
2745
- el.scrollLeft += delta * speed;
2746
- }, { passive: false });
2840
+ element.scrollLeft += delta * speed;
2841
+ };
2842
+
2843
+ element.addEventListener('wheel', onWheel, { passive: false });
2844
+ return () => element.removeEventListener('wheel', onWheel);
2747
2845
  }
2748
2846
 
2749
2847
 
@@ -2765,7 +2863,10 @@ function PGS_header(selectHeader = document) {
2765
2863
 
2766
2864
  const headerElements = pgs(header).querySelectorAll("header-element");
2767
2865
 
2866
+ if (!headerElements.length) console.log('For the header to work correctly, insert "header-element" under "header"');
2768
2867
  if (!headerElements.length) return;
2868
+
2869
+
2769
2870
 
2770
2871
  headerElements.forEach(selectHeader => {
2771
2872