mypgs 1.1.5 → 1.3.3

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 (80) hide show
  1. package/AI_GUIDELINES.md +353 -0
  2. package/README.md +483 -53
  3. package/assets/javascript/_imports.js +26 -0
  4. package/assets/javascript/_pgs.js +53 -2
  5. package/assets/javascript/components/_accordion.js +114 -66
  6. package/assets/javascript/components/_dropdown.js +199 -98
  7. package/assets/javascript/components/_menu.js +33 -69
  8. package/assets/javascript/components/_modals.js +44 -3
  9. package/assets/javascript/components/_notifications.js +162 -0
  10. package/assets/javascript/components/_slides.js +11 -1
  11. package/assets/javascript/components/_stepTabs.js +16 -4
  12. package/assets/javascript/components/_steps.js +32 -6
  13. package/assets/javascript/functions/_formValidate.js +4 -5
  14. package/assets/javascript/index.js +8 -4
  15. package/assets/javascript/patterns/_cookieConsent.js +8 -2
  16. package/assets/javascript/patterns/_header.js +1 -1
  17. package/assets/javascript/pgs.d.ts +17 -2
  18. package/assets/scss/base/_html.scss +23 -1
  19. package/assets/scss/components/_dropdown.scss +24 -88
  20. package/assets/scss/components/_logo.scss +1 -1
  21. package/assets/scss/components/_menu.scss +129 -15
  22. package/assets/scss/components/_modals.scss +15 -3
  23. package/assets/scss/components/_notification.scss +11 -14
  24. package/assets/scss/components/_tooltip.scss +2 -9
  25. package/assets/scss/index.scss +0 -1
  26. package/assets/scss/layout/_gap.scss +7 -1
  27. package/assets/scss/layout/_layout.scss +0 -12
  28. package/assets/scss/layout/_pageShell.scss +102 -108
  29. package/assets/scss/mixin/_mx-form.scss +1 -3
  30. package/assets/scss/mixin/_mx-responsive.scss +2 -2
  31. package/assets/scss/mixin/_mx-semantic.scss +0 -60
  32. package/assets/scss/mixin/mixin.scss +0 -1
  33. package/assets/scss/patterns/_footer.scss +1 -0
  34. package/assets/scss/patterns/_header.scss +20 -18
  35. package/dist/css/index.css +325 -1161
  36. package/dist/css/index.css.map +1 -1
  37. package/dist/css/index.min.css +1 -1
  38. package/dist/index.d.ts +17 -2
  39. package/dist/javascript/index.js +985 -412
  40. package/dist/javascript/index.js.map +1 -1
  41. package/dist/javascript/index.min.js +1 -1
  42. package/package.json +7 -2
  43. package/templates/components/{md-accordion.html → accordion.html} +2 -2
  44. package/templates/components/dropdown.html +91 -0
  45. package/templates/components/menu.html +41 -0
  46. package/templates/components/modal.html +78 -0
  47. package/templates/components/notification.html +35 -0
  48. package/templates/components/{md-slides.html → slides.html} +5 -5
  49. package/templates/components/{md-steps.html → steps.html} +7 -7
  50. package/templates/components/{md-tooltip.html → tooltip.html} +4 -2
  51. package/templates/demo.css +18 -0
  52. package/templates/demo.html +4 -5
  53. package/templates/demo.js +53 -52
  54. package/templates/layout/flex.html +89 -0
  55. package/templates/layout/grid.html +89 -0
  56. package/templates/layout/pageShell.html +59 -0
  57. package/templates/layout/section.html +40 -0
  58. package/templates/{layout/md-footer.html → patterns/footer.html} +1 -0
  59. package/templates/{layout/md-header.html → patterns/header.html} +6 -9
  60. package/assets/javascript/components/_exeNotifications.js +0 -85
  61. package/assets/javascript/functions/_notifications.js +0 -74
  62. package/assets/javascript/functions/_sendForm.js +0 -100
  63. package/assets/scss/base/_reset.scss +0 -15
  64. package/assets/scss/mixin/_mx-menu.scss +0 -154
  65. package/templates/components/md-dropdown.html +0 -16
  66. package/templates/components/md-menu.html +0 -40
  67. package/templates/components/md-modal.html +0 -19
  68. package/templates/components/md-notification.html +0 -13
  69. package/templates/layout/md-pageShell.html +0 -22
  70. package/templates/layout/md-section.html +0 -25
  71. /package/templates/components/{md-breadcumbs.html → breadcumbs.html} +0 -0
  72. /package/templates/components/{md-button.html → button.html} +0 -0
  73. /package/templates/components/{md-card.html → card.html} +0 -0
  74. /package/templates/components/{md-form.html → form.html} +0 -0
  75. /package/templates/components/{md-logo.html → logo.html} +0 -0
  76. /package/templates/components/{md-searchbar.html → searchbar.html} +0 -0
  77. /package/templates/components/{md-stepTabs.html → stepTabs.html} +0 -0
  78. /package/templates/components/{md-table.html → table.html} +0 -0
  79. /package/templates/layout/{md-body.html → body.html} +0 -0
  80. /package/templates/{layout/md-cookieConsent.html → patterns/cookieConsent.html} +0 -0
@@ -1,6 +1,68 @@
1
1
  /******/ (() => { // webpackBootstrap
2
2
  /******/ var __webpack_modules__ = ({
3
3
 
4
+ /***/ "./assets/javascript/_imports.js"
5
+ /*!***************************************!*\
6
+ !*** ./assets/javascript/_imports.js ***!
7
+ \***************************************/
8
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9
+
10
+ "use strict";
11
+ __webpack_require__.r(__webpack_exports__);
12
+ /* harmony import */ var _pgs_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_pgs.js */ "./assets/javascript/_pgs.js");
13
+ /* harmony import */ var _components_accordion_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/_accordion.js */ "./assets/javascript/components/_accordion.js");
14
+ /* harmony import */ var _components_dropdown_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/_dropdown.js */ "./assets/javascript/components/_dropdown.js");
15
+ /* harmony import */ var _components_menu_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/_menu.js */ "./assets/javascript/components/_menu.js");
16
+ /* harmony import */ var _components_modals_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/_modals.js */ "./assets/javascript/components/_modals.js");
17
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/_notifications.js */ "./assets/javascript/components/_notifications.js");
18
+ /* harmony import */ var _components_slides_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/_slides.js */ "./assets/javascript/components/_slides.js");
19
+ /* harmony import */ var _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/_stepTabs.js */ "./assets/javascript/components/_stepTabs.js");
20
+ /* harmony import */ var _components_steps_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./components/_steps.js */ "./assets/javascript/components/_steps.js");
21
+ /* harmony import */ var _functions_formValidate_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./functions/_formValidate.js */ "./assets/javascript/functions/_formValidate.js");
22
+ /* harmony import */ var _functions_scrollY_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./functions/_scrollY.js */ "./assets/javascript/functions/_scrollY.js");
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+ _pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs.registerModules({
37
+ accordion: _components_accordion_js__WEBPACK_IMPORTED_MODULE_1__.PGS_accordion,
38
+ dropdown: _components_dropdown_js__WEBPACK_IMPORTED_MODULE_2__.PGS_dropdown,
39
+ menu: _components_menu_js__WEBPACK_IMPORTED_MODULE_3__.PGS_menu,
40
+ modal: _components_modals_js__WEBPACK_IMPORTED_MODULE_4__.PGS_modal,
41
+ notification: _components_notifications_js__WEBPACK_IMPORTED_MODULE_5__.PGS_notification,
42
+ slides: _components_slides_js__WEBPACK_IMPORTED_MODULE_6__.PGS_slides,
43
+ stepTabs: _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_7__.PGS_stepTabs,
44
+ steps: _components_steps_js__WEBPACK_IMPORTED_MODULE_8__.PGS_steps,
45
+ formValidate: _functions_formValidate_js__WEBPACK_IMPORTED_MODULE_9__.PGS_formValidate,
46
+ scrollHorizontal: _functions_scrollY_js__WEBPACK_IMPORTED_MODULE_10__.PGS_scrollHorizontal,
47
+ });
48
+
49
+ // pgs.registerImport({
50
+ // PGS_accordion,
51
+ // PGS_dropdown,
52
+ // PGS_menu,
53
+ // PGS_modal,
54
+ // PGS_notification,
55
+ // PGS_slides,
56
+ // PGS_stepTabs,
57
+ // PGS_steps,
58
+ // PGS_formValidate,
59
+ // PGS_scrollHorizontal,
60
+ // });
61
+
62
+
63
+
64
+ /***/ },
65
+
4
66
  /***/ "./assets/javascript/_pgs.js"
5
67
  /*!***********************************!*\
6
68
  !*** ./assets/javascript/_pgs.js ***!
@@ -234,13 +296,64 @@ function pgs(root) {
234
296
  const api = createBasePgs();
235
297
  api.state = createState("pgs-state");
236
298
  api.option = createOption("pgs-option");
237
- api.modules = createOption("pgs-modules");
238
299
  return api;
239
300
  }
240
301
 
241
- globalThis.pgs ??= pgs;
302
+ const PGS_IMPORTS = {};
303
+
304
+ function registerImportModule(name, module) {
305
+ const key = String(name || "").trim().replace(/^pgs[_-\s]*/i, "").toLowerCase();
306
+
307
+ if (!key) throw new TypeError("pgs.registerImport(...modules): ogni modulo deve avere name o PGS_name");
308
+
309
+ PGS_IMPORTS[key] = {
310
+ name,
311
+ module
312
+ };
313
+ }
314
+
315
+ pgs.registerImport = function (...modules) {
316
+ modules.flat().forEach(item => {
317
+ if (item && typeof item === "object" && !item.PGS_name && !item.name) {
318
+ Object.entries(item).forEach(([name, module]) => registerImportModule(name, module));
319
+ return;
320
+ }
321
+
322
+ registerImportModule(item?.PGS_name || item?.name, item);
323
+ });
242
324
 
325
+ return pgs;
326
+ };
327
+
328
+ pgs.registerModules = function (modules = {}) {
329
+ Object.entries(modules).forEach(([name, module]) => {
330
+ const key = String(name || "").trim();
331
+ if (!key) return;
332
+
333
+ const hasOwn = Object.prototype.hasOwnProperty.call(pgs, key);
334
+ if (hasOwn && pgs[key] !== module) {
335
+ throw new Error(`pgs.registerModules(): "${key}" e' gia' definito su pgs`);
336
+ }
337
+
338
+ pgs[key] = module;
339
+ });
243
340
 
341
+ return pgs;
342
+ };
343
+
344
+ pgs.import = function (...names) {
345
+ return names.flat().reduce((imports, name) => {
346
+ const key = String(name || "").trim().replace(/^pgs[_-\s]*/i, "").toLowerCase();
347
+ const item = PGS_IMPORTS[key];
348
+
349
+ if (!item) throw new Error(`pgs.import(): modulo "${name}" non registrato`);
350
+
351
+ imports[item.name] = item.module;
352
+ return imports;
353
+ }, {});
354
+ };
355
+
356
+ globalThis.pgs ??= pgs;
244
357
 
245
358
 
246
359
  /***/ },
@@ -432,85 +545,140 @@ document.addEventListener('DOMContentLoaded', () => {
432
545
  /*!****************************************************!*\
433
546
  !*** ./assets/javascript/components/_accordion.js ***!
434
547
  \****************************************************/
435
- () {
436
-
437
- //= ACCORDION
438
- const allAccordion = pgs(document).querySelectorAll("accordion")
548
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
439
549
 
440
- allAccordion.forEach((accordion, index) => {
550
+ "use strict";
551
+ __webpack_require__.r(__webpack_exports__);
552
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
553
+ /* harmony export */ PGS_accordion: () => (/* binding */ PGS_accordion),
554
+ /* harmony export */ PGS_accordion_api: () => (/* binding */ PGS_accordion_api),
555
+ /* harmony export */ PGS_accordion_init: () => (/* binding */ PGS_accordion_init)
556
+ /* harmony export */ });
557
+ //= ACCORDION
558
+ const API = new WeakMap();
559
+ let accordionId = 0;
441
560
 
442
- const BUTTON = pgs(accordion).querySelector("accordion-button");
443
- const CONTENT = pgs(accordion).querySelector("accordion-content");
561
+ function nextAccordionId() {
562
+ accordionId += 1;
563
+ return accordionId;
564
+ }
444
565
 
445
- //== ID univoci per aria-controls / aria-labelledby
446
- const ID = index + 1;
447
- const btnId = `acc-btn-${ID}`;
448
- const panelId = `acc-panel-${ID}`;
566
+ function directPgsChild(element, token) {
567
+ return Array.from(element.children).find(child => pgs(child).contains(token));
568
+ }
449
569
 
450
- //== Stato iniziale
451
- const isOpenInit = pgs(accordion).state.contains("open");
570
+ function PGS_accordion_init(root = document) {
571
+ pgs(root).querySelectorAll("accordion").forEach((accordion) => {
572
+ if (API.has(accordion)) return;
452
573
 
453
- //== Accessibilità (setup una volta)
454
- BUTTON.setAttribute("role", "button");
455
- BUTTON.setAttribute("tabindex", "0");
456
- BUTTON.setAttribute("id", btnId);
457
- BUTTON.setAttribute("aria-controls", panelId);
574
+ const BUTTON = directPgsChild(accordion, "accordion-button");
575
+ const CONTENT = directPgsChild(accordion, "accordion-content");
576
+ if (!BUTTON || !CONTENT) return;
458
577
 
459
- CONTENT.setAttribute("id", panelId);
460
- CONTENT.setAttribute("role", "region");
461
- CONTENT.setAttribute("aria-labelledby", btnId);
578
+ //== ID univoci per aria-controls / aria-labelledby
579
+ const ID = nextAccordionId();
580
+ const btnId = `acc-btn-${ID}`;
581
+ const panelId = `acc-panel-${ID}`;
462
582
 
463
- //+ Accessibility (applica stato aperto/chiuso)
464
- function accordionAccessibility(isOpen, button, content) {
465
- const text = (button?.textContent || "").trim().replace(/\s+/g, " ");
466
- button.setAttribute("aria-label", `${isOpen ? "Chiudi" : "Apri"} ${text || "sezione"}`);
467
- button.setAttribute("aria-expanded", String(isOpen));
468
- content.hidden = !isOpen;
469
- }
583
+ //== Stato iniziale
584
+ const isOpenInit = pgs(accordion).state.contains("open");
470
585
 
471
- //+ Chiudi tutti gli altri
472
- function closeOltherAccordion() {
473
- for (const otherLi of allAccordion) {
474
- if (otherLi === accordion) continue;
586
+ //== Accessibilità (setup una volta)
587
+ BUTTON.setAttribute("role", "button");
588
+ BUTTON.setAttribute("tabindex", "0");
589
+ if (!BUTTON.id) BUTTON.setAttribute("id", btnId);
475
590
 
476
- const otherBtn = pgs(otherLi).querySelector("accordion-button");
477
- const otherContent = pgs(otherLi).querySelector("accordion-content");
478
- if (!otherBtn || !otherContent) continue;
591
+ if (!CONTENT.id) CONTENT.setAttribute("id", panelId);
592
+ BUTTON.setAttribute("aria-controls", CONTENT.id);
593
+ CONTENT.setAttribute("role", "region");
594
+ CONTENT.setAttribute("aria-labelledby", BUTTON.id);
479
595
 
480
- pgs(otherLi).state().remove("open");
481
- accordionAccessibility(false, otherBtn, otherContent);
596
+ //+ Accessibility (applica stato aperto/chiuso)
597
+ function accordionAccessibility(isOpen, button, content) {
598
+ const text = (button?.textContent || "").trim().replace(/\s+/g, " ");
599
+ button.setAttribute("aria-label", `${isOpen ? "Chiudi" : "Apri"} ${text || "sezione"}`);
600
+ button.setAttribute("aria-expanded", String(isOpen));
601
+ content.hidden = !isOpen;
482
602
  }
483
- }
484
603
 
485
- //+ FN ACCORDION
486
- function accordionFunction() {
487
- const isOpen = pgs(accordion).state.contains("open");
488
- const nowOpen = !isOpen;
604
+ //+ Chiudi tutti gli altri
605
+ function closeOltherAccordion() {
606
+ for (const otherLi of pgs(document).querySelectorAll("accordion")) {
607
+ if (otherLi === accordion) continue;
489
608
 
490
- pgs(accordion).state.toggle("open", nowOpen);
491
- accordionAccessibility(nowOpen, BUTTON, CONTENT);
609
+ const otherBtn = pgs(otherLi).querySelector("accordion-button");
610
+ const otherContent = pgs(otherLi).querySelector("accordion-content");
611
+ if (!otherBtn || !otherContent) continue;
492
612
 
493
- closeOltherAccordion();
613
+ pgs(otherLi).state().remove("open");
614
+ accordionAccessibility(false, otherBtn, otherContent);
615
+ }
616
+ }
494
617
 
495
- //== scroll to view
496
- if (nowOpen) setTimeout(() => accordion.scrollIntoView({ block: "nearest", inline: "nearest" }), 100);
497
- }
618
+ //+ FN ACCORDION
619
+ function accordionFunction() {
620
+ const isOpen = pgs(accordion).state.contains("open");
621
+ const nowOpen = !isOpen;
498
622
 
499
- // applica stato iniziale
500
- accordionAccessibility(isOpenInit, BUTTON, CONTENT);
623
+ pgs(accordion).state.toggle("open", nowOpen);
624
+ accordionAccessibility(nowOpen, BUTTON, CONTENT);
501
625
 
502
- //- Eventi
503
- BUTTON.addEventListener("click", accordionFunction);
626
+ closeOltherAccordion();
504
627
 
505
- //- Tastiera: Enter / Space
506
- BUTTON.addEventListener("keydown", (e) => {
507
- if (e.key === "Enter" || e.key === " ") {
508
- e.preventDefault();
509
- accordionFunction();
628
+ //== scroll to view
629
+ if (nowOpen) setTimeout(() => accordion.scrollIntoView({ block: "nearest", inline: "nearest" }), 100);
630
+ }
631
+
632
+ function open() {
633
+ if (!pgs(accordion).state.contains("open")) accordionFunction();
634
+ }
635
+
636
+ function close() {
637
+ if (pgs(accordion).state.contains("open")) accordionFunction();
510
638
  }
639
+
640
+ // applica stato iniziale
641
+ accordionAccessibility(isOpenInit, BUTTON, CONTENT);
642
+
643
+ //- Eventi
644
+ BUTTON.addEventListener("click", accordionFunction);
645
+
646
+ //- Tastiera: Enter / Space
647
+ BUTTON.addEventListener("keydown", (e) => {
648
+ if (e.key === "Enter" || e.key === " ") {
649
+ e.preventDefault();
650
+ accordionFunction();
651
+ }
652
+ });
653
+
654
+ API.set(accordion, {
655
+ element: accordion,
656
+ button: BUTTON,
657
+ content: CONTENT,
658
+ open,
659
+ close,
660
+ toggle: accordionFunction,
661
+ refresh: () => {
662
+ PGS_accordion_init(accordion.parentNode || document);
663
+ return API.get(accordion);
664
+ },
665
+ isOpen: () => pgs(accordion).state.contains("open"),
666
+ });
511
667
  });
668
+ }
512
669
 
513
- });
670
+ //# INIT
671
+ PGS_accordion_init();
672
+
673
+ //# API
674
+ function PGS_accordion_api(selector) {
675
+ return API.get(selector);
676
+ }
677
+
678
+ const PGS_accordion = {
679
+ init: PGS_accordion_init,
680
+ api: PGS_accordion_api
681
+ };
514
682
 
515
683
 
516
684
  /***/ },
@@ -524,218 +692,218 @@ allAccordion.forEach((accordion, index) => {
524
692
  "use strict";
525
693
  __webpack_require__.r(__webpack_exports__);
526
694
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
527
- /* harmony export */ pgs_dropdown: () => (/* binding */ pgs_dropdown)
695
+ /* harmony export */ PGS_dropdown: () => (/* binding */ PGS_dropdown)
528
696
  /* harmony export */ });
529
- // + dropdown (Popover API)
530
- function pgs_dropdown() {
531
- pgs(document).querySelectorAll("dropdown").forEach((DROPDOWN, index) => {
532
- const BUTTON = pgs(DROPDOWN).querySelector("dropdown-button");
533
- const CONTENT = pgs(DROPDOWN).querySelector("dropdown-content");
534
-
535
- if (!BUTTON || !CONTENT) return;
536
-
537
- // = INIT
538
- if (DROPDOWN.getAttribute("data-initialize") === "true") return;
539
- DROPDOWN.setAttribute("data-initialize", "true");
697
+ // + dropdown
698
+ const API = new WeakMap();
699
+ const OPEN_DROPDOWNS = new Set();
700
+ const VIEWPORT_GAP = 8;
701
+ let dropdownId = 0;
540
702
 
541
- // == CSS dropdown-anchor
542
- const ANCHOR_NAME = `--dropdown-anchor-${index}`;
543
- DROPDOWN.style.setProperty("--dropdown-anchor", ANCHOR_NAME);
703
+ function nextDropdownId() {
704
+ dropdownId += 1;
705
+ return dropdownId;
706
+ }
544
707
 
545
- // == IDs + ACCESSIBILITY
546
- if (!BUTTON.id) BUTTON.id = `dropdown-btn-${index}`;
547
- if (!CONTENT.id) CONTENT.id = `dropdown-panel-${index}`;
548
- BUTTON.setAttribute("type", "button");
549
- BUTTON.setAttribute("aria-haspopup", "true");
550
- BUTTON.setAttribute("aria-controls", CONTENT.id);
551
- BUTTON.setAttribute("aria-expanded", "false");
552
- CONTENT.setAttribute("aria-labelledby", BUTTON.id);
708
+ function isDropdownContent(element) {
709
+ return element instanceof Element && pgs(element).contains("dropdown-content");
710
+ }
553
711
 
554
- // == POPVER SETUP
555
- if (!CONTENT.hasAttribute("popover")) CONTENT.setAttribute("popover", "auto");
556
- BUTTON.setAttribute("popovertarget", CONTENT.id);
557
- BUTTON.setAttribute("popovertargetaction", "toggle");
558
-
559
- //-( Safari / legacy fallback: popover is in the top layer, so fixed coords are viewport-based.
560
- const HAS_ANCHOR_POSITIONING =
561
- CSS.supports("anchor-name: --dropdown-anchor") &&
562
- CSS.supports("position-anchor: --dropdown-anchor") &&
563
- CSS.supports("position-area: bottom") &&
564
- CSS.supports("top: anchor(bottom)");
565
- const USE_FALLBACK_POSITIONING = pgs(DROPDOWN).contains("tooltip") || !HAS_ANCHOR_POSITIONING;
566
-
567
- const updatePopoverPosition = () => {
568
- if (!USE_FALLBACK_POSITIONING) return;
569
-
570
- const buttonRect = BUTTON.getBoundingClientRect();
571
- const style = getComputedStyle(DROPDOWN);
572
- const offset = parseFloat(style.getPropertyValue("--dropdown-offset")) || 10;
573
- const padding = parseFloat(style.getPropertyValue("--dropdown-padding")) || 0;
574
- const arrowSize = parseFloat(style.getPropertyValue("--dropdown-arrow-size")) || 12;
575
- const viewportGap = 8;
576
- const viewportWidth = window.innerWidth;
577
- const maxWidth = viewportWidth - viewportGap * 2;
578
- const contentStyle = getComputedStyle(CONTENT);
579
- const cssMaxWidth = parseFloat(contentStyle.maxWidth);
580
- const dropdownMaxWidth = Number.isFinite(cssMaxWidth) ? Math.min(cssMaxWidth, maxWidth) : maxWidth;
581
- const contentWidth = Math.min(
582
- Math.max(CONTENT.scrollWidth + padding * 2, buttonRect.width),
583
- dropdownMaxWidth
584
- );
585
- const top = buttonRect.bottom + offset;
586
- const centeredLeft = buttonRect.left + buttonRect.width / 2 - contentWidth / 2;
587
- const left = Math.min(
588
- Math.max(centeredLeft, viewportGap),
589
- viewportWidth - contentWidth - viewportGap
590
- );
591
- const buttonCenter = buttonRect.left + buttonRect.width / 2;
592
- const arrowLeft = Math.min(
593
- Math.max(buttonCenter - left, padding + arrowSize),
594
- contentWidth - padding - arrowSize
595
- );
712
+ function getDropdownTrigger(dropdown, content) {
713
+ const children = Array.from(dropdown.children).filter(child => child !== content);
714
+ const dropdownButton = children.find(child => pgs(child).contains("dropdown-button"));
596
715
 
597
- DROPDOWN.style.setProperty("--dropdown-fallback-top", `${top}px`);
598
- DROPDOWN.style.setProperty("--dropdown-fallback-left", `${left}px`);
599
- DROPDOWN.style.setProperty("--dropdown-arrow-left", `${arrowLeft}px`);
600
- };
716
+ return dropdownButton || children.find(child => !isDropdownContent(child)) || dropdown;
717
+ }
601
718
 
602
- BUTTON.addEventListener("click", e => {
603
- if (!USE_FALLBACK_POSITIONING) return;
719
+ function getDropdownContent(dropdown) {
720
+ return Array.from(dropdown.children).find(isDropdownContent) || pgs(dropdown).querySelector("dropdown-content");
721
+ }
604
722
 
605
- e.preventDefault();
606
- if (CONTENT.matches(":popover-open")) {
607
- CONTENT.hidePopover();
608
- return;
609
- }
723
+ function getDropdowns(root) {
724
+ const dropdowns = root instanceof Element && pgs(root).contains("dropdown") ? [root] : [];
725
+ dropdowns.push(...pgs(root).querySelectorAll("dropdown"));
726
+ return dropdowns;
727
+ }
610
728
 
611
- updatePopoverPosition();
612
- CONTENT.showPopover();
613
- });
729
+ function getposition(dropdown) {
730
+ const option = pgs(dropdown).option;
731
+ const optionValue = option.getValueBrackets("position");
732
+ const raw = (optionValue || "bottom center").trim().toLowerCase();
733
+ const parts = raw.split(/\s+/).filter(Boolean);
734
+ const side = parts.find(part => ["top", "right", "bottom", "left"].includes(part)) || "bottom";
735
+ const align = parts.find(part => ["top", "right", "bottom", "left", "center"].includes(part) && part !== side) || "center";
614
736
 
615
- // == sync ARIA + data-open quando apre/chiude
616
- CONTENT.addEventListener("toggle", e => {
617
- const open = CONTENT.matches(":popover-open");
618
- BUTTON.setAttribute("aria-expanded", open ? "true" : "false");
619
- pgs(DROPDOWN).state.toggle("open", open);
620
- if (open) {
621
- updatePopoverPosition();
622
- CONTENT.querySelector('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])')?.focus();
623
- }
624
- });
737
+ return { side, align };
738
+ }
625
739
 
626
- window.addEventListener("resize", () => {
627
- if (CONTENT.matches(":popover-open")) updatePopoverPosition();
628
- });
629
- window.addEventListener("scroll", () => {
630
- if (CONTENT.matches(":popover-open")) updatePopoverPosition();
631
- }, true);
632
- });
740
+ function clamp(value, min, max) {
741
+ return Math.min(Math.max(value, min), max);
633
742
  }
634
743
 
635
- // # INIT
636
- pgs_dropdown();
744
+ function updateposition(dropdown) {
745
+ const data = API.get(dropdown);
746
+ if (!data || !data.isOpen()) return;
747
+
748
+ const { trigger, content } = data;
749
+ const { side, align } = getposition(dropdown);
750
+ const triggerRect = trigger.getBoundingClientRect();
751
+ const contentRect = content.getBoundingClientRect();
752
+ const viewportWidth = document.documentElement.clientWidth;
753
+ const maxLeft = Math.max(VIEWPORT_GAP, viewportWidth - contentRect.width - VIEWPORT_GAP);
754
+ let left = triggerRect.left + (triggerRect.width - contentRect.width) / 2;
755
+ let top = triggerRect.bottom + VIEWPORT_GAP;
756
+
757
+ if (side === "top" || side === "bottom") {
758
+ top = side === "top"
759
+ ? triggerRect.top - contentRect.height - VIEWPORT_GAP
760
+ : triggerRect.bottom + VIEWPORT_GAP;
761
+
762
+ if (align === "left") left = triggerRect.left;
763
+ if (align === "right") left = triggerRect.right - contentRect.width;
764
+ }
637
765
 
766
+ if (side === "left" || side === "right") {
767
+ left = side === "left"
768
+ ? triggerRect.left - contentRect.width - VIEWPORT_GAP
769
+ : triggerRect.right + VIEWPORT_GAP;
770
+ top = triggerRect.top + (triggerRect.height - contentRect.height) / 2;
638
771
 
639
- /***/ },
772
+ if (align === "top") top = triggerRect.top;
773
+ if (align === "bottom") top = triggerRect.bottom - contentRect.height;
774
+ }
640
775
 
641
- /***/ "./assets/javascript/components/_exeNotifications.js"
642
- /*!***********************************************************!*\
643
- !*** ./assets/javascript/components/_exeNotifications.js ***!
644
- \***********************************************************/
645
- (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
776
+ if (side === "left" && left < VIEWPORT_GAP) {
777
+ left = triggerRect.right + VIEWPORT_GAP;
778
+ }
646
779
 
647
- "use strict";
648
- __webpack_require__.r(__webpack_exports__);
649
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
650
- /* harmony export */ PGS_md_notification: () => (/* binding */ PGS_md_notification)
651
- /* harmony export */ });
652
- /* harmony import */ var _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../functions/_notifications.js */ "./assets/javascript/functions/_notifications.js");
780
+ if (side === "right" && left + contentRect.width > viewportWidth - VIEWPORT_GAP) {
781
+ left = triggerRect.left - contentRect.width - VIEWPORT_GAP;
782
+ }
653
783
 
784
+ left = clamp(left, VIEWPORT_GAP, maxLeft);
785
+
786
+ content.style.setProperty("--dropdown-left", `${Math.round(left)}px`);
787
+ content.style.setProperty("--dropdown-top", `${Math.round(top)}px`);
788
+ }
654
789
 
655
- function escapeHtml(value) {
656
- return String(value ?? "");
790
+ function updateOpenDropdowns() {
791
+ OPEN_DROPDOWNS.forEach(updateposition);
657
792
  }
658
793
 
659
- function getDuration(notification) {
660
- const rawDuration = notification.duration;
661
- const duration = Number.parseInt(rawDuration, 10);
794
+ function closeDropdown(dropdown) {
795
+ const data = API.get(dropdown);
796
+ if (!data || !data.isOpen()) return;
662
797
 
663
- return Number.isNaN(duration) ? 5000 : duration;
798
+ pgs(dropdown).state.remove("open");
799
+ data.trigger.setAttribute("aria-expanded", "false");
800
+ OPEN_DROPDOWNS.delete(dropdown);
664
801
  }
665
802
 
666
- function getNotificationApi(notification) {
667
- const element = String(notification.element || "notification").trim();
803
+ function openDropdown(dropdown) {
804
+ const data = API.get(dropdown);
805
+ if (!data || data.isOpen()) return;
668
806
 
669
- return element === "toast" ? _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_toast : _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification;
807
+ OPEN_DROPDOWNS.forEach(item => {
808
+ if (item !== dropdown) closeDropdown(item);
809
+ });
810
+
811
+ pgs(dropdown).state.add("open");
812
+ data.trigger.setAttribute("aria-expanded", "true");
813
+ OPEN_DROPDOWNS.add(dropdown);
814
+ updateposition(dropdown);
670
815
  }
671
816
 
672
- function getNotificationType(notification, api) {
673
- const type = String(notification.type || "info").trim();
817
+ function toggleDropdown(dropdown) {
818
+ const data = API.get(dropdown);
819
+ if (!data) return;
674
820
 
675
- return typeof api[type] === "function" ? type : "info";
821
+ if (data.isOpen()) closeDropdown(dropdown);
822
+ else openDropdown(dropdown);
676
823
  }
677
824
 
678
- function getNotificationData(root) {
679
- try {
680
- return JSON.parse(root.dataset.notification || "{}");
681
- } catch (error) {
682
- console.warn("PGS notification: dati non validi", error);
683
- return {};
684
- }
825
+ function isInsideAnyDropdown(target) {
826
+ return Array.from(OPEN_DROPDOWNS).some(dropdown => dropdown.contains(target));
685
827
  }
686
828
 
687
- function getNotificationContent(title, content) {
688
- const safeContent = escapeHtml(content);
689
- const safeTitle = escapeHtml(title);
829
+ function PGS_dropdown_init(root = document) {
830
+ getDropdowns(root).forEach((DROPDOWN) => {
831
+ if (API.has(DROPDOWN)) return;
690
832
 
691
- if (!safeTitle) return safeContent;
692
- if (!safeContent) return `<span pgs="notification-element-title">${safeTitle}</span>`;
833
+ const CONTENT = getDropdownContent(DROPDOWN);
834
+ if (!CONTENT) return;
693
835
 
694
- return `
695
- <span pgs="notification-element-title">${safeTitle}</span>
696
- <br>
697
- <span pgs="notification-element-content">${safeContent}</span>
698
- `;
699
- }
836
+ const TRIGGER = getDropdownTrigger(DROPDOWN, CONTENT);
837
+ const id = nextDropdownId();
700
838
 
701
- function PGS_md_notification(root) {
702
- if (!root || root.dataset.initialize === "true") return;
703
- root.dataset.initialize = "true";
839
+ if (!TRIGGER.id) TRIGGER.id = `dropdown-btn-${id}`;
840
+ if (!CONTENT.id) CONTENT.id = `dropdown-panel-${id}`;
704
841
 
705
- const notification = getNotificationData(root);
706
- const title = String(notification.title || "").trim();
707
- const content = String(notification.message || "").trim();
708
- if (!title && !content) {
709
- root.remove();
710
- return;
711
- }
842
+ if (TRIGGER.matches("button") && !TRIGGER.hasAttribute("type")) {
843
+ TRIGGER.setAttribute("type", "button");
844
+ }
845
+
846
+ TRIGGER.setAttribute("aria-haspopup", "true");
847
+ TRIGGER.setAttribute("aria-controls", CONTENT.id);
848
+ TRIGGER.setAttribute("aria-expanded", String(pgs(DROPDOWN).state.contains("open")));
849
+ CONTENT.setAttribute("aria-labelledby", TRIGGER.id);
850
+
851
+ const data = {
852
+ element: DROPDOWN,
853
+ trigger: TRIGGER,
854
+ content: CONTENT,
855
+ open: () => openDropdown(DROPDOWN),
856
+ close: () => closeDropdown(DROPDOWN),
857
+ toggle: () => toggleDropdown(DROPDOWN),
858
+ refresh: () => {
859
+ PGS_dropdown_init(DROPDOWN.parentNode || document);
860
+ updateposition(DROPDOWN);
861
+ return API.get(DROPDOWN);
862
+ },
863
+ isOpen: () => pgs(DROPDOWN).state.contains("open")
864
+ };
712
865
 
713
- const link = notification.link || null;
714
- const icon = notification.icon || undefined;
715
- const duration = getDuration(notification);
716
- const api = getNotificationApi(notification);
717
- const type = getNotificationType(notification, api);
718
- const formattedContent = getNotificationContent(title, content);
866
+ TRIGGER.addEventListener("click", (event) => {
867
+ if (isDropdownContent(event.target)) return;
868
+ event.preventDefault();
869
+ event.stopPropagation();
870
+ toggleDropdown(DROPDOWN);
871
+ });
719
872
 
720
- if (api === _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_toast) {
721
- api[type](formattedContent, duration, icon);
722
- } else {
723
- api[type](formattedContent, link, duration, icon);
724
- }
873
+ CONTENT.addEventListener("click", event => event.stopPropagation());
874
+ API.set(DROPDOWN, data);
725
875
 
726
- root.remove();
876
+ if (data.isOpen()) OPEN_DROPDOWNS.add(DROPDOWN);
877
+ updateposition(DROPDOWN);
878
+ });
727
879
  }
728
880
 
729
- function initMdNotifications() {
730
- pgs(document).querySelectorAll("notificationTrigger").forEach(PGS_md_notification);
731
- }
881
+ document.addEventListener("click", (event) => {
882
+ if (isInsideAnyDropdown(event.target)) return;
883
+ OPEN_DROPDOWNS.forEach(closeDropdown);
884
+ });
732
885
 
733
- if (document.readyState === "loading") {
734
- document.addEventListener("DOMContentLoaded", initMdNotifications);
735
- } else {
736
- initMdNotifications();
886
+ document.addEventListener("keydown", (event) => {
887
+ if (event.key !== "Escape") return;
888
+ OPEN_DROPDOWNS.forEach(closeDropdown);
889
+ });
890
+
891
+ window.addEventListener("resize", updateOpenDropdowns);
892
+ window.addEventListener("scroll", updateOpenDropdowns, true);
893
+
894
+ // # INIT
895
+ PGS_dropdown_init();
896
+
897
+ // # API
898
+ function PGS_dropdown_api(selector) {
899
+ return API.get(selector);
737
900
  }
738
901
 
902
+ const PGS_dropdown = {
903
+ init: PGS_dropdown_init,
904
+ api: PGS_dropdown_api
905
+ };
906
+
739
907
 
740
908
  /***/ },
741
909
 
@@ -753,96 +921,61 @@ __webpack_require__.r(__webpack_exports__);
753
921
  /* harmony import */ var _dropdown__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_dropdown */ "./assets/javascript/components/_dropdown.js");
754
922
 
755
923
 
924
+ const API = new WeakMap();
925
+
756
926
  //= DROP DOWN MENU
757
- function PGS_menu() {
927
+ function PGS_menu_init(root = document) {
758
928
 
759
- pgs(document).querySelectorAll('menu-horizontal').forEach(MENU => {
929
+ pgs(root).querySelectorAll('menu').forEach(MENU => {
930
+ if (API.has(MENU)) return;
931
+
932
+ MENU.querySelectorAll('li').forEach(li => {
933
+ const ul = li.querySelector("ul");
760
934
 
761
- MENU.querySelectorAll('nav > ul > li.menu-item-has-children').forEach(li => {
762
- if (li.querySelector("ul")) {
763
- const ul = li.querySelector("ul");
935
+ if (ul) {
764
936
 
765
937
  const button = document.createElement("button");
766
- button.className = "icon-down";
767
938
  button.type = "button";
768
939
  button.innerHTML = "<span>&#9207;</span>";
940
+ pgs(button).add("menu-buttonIcon");
769
941
  li.querySelector("a").insertAdjacentElement("afterend", button);
770
942
 
771
943
  pgs(li).add("dropdown")
772
944
  pgs(button).add("dropdown-button")
773
945
  pgs(button).add("buttonNohover")
774
946
  pgs(ul).add("dropdown-content")
775
- pgs(ul).add("menu-vertical")
947
+
776
948
  }
777
949
  });
778
- });
779
-
780
- pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
781
-
782
- MENU.querySelectorAll('.menu-item-has-children').forEach((li, index) => {
783
- const ul = li.querySelector("ul");
784
950
 
785
- if (!ul) return
786
-
787
- const button = document.createElement("button");
788
- button.className = "icon-down buttonIcon";
789
- button.type = "button";
790
-
791
- // ID unico per aria-controls
792
- const submenuId = `vertical-submenu-${index}`;
793
- ul.id = submenuId;
794
-
795
- // Stato iniziale
796
- pgs(button).add("buttonIcon")
797
- button.setAttribute("aria-expanded", "false");
798
- button.setAttribute("aria-controls", submenuId);
799
- button.setAttribute("aria-label", "Apri sottomenu");
800
- button.innerHTML = "<span aria-hidden='true'>&#9207;</span>";
801
- li.querySelector("a").insertAdjacentElement("afterend", button);
802
-
803
- function toggleMenu() {
804
- // const isOpena = ul.classList.toggle("open");
805
- const isOpen = pgs(ul).state.toggle("open");
806
- button.setAttribute("aria-expanded", isOpen);
807
- button.setAttribute("aria-label", isOpen ? "Chiudi sottomenu" : "Apri sottomenu");
808
- };
809
-
810
- // Click
811
- button.addEventListener("click", toggleMenu);
812
- button.addEventListener("keydown", (e) => {
813
- if (e.key === "Enter" || e.key === " ") {
814
- e.preventDefault();
815
- toggleMenu();
816
- }
817
- });
951
+ API.set(MENU, {
952
+ element: MENU,
953
+ type: "horizontal",
954
+ // items: () => Array.from(MENU.querySelectorAll('nav > ul > li')),
955
+ // submenus: () => Array.from(MENU.querySelectorAll('.menu-item-has-children > ul')),
956
+ // dropdowns: () => Array.from(MENU.querySelectorAll('.menu-item-has-children')).map(PGS_dropdown_api).filter(Boolean),
957
+ refresh: () => {
958
+ PGS_menu_init(MENU.parentNode || document);
959
+ return API.get(MENU);
960
+ },
818
961
  });
962
+ _dropdown__WEBPACK_IMPORTED_MODULE_0__.PGS_dropdown.init(MENU);
963
+ });
819
964
 
820
- // pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
821
-
822
- // MENU.querySelectorAll('.menu-item-has-children').forEach(li => {
823
- // if (li.querySelector("ul")) {
824
- // const ul = li.querySelector("ul");
825
-
826
- // const button = document.createElement("button");
827
- // button.className = "icon-down";
828
- // button.type = "button";
829
- // button.innerHTML = "<span>&#9207;</span>";
830
- // li.querySelector("a").insertAdjacentElement("afterend", button);
965
+ }
831
966
 
967
+ PGS_menu_init()
832
968
 
833
- // pgs(button).add("buttonIcon")
834
- // button.addEventListener("click", () => {
835
- // ul.classList.toggle("open")
836
- // })
837
- // }
838
- // });
839
- // });
840
- });
841
- (0,_dropdown__WEBPACK_IMPORTED_MODULE_0__.pgs_dropdown)()
969
+ function PGS_menu_api(selector) {
970
+ return API.get(selector);
842
971
  }
843
972
 
844
- //# INIT PGS_menu
845
- PGS_menu()
973
+ //# EXPORT
974
+ const PGS_menu = {
975
+ init: PGS_menu_init,
976
+ api: PGS_menu_api
977
+ };
978
+
846
979
 
847
980
  /***/ },
848
981
 
@@ -855,12 +988,16 @@ PGS_menu()
855
988
  "use strict";
856
989
  __webpack_require__.r(__webpack_exports__);
857
990
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
858
- /* harmony export */ PGS_modal: () => (/* binding */ PGS_modal)
991
+ /* harmony export */ PGS_modal: () => (/* binding */ PGS_modal),
992
+ /* harmony export */ PGS_modal_api: () => (/* binding */ PGS_modal_api),
993
+ /* harmony export */ PGS_modal_init: () => (/* binding */ PGS_modal_init)
859
994
  /* harmony export */ });
860
995
  //# MODAL
861
- PGS_modal()
862
- function PGS_modal(selector = "modal") {
996
+ const API = new WeakMap();
997
+
998
+ function PGS_modal_init(selector = "modal") {
863
999
  pgs(document).querySelectorAll(selector).forEach(MODAL => {
1000
+ if (API.has(MODAL)) return;
864
1001
 
865
1002
  const BUTTON_OPEN = pgs(MODAL).querySelector("modal-button");
866
1003
  const DIALOG = MODAL.querySelector("dialog");
@@ -913,9 +1050,14 @@ function PGS_modal(selector = "modal") {
913
1050
  //+ FN OPEN
914
1051
  function openModal(e) {
915
1052
  e?.stopImmediatePropagation();
1053
+ if (DIALOG.open) {
1054
+ closeModal(e);
1055
+ return;
1056
+ }
1057
+
916
1058
  if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
917
1059
  statusModal(true);
918
- DIALOG.open ? closeModal(e) : topLevel ? DIALOG.showModal() : DIALOG.show();
1060
+ topLevel ? DIALOG.showModal() : DIALOG.show();
919
1061
  // modalCustomEvents('modal:open', { event: e });
920
1062
  MODAL.dispatchEvent(new CustomEvent('modal:open'));
921
1063
  DIALOG.dispatchEvent(new CustomEvent('modal:open'));
@@ -931,6 +1073,14 @@ function PGS_modal(selector = "modal") {
931
1073
  DIALOG.dispatchEvent(new CustomEvent('modal:close'));
932
1074
  }
933
1075
 
1076
+ function forceOpen(e) {
1077
+ if (!DIALOG.open) openModal(e);
1078
+ }
1079
+
1080
+ function forceClose(e) {
1081
+ if (DIALOG.open) closeModal(e);
1082
+ }
1083
+
934
1084
  //+ fn OPEN ON HISTORY
935
1085
  function openModalOnHistory() {
936
1086
  const params = new URLSearchParams(window.location.search);
@@ -976,10 +1126,214 @@ function PGS_modal(selector = "modal") {
976
1126
  } catch (_) { }
977
1127
  });
978
1128
  }
1129
+
1130
+ API.set(MODAL, {
1131
+ element: MODAL,
1132
+ button: BUTTON_OPEN,
1133
+ dialog: DIALOG,
1134
+ closeButton: BUTTON_CLOSE,
1135
+ open: forceOpen,
1136
+ close: forceClose,
1137
+ toggle: openModal,
1138
+ refresh: () => {
1139
+ PGS_modal_init(selector);
1140
+ return API.get(MODAL);
1141
+ },
1142
+ isOpen: () => DIALOG.open,
1143
+ });
979
1144
  });
980
1145
  }
981
1146
 
982
1147
  //# INIT PGS_modal
1148
+ PGS_modal_init()
1149
+
1150
+ //# API
1151
+ function PGS_modal_api(selector) {
1152
+ return API.get(selector);
1153
+ }
1154
+
1155
+ const PGS_modal = {
1156
+ init: PGS_modal_init,
1157
+ api: PGS_modal_api
1158
+ };
1159
+
1160
+
1161
+ /***/ },
1162
+
1163
+ /***/ "./assets/javascript/components/_notifications.js"
1164
+ /*!********************************************************!*\
1165
+ !*** ./assets/javascript/components/_notifications.js ***!
1166
+ \********************************************************/
1167
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1168
+
1169
+ "use strict";
1170
+ __webpack_require__.r(__webpack_exports__);
1171
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1172
+ /* harmony export */ PGS_notification: () => (/* binding */ PGS_notification),
1173
+ /* harmony export */ PGS_notificationTrigger_init: () => (/* binding */ PGS_notificationTrigger_init)
1174
+ /* harmony export */ });
1175
+ //= PGS_notification
1176
+ const fn_notification = {
1177
+ _escapeHtml(value) {
1178
+ return String(value ?? "");
1179
+ },
1180
+
1181
+ _getDuration(notification) {
1182
+ const rawDuration = notification.duration;
1183
+ const duration = Number.parseInt(rawDuration, 10);
1184
+
1185
+ return Number.isNaN(duration) ? 5000 : duration;
1186
+ },
1187
+
1188
+ _getApi(notification) {
1189
+ const element = String(notification.element || "notification").trim();
1190
+
1191
+ return element === "toast" ? PGS_notification.toast : PGS_notification.alert;
1192
+ },
1193
+
1194
+ _getType(notification, api) {
1195
+ const type = String(notification.type || "info").trim();
1196
+
1197
+ return typeof api[type] === "function" ? type : "info";
1198
+ },
1199
+
1200
+ _getData(root) {
1201
+ try {
1202
+ return JSON.parse(root.dataset.notification || "{}");
1203
+ } catch (error) {
1204
+ console.warn("PGS notification: dati non validi", error);
1205
+ return {};
1206
+ }
1207
+ },
1208
+
1209
+ _getContent(title, content) {
1210
+ const safeContent = this._escapeHtml(content);
1211
+ const safeTitle = this._escapeHtml(title);
1212
+
1213
+ if (!safeTitle) return safeContent;
1214
+ if (!safeContent) return `<span pgs="notification-element-title">${safeTitle}</span>`;
1215
+
1216
+ return `
1217
+ <span pgs="notification-element-title">${safeTitle}</span>
1218
+ <br>
1219
+ <span pgs="notification-element-content">${safeContent}</span>
1220
+ `;
1221
+ },
1222
+
1223
+ initNotification(type, containerToken, icon, text, timeout, methodDelete = "replace", link = null) {
1224
+ let containerNotification = pgs(document).querySelector(containerToken);
1225
+
1226
+ //== Create Container
1227
+ if (!containerNotification) {
1228
+ const newContainer = document.createElement("div");
1229
+ pgs(newContainer).add(containerToken);
1230
+ newContainer.setAttribute("aria-live", "polite");
1231
+ newContainer.setAttribute("aria-relevant", "additions");
1232
+ document.body.appendChild(newContainer);
1233
+ containerNotification = newContainer;
1234
+ }
1235
+
1236
+ //== Create Notification
1237
+ const notification = document.createElement(link ? "a" : "div");
1238
+ if (methodDelete == "replace") containerNotification.innerHTML = "";
1239
+ if (link) notification.href = link;
1240
+ if (timeout > 0) notification.style.setProperty("--notification-timeout", timeout + "ms");
1241
+ pgs(notification).state.add(type);
1242
+ pgs(notification).add("notification-element");
1243
+ notification.setAttribute("role", type == "error" ? "alert" : "status")
1244
+ notification.innerHTML = `${icon} <p>${text}</p>`;
1245
+ containerNotification.appendChild(notification);
1246
+
1247
+
1248
+ //+ Animation delete
1249
+ function deleteNotification() {
1250
+ methodDelete == "stack" ? notification.style.translate = "120%" : notification.style.opacity = "0";
1251
+ setTimeout(() => notification.remove(), 300);
1252
+ }
1253
+
1254
+ //== Timeout delete
1255
+ if (timeout > 0) setTimeout(() => { deleteNotification() }, timeout);
1256
+
1257
+ //== button delete
1258
+ const btnDelete = document.createElement("button");
1259
+ btnDelete.type = "button";
1260
+ btnDelete.ariaLabel = "Rimuovi notifica";
1261
+ btnDelete.innerHTML = '<i class="fa-solid fa-xmark"></i>';
1262
+ btnDelete.setAttribute("pgs", "buttonClose");
1263
+ notification.insertAdjacentElement("afterbegin", btnDelete);
1264
+
1265
+ //== event
1266
+
1267
+ btnDelete.addEventListener("click", function (e) {
1268
+ e.preventDefault();
1269
+ e.stopPropagation();
1270
+ e.stopImmediatePropagation()
1271
+ deleteNotification(e); // Esegue la tua funzione
1272
+ });
1273
+ },
1274
+
1275
+ deleteAll(containerToken) {
1276
+ let containerNotification = pgs(document).querySelector(containerToken);
1277
+ if (containerNotification) containerNotification.innerHTML = "";
1278
+ },
1279
+
1280
+ trigger(root = document) {
1281
+ pgs(root).querySelectorAll("notificationTrigger").forEach(element => {
1282
+ if (!element || element.dataset.initialize === "true") return;
1283
+
1284
+ element.dataset.initialize = "true";
1285
+
1286
+ const notification = this._getData(element);
1287
+ const title = String(notification.title || "").trim();
1288
+ const content = String(notification.message || "").trim();
1289
+
1290
+ if (!title && !content) {
1291
+ element.remove();
1292
+ return;
1293
+ }
1294
+
1295
+ const link = notification.link || null;
1296
+ const icon = notification.icon || undefined;
1297
+ const duration = this._getDuration(notification);
1298
+ const api = this._getApi(notification);
1299
+ const type = this._getType(notification, api);
1300
+ const formattedContent = this._getContent(title, content);
1301
+
1302
+ if (api === PGS_notification.toast) api[type](formattedContent, duration, icon);
1303
+ else api[type](formattedContent, link, duration, icon);
1304
+
1305
+ element.remove();
1306
+ });
1307
+ }
1308
+ };
1309
+
1310
+ //# EXPORT
1311
+ function PGS_notificationTrigger_init(root = document) {
1312
+ return fn_notification.trigger(root);
1313
+ }
1314
+
1315
+ const PGS_notification = {
1316
+ trigger: PGS_notificationTrigger_init,
1317
+ alert: {
1318
+ error: (text = "Errore", link = null, timeout = 0, icon = '<i class="fa-solid fa-circle-xmark"></i>') => fn_notification.initNotification("error", "notification", icon, text, timeout, "stack", link),
1319
+ success: (text = "Aggiornato", link = null, timeout = 0, icon = '<i class="fa-solid fa-check"></i>') => fn_notification.initNotification("success", "notification", icon, text, timeout, "stack", link),
1320
+ info: (text = "Aggiornamento", link = null, timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => fn_notification.initNotification("info", "notification", icon, text, timeout, "stack", link),
1321
+ warning: (text = "Attenzione", link = null, timeout = 0, icon = '<i class="fa-solid fa-triangle-exclamation"></i>') => fn_notification.initNotification("warning", "notification", icon, text, timeout, "stack", link),
1322
+ deleteAll: () => fn_notification.deleteAll("notification")
1323
+ },
1324
+ toast: {
1325
+ error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-circle-xmark"></i>',) => fn_notification.initNotification("error", "toast", icon, text, timeout),
1326
+ success: (text = "Aggiornato", timeout = 4000, icon = '<i class="fa-solid fa-check"></i>',) => fn_notification.initNotification("success", "toast", icon, text, timeout),
1327
+ info: (text = "Aggiornamento", timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => fn_notification.initNotification("info", "toast", icon, text, timeout),
1328
+ warning: (text = "Attenzione", timeout = 4000, icon = '<i class="fa-solid fa-triangle-exclamation"></i>',) => fn_notification.initNotification("warning", "toast", icon, text, timeout),
1329
+ deleteAll: () => fn_notification.deleteAll("toast")
1330
+ }
1331
+ };
1332
+
1333
+
1334
+ //= EXECUTE
1335
+ if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", () => PGS_notificationTrigger_init());
1336
+ else PGS_notificationTrigger_init();
983
1337
 
984
1338
 
985
1339
  /***/ },
@@ -993,6 +1347,7 @@ function PGS_modal(selector = "modal") {
993
1347
  "use strict";
994
1348
  __webpack_require__.r(__webpack_exports__);
995
1349
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1350
+ /* harmony export */ PGS_slides: () => (/* binding */ PGS_slides),
996
1351
  /* harmony export */ PGS_slides_api: () => (/* binding */ PGS_slides_api),
997
1352
  /* harmony export */ PGS_slides_init: () => (/* binding */ PGS_slides_init)
998
1353
  /* harmony export */ });
@@ -1161,10 +1516,13 @@ class PGS_Slides {
1161
1516
  const last = children[children.length - 1];
1162
1517
  return last?.classList.contains("view") || false;
1163
1518
  },
1519
+ refresh: () => {
1520
+ PGS_slides_init(this.selector.parentNode || document);
1521
+ return API.get(this.selector);
1522
+ },
1164
1523
  });
1165
1524
  }
1166
1525
  }
1167
- PGS_slides_init();
1168
1526
 
1169
1527
  //# INIT
1170
1528
  function PGS_slides_init(root = document) {
@@ -1176,11 +1534,18 @@ function PGS_slides_init(root = document) {
1176
1534
  });
1177
1535
  }
1178
1536
 
1537
+ PGS_slides_init();
1538
+
1179
1539
  //# API
1180
1540
  function PGS_slides_api(selector) {
1181
1541
  return API.get(selector);
1182
1542
  }
1183
1543
 
1544
+ const PGS_slides = {
1545
+ init: PGS_slides_init,
1546
+ api: PGS_slides_api
1547
+ };
1548
+
1184
1549
 
1185
1550
  /***/ },
1186
1551
 
@@ -1194,13 +1559,13 @@ function PGS_slides_api(selector) {
1194
1559
  __webpack_require__.r(__webpack_exports__);
1195
1560
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1196
1561
  /* harmony export */ PGS_stepTabs: () => (/* binding */ PGS_stepTabs),
1197
- /* harmony export */ PGS_tabs_api: () => (/* binding */ PGS_tabs_api)
1562
+ /* harmony export */ PGS_stepTabs_api: () => (/* binding */ PGS_stepTabs_api),
1563
+ /* harmony export */ PGS_stepTabs_init: () => (/* binding */ PGS_stepTabs_init)
1198
1564
  /* harmony export */ });
1199
1565
  const API = new WeakMap();
1200
- PGS_stepTabs()
1201
1566
 
1202
- function PGS_stepTabs() {
1203
- pgs(document).querySelectorAll("stepTabs").forEach(tabsWizard => {
1567
+ function PGS_stepTabs_init(root = document) {
1568
+ pgs(root).querySelectorAll("stepTabs").forEach(tabsWizard => {
1204
1569
  if (tabsWizard.dataset.stepTabsInitialized === "true") return;
1205
1570
  tabsWizard.dataset.stepTabsInitialized = "true";
1206
1571
 
@@ -1315,21 +1680,34 @@ function PGS_stepTabs() {
1315
1680
  //-(API)
1316
1681
  // tabsWizard.addEventListener("stepTabs:reset", () => restartTab());
1317
1682
  API.set(tabsWizard, {
1683
+ element: tabsWizard,
1684
+ container: tabsContainer,
1318
1685
  restart: restartTab,
1319
1686
  goTo,
1320
1687
  next: () => goTo(current + 1),
1321
1688
  prev: () => goTo(current - 1),
1322
1689
  toggleLock: (step, lock = true) => typeof step === "number" && allTab[step] && (pgs(allTab[step]).state.toggle("is-locked", lock), goTo(current)),
1690
+ refresh: () => {
1691
+ PGS_stepTabs_init(tabsWizard.parentNode || document);
1692
+ return API.get(tabsWizard);
1693
+ },
1323
1694
  getCurrent: () => current,
1324
1695
  getState: () => ({ current, total }),
1325
1696
  });
1326
1697
  });
1327
1698
  }
1328
1699
 
1329
- function PGS_tabs_api(selector) {
1700
+ PGS_stepTabs_init()
1701
+
1702
+ function PGS_stepTabs_api(selector) {
1330
1703
  return API.get(selector);
1331
1704
  }
1332
1705
 
1706
+ const PGS_stepTabs = {
1707
+ init: PGS_stepTabs_init,
1708
+ api: PGS_stepTabs_api
1709
+ };
1710
+
1333
1711
  /*
1334
1712
  / EXAMPLE
1335
1713
  // vai allo step 2
@@ -1366,11 +1744,15 @@ function PGS_tabs_api(selector) {
1366
1744
  "use strict";
1367
1745
  __webpack_require__.r(__webpack_exports__);
1368
1746
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1369
- /* harmony export */ PGS_ol: () => (/* binding */ PGS_ol)
1747
+ /* harmony export */ PGS_steps: () => (/* binding */ PGS_steps),
1748
+ /* harmony export */ PGS_steps_api: () => (/* binding */ PGS_steps_api),
1749
+ /* harmony export */ PGS_steps_init: () => (/* binding */ PGS_steps_init)
1370
1750
  /* harmony export */ });
1751
+ const API = new WeakMap();
1371
1752
 
1372
- function PGS_ol() {
1373
- pgs(document).querySelectorAll("steps").forEach(steps => {
1753
+ function PGS_steps_init(root = document) {
1754
+ pgs(root).querySelectorAll("steps").forEach(steps => {
1755
+ if (API.has(steps)) return;
1374
1756
 
1375
1757
  pgs(steps).querySelectorAll("steps-step").forEach((li, index) => {
1376
1758
 
@@ -1386,105 +1768,273 @@ function PGS_ol() {
1386
1768
  }
1387
1769
 
1388
1770
  //= line
1389
- const line = document.createElement("span");
1390
- pgs(line).add("steps-step-line")
1391
- li.insertAdjacentElement("afterbegin", line);
1771
+ if (!pgs(li).querySelector("steps-step-line")) {
1772
+ const line = document.createElement("span");
1773
+ pgs(line).add("steps-step-line")
1774
+ li.insertAdjacentElement("afterbegin", line);
1775
+ }
1776
+ });
1777
+
1778
+ API.set(steps, {
1779
+ element: steps,
1780
+ steps: () => Array.from(pgs(steps).querySelectorAll("steps-step")),
1781
+ getStep: (index) => pgs(steps).querySelectorAll("steps-step")[index],
1782
+ getTotal: () => pgs(steps).querySelectorAll("steps-step").length,
1783
+ refresh: () => {
1784
+ API.delete(steps);
1785
+ PGS_steps_init(steps.parentNode || document);
1786
+ return API.get(steps);
1787
+ },
1392
1788
  });
1393
1789
  });
1394
1790
  }
1395
1791
 
1396
1792
  //# INIT PGS_ol
1397
- PGS_ol()
1793
+ PGS_steps_init()
1794
+
1795
+ //# API
1796
+ function PGS_steps_api(selector) {
1797
+ return API.get(selector);
1798
+ }
1799
+
1800
+ const PGS_steps = {
1801
+ init: PGS_steps_init,
1802
+ api: PGS_steps_api
1803
+ };
1804
+
1398
1805
 
1399
1806
  /***/ },
1400
1807
 
1401
- /***/ "./assets/javascript/functions/_notifications.js"
1402
- /*!*******************************************************!*\
1403
- !*** ./assets/javascript/functions/_notifications.js ***!
1404
- \*******************************************************/
1808
+ /***/ "./assets/javascript/functions/_formValidate.js"
1809
+ /*!******************************************************!*\
1810
+ !*** ./assets/javascript/functions/_formValidate.js ***!
1811
+ \******************************************************/
1405
1812
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1406
1813
 
1407
1814
  "use strict";
1408
1815
  __webpack_require__.r(__webpack_exports__);
1409
1816
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1410
- /* harmony export */ PGS_notification: () => (/* binding */ PGS_notification),
1411
- /* harmony export */ PGS_toast: () => (/* binding */ PGS_toast)
1817
+ /* harmony export */ PGS_formValidate: () => (/* binding */ PGS_formValidate)
1412
1818
  /* harmony export */ });
1413
- //# PGS_notification
1414
- function initNotification(type, containerToken, icon, text, timeout, methodDelete = "replace", link = null) {
1415
- let containerNotification = pgs(document).querySelector(containerToken);
1416
-
1417
- //== Create Container
1418
- if (!containerNotification) {
1419
- const newContainer = document.createElement("div");
1420
- pgs(newContainer).add(containerToken);
1421
- newContainer.setAttribute("aria-live", "polite");
1422
- newContainer.setAttribute("aria-relevant", "additions");
1423
- document.body.appendChild(newContainer);
1424
- containerNotification = newContainer;
1819
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/_notifications.js */ "./assets/javascript/components/_notifications.js");
1820
+
1821
+
1822
+
1823
+ class PGS_formValidate {
1824
+ constructor({ form } = {}) {
1825
+ this.container = form;
1826
+ this._rules = [];
1827
+ // pgs(this.container).add("formError");
1828
+ }
1829
+
1830
+ //+ ADD
1831
+ addError(field, i) {
1832
+ field.setAttribute("data-form-field-status", "error");
1833
+ if (i == 0) field.scrollIntoView();
1834
+
1835
+ let message = field.getAttribute("data-form-field-message");
1836
+
1837
+ if (i == 0 && message) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.error(message);
1838
+ else if (i == 0) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.error("Compila tutti i campi!");
1839
+ }
1840
+
1841
+ //+ REMOVE
1842
+ removeError(field) {
1843
+ field.setAttribute("data-form-field-status", "");
1425
1844
  }
1426
1845
 
1427
- //== Create Notification
1428
- const notification = document.createElement(link ? "a" : "div");
1429
- if (methodDelete == "replace") containerNotification.innerHTML = "";
1430
- if (link) notification.href = link;
1431
- if (timeout > 0) notification.style.setProperty("--notification-timeout", timeout + "ms");
1432
- pgs(notification).state.add(type);
1433
- pgs(notification).add("notification-element");
1434
- notification.setAttribute("role", type == "error" ? "alert" : "status")
1435
- notification.innerHTML = `${icon} <p>${text}</p>`;
1436
- containerNotification.appendChild(notification);
1437
-
1438
-
1439
- //+ Animation delete
1440
- function deleteNotification() {
1441
- methodDelete == "stack" ? notification.style.translate = "120%" : notification.style.opacity = "0";
1442
- setTimeout(() => notification.remove(), 300);
1846
+ #removeErrorOnClick(allFields) {
1847
+ allFields.forEach(element => {
1848
+ element.addEventListener("click", e => this.removeError(element))
1849
+ });
1443
1850
  }
1444
1851
 
1445
- //== Timeout delete
1446
- if (timeout > 0) setTimeout(() => { deleteNotification() }, timeout);
1852
+ // + --------------------------
1853
+ // + Helpers
1854
+ // + --------------------------
1855
+ help = {
1856
+ // supporta sia required nativo, sia data-required="true"
1857
+ isRequired(field) {
1858
+ if (!field) return false;
1859
+
1860
+ const required = field.required === true || field?.dataset?.required === "true" || field?.getAttribute('aria-required') == "true";
1861
+ return required && !field.hidden; // solo attributo/proprietà "hidden"
1862
+ },
1863
+ // input (non speciali), textarea
1864
+ isEmptyTextLike(field) { return !String(field?.value ?? "").trim(); },
1865
+ // select: vuoto se value == "" o null
1866
+ isEmptySelect(field) { return !String(field?.value ?? "").trim(); },
1867
+ // recupera name in modo sicuro
1868
+ getGroupName(field) { return field?.name || field?.getAttribute?.("name") || ""; }
1869
+ };
1447
1870
 
1448
- //== button delete
1449
- const btnDelete = document.createElement("button");
1450
- btnDelete.type = "button";
1451
- btnDelete.ariaLabel = "Rimuovi notifica";
1452
- btnDelete.innerHTML = '<i class="fa-solid fa-xmark"></i>';
1453
- btnDelete.setAttribute("pgs", "buttonClose");
1454
- notification.insertAdjacentElement("afterbegin", btnDelete);
1455
1871
 
1456
- //== event
1457
- btnDelete.addEventListener("click", function (e) {
1458
- e.preventDefault();
1459
- e.stopPropagation();
1460
- e.stopImmediatePropagation()
1461
- deleteNotification(e); // Esegue la tua funzione
1462
- });
1463
- }
1872
+ // + --------------------------
1873
+ // + input + altri elementi.
1874
+ // + --------------------------
1875
+ #inputValue(container) {
1464
1876
 
1465
- function deleteALl(containerToken) {
1466
- let containerNotification = pgs(document).querySelector(containerToken);
1467
- if (containerNotification) containerNotification.innerHTML = "";
1468
- }
1877
+ //++ add rule
1878
+ const ruleInvalidFields = [];
1879
+ for (const rule of this._rules) {
1880
+ const res = rule(container);
1469
1881
 
1882
+ // la rule può tornare:
1883
+ // • null/undefined => ok
1884
+ // • un elemento => invalido
1885
+ // • un array di elementi => invalidi
1886
+ if (!res) continue;
1470
1887
 
1888
+ if (Array.isArray(res)) ruleInvalidFields.push(...res);
1889
+ else ruleInvalidFields.push(res);
1890
+ }
1471
1891
 
1472
- let PGS_notification = {
1473
- error: (text = "Errore", link = null, timeout = 0, icon = '<i class="fa-solid fa-octagon-xmark"></i>') => initNotification("error", "notification", icon, text, timeout, "stack", link),
1474
- success: (text = "Aggiornato", link = null, timeout = 0, icon = '<i class="fa-solid fa-check"></i>') => initNotification("success", "notification", icon, text, timeout, "stack", link),
1475
- info: (text = "Aggiornamento", link = null, timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => initNotification("info", "notification", icon, text, timeout, "stack", link),
1476
- warning: (text = "Attenzione", link = null, timeout = 0, icon = '<i class="fa-solid fa-triangle-exclamation"></i>') => initNotification("warning", "notification", icon, text, timeout, "stack", link),
1477
- deleteAllNotification: () => deleteALl("notification")
1478
- }
1892
+ //== INPUT
1893
+ // "testuali" (esclude hidden/disabled/checkbox/radio/file come nel tuo snippet)
1894
+ const textInputs = Array.from(container.querySelectorAll("input")).filter((input) => {
1895
+ if (input.disabled) return false;
1896
+ if (input.type === "hidden") return false;
1897
+ if (input.type === "checkbox" || input.type === "radio" || input.type === "file") return false;
1898
+
1899
+ // valida solo se required (o data-required="true")
1900
+ if (!this.help.isRequired(input)) return false;
1901
+
1902
+ return this.help.isEmptyTextLike(input);
1903
+ });
1904
+
1905
+ //== TEXTAREA
1906
+ // required vuote
1907
+ const textareas = Array.from(container.querySelectorAll("textarea")).filter((ta) => {
1908
+ if (ta.disabled) return false;
1909
+ if (!this.help.isRequired(ta)) return false;
1910
+ return this.help.isEmptyTextLike(ta);
1911
+ });
1912
+
1913
+ //== SELECT
1914
+ // required vuoti
1915
+ const selects = Array.from(container.querySelectorAll("select")).filter((sel) => {
1916
+ if (sel.disabled) return false;
1917
+ if (!this.help.isRequired(sel)) return false;
1918
+ return this.help.isEmptySelect(sel);
1919
+ });
1920
+
1921
+ //== RADIO
1922
+ // required: se in un gruppo required non ce n'è uno checked => errore sul "primo" radio del gruppo
1923
+ const radios = Array.from(container.querySelectorAll('input[type="radio"]')).filter((r) => !r.disabled);
1924
+ const requiredRadioGroups = new Map(); // name -> [elements]
1925
+ for (const r of radios) {
1926
+ if (!this.help.isRequired(r)) continue;
1927
+ const name = this.help.getGroupName(r);
1928
+ if (!name) continue;
1929
+ if (!requiredRadioGroups.has(name)) requiredRadioGroups.set(name, []);
1930
+ requiredRadioGroups.get(name).push(r);
1931
+ }
1932
+ const radioGroupErrors = [];
1933
+ for (const [name, group] of requiredRadioGroups.entries()) {
1934
+ const anyChecked = group.some((r) => r.checked);
1935
+ if (!anyChecked) {
1936
+ // scegli dove mettere l'errore: tipicamente sul primo radio del gruppo
1937
+ radioGroupErrors.push(group[0]);
1938
+ }
1939
+ }
1479
1940
 
1480
- let PGS_toast = {
1481
- error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-octagon-xmark"></i>',) => initNotification("error", "toast", icon, text, timeout),
1482
- success: (text = "Aggiornato", timeout = 4000, icon = '<i class="fa-solid fa-check"></i>',) => initNotification("success", "toast", icon, text, timeout),
1483
- info: (text = "Aggiornamento", timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => initNotification("info", "toast", icon, text, timeout),
1484
- warning: (text = "Attenzione", timeout = 4000, icon = '<i class="fa-solid fa-triangle-exclamation"></i>',) => initNotification("warning", "toast", icon, text, timeout),
1485
- deleteTost: () => deleteALl("toast")
1941
+ //== CHECKBOX
1942
+ // required: può essere singola checkbox required (checked obbligatorio)
1943
+ // oppure gruppo di checkbox (stesso name) con almeno una selezionata
1944
+ const checkboxes = Array.from(container.querySelectorAll('input[type="checkbox"]')).filter((c) => !c.disabled);
1945
+ const requiredCheckboxSingles = [];
1946
+ const requiredCheckboxGroups = new Map(); // name -> [elements]
1947
+ for (const c of checkboxes) {
1948
+ if (!this.help.isRequired(c)) continue;
1949
+
1950
+ const name = this.help.getGroupName(c);
1951
+ if (!name) {
1952
+ // checkbox senza name: trattala come singola required
1953
+ if (!c.checked) requiredCheckboxSingles.push(c);
1954
+ continue;
1955
+ }
1956
+
1957
+ // se vuoi trattare come gruppo, raggruppa per name
1958
+ if (!requiredCheckboxGroups.has(name)) requiredCheckboxGroups.set(name, []);
1959
+ requiredCheckboxGroups.get(name).push(c);
1960
+ }
1961
+ const checkboxGroupErrors = [];
1962
+ for (const [name, group] of requiredCheckboxGroups.entries()) {
1963
+ // se è un gruppo (>=2) richiedi almeno una spuntata
1964
+ // se è 1 sola, si comporta come singola
1965
+ const anyChecked = group.some((c) => c.checked);
1966
+ if (!anyChecked) checkboxGroupErrors.push(group[0]);
1967
+ }
1968
+
1969
+ //== FILE
1970
+ // required: se vuoi includerlo
1971
+ const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')).filter((f) => {
1972
+ if (f.disabled) return false;
1973
+ if (!this.help.isRequired(f)) return false;
1974
+ return !(f.files && f.files.length > 0);
1975
+ });
1976
+
1977
+ //== risultato finale: tutti i campi da marcare come errore
1978
+ const invalidFields = [
1979
+ textInputs,
1980
+ textareas,
1981
+ selects,
1982
+ radioGroupErrors,
1983
+ requiredCheckboxSingles,
1984
+ checkboxGroupErrors,
1985
+ fileInputs,
1986
+ ruleInvalidFields
1987
+ ];
1988
+
1989
+ return invalidFields.flat();
1990
+ }
1991
+
1992
+ // + -------------------------
1993
+ // + VALIDATE
1994
+ // + -------------------------
1995
+ validate() {
1996
+ const invalid = this.#inputValue(this.container);
1997
+ const allFields = this.container.querySelectorAll("input, textarea, select")
1998
+
1999
+ //== pulizia/aggiornamento errori:
2000
+ // prima rimuovo errori dai campi "non più invalidi"
2001
+ Array.from(allFields).filter((el) => !el.disabled);
2002
+
2003
+ //== per radio/checkbox in gruppo:
2004
+ // rimuovi l'errore solo sull'elemento che lo ospita (qui: se presente)
2005
+ for (const el of allFields) { if (!invalid.includes(el)) this.removeError(el); }
2006
+
2007
+ //== aggiungo errori dove serve
2008
+ invalid.forEach((el, i) => this.addError(el, i))
2009
+
2010
+ //== rimuove l'errore al click
2011
+ this.#removeErrorOnClick(allFields)
2012
+
2013
+ //== status form
2014
+ if (invalid.length) {
2015
+ this.container.setAttribute("data-form-status", "error");
2016
+ return false;
2017
+ } else {
2018
+ this.container.setAttribute("data-form-status", "success");
2019
+ return true;
2020
+ }
2021
+ }
2022
+
2023
+ ifSuccess(text = "Inviato con successo") {
2024
+ if (this.validate() == true) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.success(text)
2025
+ }
2026
+
2027
+ // + -------------------------
2028
+ // + ADD RULE
2029
+ // + -------------------------
2030
+ addNewRule(container) {
2031
+ if (typeof container !== "function") throw new Error("Rule must be a function");
2032
+ this._rules.push(container);
2033
+ return this;
2034
+ }
1486
2035
  }
1487
2036
 
2037
+
1488
2038
  /***/ },
1489
2039
 
1490
2040
  /***/ "./assets/javascript/functions/_scrollY.js"
@@ -1683,7 +2233,7 @@ function assignCookieRuntimeAttributes({ root, analyticsToggle, acceptAllButton,
1683
2233
  }
1684
2234
 
1685
2235
  //= CookieConsent
1686
- document.addEventListener('DOMContentLoaded', function () {
2236
+ function initCookieConsent() {
1687
2237
  const root = pgs(document).querySelector('cookieConsent');
1688
2238
  if (!root) return;
1689
2239
 
@@ -1793,7 +2343,13 @@ document.addEventListener('DOMContentLoaded', function () {
1793
2343
  } else {
1794
2344
  setBannerVisibility(true);
1795
2345
  }
1796
- });
2346
+ }
2347
+
2348
+ if (document.readyState === 'loading') {
2349
+ document.addEventListener('DOMContentLoaded', initCookieConsent);
2350
+ } else {
2351
+ initCookieConsent();
2352
+ }
1797
2353
 
1798
2354
 
1799
2355
  /***/ },
@@ -1802,13 +2358,8 @@ document.addEventListener('DOMContentLoaded', function () {
1802
2358
  /*!***********************************************!*\
1803
2359
  !*** ./assets/javascript/patterns/_header.js ***!
1804
2360
  \***********************************************/
1805
- (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2361
+ () {
1806
2362
 
1807
- "use strict";
1808
- __webpack_require__.r(__webpack_exports__);
1809
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1810
- /* harmony export */ PGS_header: () => (/* binding */ PGS_header)
1811
- /* harmony export */ });
1812
2363
  //# HEADER
1813
2364
  const header = pgs(document).querySelector("header");
1814
2365
  const headerElements = pgs(header).querySelectorAll("header-element");
@@ -1949,17 +2500,17 @@ if (window.innerWidth < 600) {
1949
2500
  /******/ });
1950
2501
  /************************************************************************/
1951
2502
  /******/ // The module cache
1952
- /******/ var __webpack_module_cache__ = {};
2503
+ /******/ const __webpack_module_cache__ = {};
1953
2504
  /******/
1954
2505
  /******/ // The require function
1955
2506
  /******/ function __webpack_require__(moduleId) {
1956
2507
  /******/ // Check if module is in cache
1957
- /******/ var cachedModule = __webpack_module_cache__[moduleId];
2508
+ /******/ const cachedModule = __webpack_module_cache__[moduleId];
1958
2509
  /******/ if (cachedModule !== undefined) {
1959
2510
  /******/ return cachedModule.exports;
1960
2511
  /******/ }
1961
2512
  /******/ // Create a new module (and put it into the cache)
1962
- /******/ var module = __webpack_module_cache__[moduleId] = {
2513
+ /******/ const module = __webpack_module_cache__[moduleId] = {
1963
2514
  /******/ // no module.id needed
1964
2515
  /******/ // no module.loaded needed
1965
2516
  /******/ exports: {}
@@ -1968,7 +2519,7 @@ if (window.innerWidth < 600) {
1968
2519
  /******/ // Execute the module function
1969
2520
  /******/ if (!(moduleId in __webpack_modules__)) {
1970
2521
  /******/ delete __webpack_module_cache__[moduleId];
1971
- /******/ var e = new Error("Cannot find module '" + moduleId + "'");
2522
+ /******/ const e = new Error("Cannot find module '" + moduleId + "'");
1972
2523
  /******/ e.code = 'MODULE_NOT_FOUND';
1973
2524
  /******/ throw e;
1974
2525
  /******/ }
@@ -1983,7 +2534,7 @@ if (window.innerWidth < 600) {
1983
2534
  /******/ (() => {
1984
2535
  /******/ // getDefaultExport function for compatibility with non-harmony modules
1985
2536
  /******/ __webpack_require__.n = (module) => {
1986
- /******/ var getter = module && module.__esModule ?
2537
+ /******/ const getter = module && module.__esModule ?
1987
2538
  /******/ () => (module['default']) :
1988
2539
  /******/ () => (module);
1989
2540
  /******/ __webpack_require__.d(getter, { a: getter });
@@ -1993,11 +2544,26 @@ if (window.innerWidth < 600) {
1993
2544
  /******/
1994
2545
  /******/ /* webpack/runtime/define property getters */
1995
2546
  /******/ (() => {
1996
- /******/ // define getter functions for harmony exports
2547
+ /******/ // define getter/value functions for harmony exports
1997
2548
  /******/ __webpack_require__.d = (exports, definition) => {
1998
- /******/ for(var key in definition) {
1999
- /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
2000
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
2549
+ /******/ if(Array.isArray(definition)) {
2550
+ /******/ var i = 0;
2551
+ /******/ while(i < definition.length) {
2552
+ /******/ var key = definition[i++];
2553
+ /******/ var binding = definition[i++];
2554
+ /******/ if(!__webpack_require__.o(exports, key)) {
2555
+ /******/ if(binding === 0) {
2556
+ /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
2557
+ /******/ } else {
2558
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
2559
+ /******/ }
2560
+ /******/ } else if(binding === 0) { i++; }
2561
+ /******/ }
2562
+ /******/ } else {
2563
+ /******/ for(var key in definition) {
2564
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
2565
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
2566
+ /******/ }
2001
2567
  /******/ }
2002
2568
  /******/ }
2003
2569
  /******/ };
@@ -2012,7 +2578,7 @@ if (window.innerWidth < 600) {
2012
2578
  /******/ (() => {
2013
2579
  /******/ // define __esModule on exports
2014
2580
  /******/ __webpack_require__.r = (exports) => {
2015
- /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
2581
+ /******/ if(Symbol.toStringTag) {
2016
2582
  /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2017
2583
  /******/ }
2018
2584
  /******/ Object.defineProperty(exports, '__esModule', { value: true });
@@ -2020,7 +2586,7 @@ if (window.innerWidth < 600) {
2020
2586
  /******/ })();
2021
2587
  /******/
2022
2588
  /************************************************************************/
2023
- var __webpack_exports__ = {};
2589
+ let __webpack_exports__ = {};
2024
2590
  // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
2025
2591
  (() => {
2026
2592
  "use strict";
@@ -2028,26 +2594,31 @@ var __webpack_exports__ = {};
2028
2594
  !*** ./assets/javascript/index.js ***!
2029
2595
  \************************************/
2030
2596
  __webpack_require__.r(__webpack_exports__);
2597
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2598
+ /* harmony export */ pgs: () => (/* reexport safe */ _pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)
2599
+ /* harmony export */ });
2031
2600
  /* harmony import */ var _pgs_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_pgs.js */ "./assets/javascript/_pgs.js");
2032
2601
  /* harmony import */ var _base_darkmode_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./base/_darkmode.js */ "./assets/javascript/base/_darkmode.js");
2033
2602
  /* harmony import */ var _base_darkmode_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_base_darkmode_js__WEBPACK_IMPORTED_MODULE_1__);
2034
2603
  /* harmony import */ var _base_object_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./base/_object.js */ "./assets/javascript/base/_object.js");
2035
2604
  /* harmony import */ var _base_object_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_base_object_js__WEBPACK_IMPORTED_MODULE_2__);
2036
2605
  /* harmony import */ var _components_accordion_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/_accordion.js */ "./assets/javascript/components/_accordion.js");
2037
- /* harmony import */ var _components_accordion_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_components_accordion_js__WEBPACK_IMPORTED_MODULE_3__);
2038
2606
  /* harmony import */ var _components_dropdown_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/_dropdown.js */ "./assets/javascript/components/_dropdown.js");
2039
- /* harmony import */ var _components_exeNotifications_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/_exeNotifications.js */ "./assets/javascript/components/_exeNotifications.js");
2040
- /* harmony import */ var _components_menu_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/_menu.js */ "./assets/javascript/components/_menu.js");
2041
- /* harmony import */ var _components_modals_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/_modals.js */ "./assets/javascript/components/_modals.js");
2042
- /* harmony import */ var _components_slides_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./components/_slides.js */ "./assets/javascript/components/_slides.js");
2043
- /* harmony import */ var _components_steps_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./components/_steps.js */ "./assets/javascript/components/_steps.js");
2044
- /* harmony import */ var _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./components/_stepTabs.js */ "./assets/javascript/components/_stepTabs.js");
2045
- /* harmony import */ var _patterns_header_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./patterns/_header.js */ "./assets/javascript/patterns/_header.js");
2046
- /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./patterns/_cookieConsent.js */ "./assets/javascript/patterns/_cookieConsent.js");
2047
- /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_12__);
2607
+ /* harmony import */ var _components_menu_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/_menu.js */ "./assets/javascript/components/_menu.js");
2608
+ /* harmony import */ var _components_modals_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/_modals.js */ "./assets/javascript/components/_modals.js");
2609
+ /* harmony import */ var _components_slides_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/_slides.js */ "./assets/javascript/components/_slides.js");
2610
+ /* harmony import */ var _components_steps_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./components/_steps.js */ "./assets/javascript/components/_steps.js");
2611
+ /* harmony import */ var _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./components/_stepTabs.js */ "./assets/javascript/components/_stepTabs.js");
2612
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./components/_notifications.js */ "./assets/javascript/components/_notifications.js");
2613
+ /* harmony import */ var _imports_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./_imports.js */ "./assets/javascript/_imports.js");
2614
+ /* harmony import */ var _patterns_header_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./patterns/_header.js */ "./assets/javascript/patterns/_header.js");
2615
+ /* harmony import */ var _patterns_header_js__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_patterns_header_js__WEBPACK_IMPORTED_MODULE_12__);
2616
+ /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./patterns/_cookieConsent.js */ "./assets/javascript/patterns/_cookieConsent.js");
2617
+ /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_13__);
2048
2618
  //= PGS
2049
2619
 
2050
2620
 
2621
+
2051
2622
  //= BASE
2052
2623
 
2053
2624
 
@@ -2062,8 +2633,10 @@ __webpack_require__.r(__webpack_exports__);
2062
2633
 
2063
2634
 
2064
2635
 
2065
- //= patterns
2636
+ //= IMPORT REGISTRY
2637
+
2066
2638
 
2639
+ //= PATTERNS
2067
2640
 
2068
2641
 
2069
2642
  })();