mypgs 1.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 (79) hide show
  1. package/README.md +33 -0
  2. package/assets/javascript/_pgs.js +214 -0
  3. package/assets/javascript/base/_darkmode.js +121 -0
  4. package/assets/javascript/base/_object.js +42 -0
  5. package/assets/javascript/components/_accordion.js +77 -0
  6. package/assets/javascript/components/_dropdown.js +107 -0
  7. package/assets/javascript/components/_exeNotifications.js +85 -0
  8. package/assets/javascript/components/_menu.js +92 -0
  9. package/assets/javascript/components/_modals.js +123 -0
  10. package/assets/javascript/components/_slides.js +183 -0
  11. package/assets/javascript/components/_steps.js +27 -0
  12. package/assets/javascript/components/_tabs.js +134 -0
  13. package/assets/javascript/functions/_formValidate.js +217 -0
  14. package/assets/javascript/functions/_notifications.js +74 -0
  15. package/assets/javascript/functions/_scrollY.js +77 -0
  16. package/assets/javascript/functions/_sendForm.js +100 -0
  17. package/assets/javascript/index.js +20 -0
  18. package/assets/javascript/patterns/_cookieConsent.js +209 -0
  19. package/assets/javascript/patterns/_header.js +134 -0
  20. package/assets/javascript/pgs.d.ts +23 -0
  21. package/assets/scss/base/_body.scss +151 -0
  22. package/assets/scss/base/_color.scss +56 -0
  23. package/assets/scss/base/_general.scss +58 -0
  24. package/assets/scss/base/_heading.scss +20 -0
  25. package/assets/scss/base/_html.scss +4 -0
  26. package/assets/scss/base/_reset.scss +15 -0
  27. package/assets/scss/base/_variables.scss +39 -0
  28. package/assets/scss/components/_accordion.scss +91 -0
  29. package/assets/scss/components/_breadcumbs.scss +40 -0
  30. package/assets/scss/components/_button.scss +28 -0
  31. package/assets/scss/components/_dropdown.scss +106 -0
  32. package/assets/scss/components/_form.scss +53 -0
  33. package/assets/scss/components/_logo.scss +51 -0
  34. package/assets/scss/components/_menu.scss +23 -0
  35. package/assets/scss/components/_modals.scss +120 -0
  36. package/assets/scss/components/_notification.scss +193 -0
  37. package/assets/scss/components/_searchbar.scss +68 -0
  38. package/assets/scss/components/_slides.scss +198 -0
  39. package/assets/scss/components/_steps.scss +111 -0
  40. package/assets/scss/components/_table.scss +59 -0
  41. package/assets/scss/components/_tabs.scss +69 -0
  42. package/assets/scss/components/_tooltip.scss +16 -0
  43. package/assets/scss/index.scss +64 -0
  44. package/assets/scss/layout/_flex.scss +47 -0
  45. package/assets/scss/layout/_gap.scss +12 -0
  46. package/assets/scss/layout/_grid.scss +11 -0
  47. package/assets/scss/layout/_layout.scss +41 -0
  48. package/assets/scss/layout/_pageShell.scss +171 -0
  49. package/assets/scss/mixin/_mx-base.scss +126 -0
  50. package/assets/scss/mixin/_mx-button.scss +186 -0
  51. package/assets/scss/mixin/_mx-card.scss +77 -0
  52. package/assets/scss/mixin/_mx-color.scss +34 -0
  53. package/assets/scss/mixin/_mx-form-addon.scss +180 -0
  54. package/assets/scss/mixin/_mx-form.scss +512 -0
  55. package/assets/scss/mixin/_mx-menu.scss +154 -0
  56. package/assets/scss/mixin/_mx-responsive.scss +353 -0
  57. package/assets/scss/mixin/_mx-semantic.scss +147 -0
  58. package/assets/scss/mixin/mixin.scss +36 -0
  59. package/assets/scss/patterns/_cookieConsent.scss +101 -0
  60. package/assets/scss/patterns/_footer.scss +180 -0
  61. package/assets/scss/patterns/_header.scss +143 -0
  62. package/dist/css/index.css +7026 -0
  63. package/dist/css/index.css.map +1 -0
  64. package/dist/css/index.min.css +1 -0
  65. package/dist/index.d.ts +24 -0
  66. package/dist/javascript/index.js +2034 -0
  67. package/dist/javascript/index.js.map +1 -0
  68. package/dist/javascript/index.min.js +1 -0
  69. package/package.json +40 -0
  70. package/templates/components/md-breadcumbs.html +23 -0
  71. package/templates/components/md-menu.html +6 -0
  72. package/templates/components/md-notification.html +10 -0
  73. package/templates/components/md-searchbar.html +24 -0
  74. package/templates/components/md-tooltip.html +5 -0
  75. package/templates/layout/md-body.html +20 -0
  76. package/templates/layout/md-cookieConsent.html +51 -0
  77. package/templates/layout/md-footer.html +16 -0
  78. package/templates/layout/md-header.html +43 -0
  79. package/webpack.config.js +131 -0
@@ -0,0 +1,92 @@
1
+ import { pgs_dropdown } from "./_dropdown";
2
+
3
+ //= DROP DOWN MENU
4
+ export function PGS_menu() {
5
+
6
+ pgs(document).querySelectorAll('menu-horizontal').forEach(MENU => {
7
+
8
+ MENU.querySelectorAll('nav > ul > li.menu-item-has-children').forEach(li => {
9
+ if (li.querySelector("ul")) {
10
+ const ul = li.querySelector("ul");
11
+
12
+ const button = document.createElement("button");
13
+ button.className = "icon-down";
14
+ button.type = "button";
15
+ button.innerHTML = "<span>&#9207;</span>";
16
+ li.querySelector("a").insertAdjacentElement("afterend", button);
17
+
18
+ pgs(li).add("dropdown")
19
+ pgs(button).add("dropdown-button")
20
+ pgs(button).add("buttonNohover")
21
+ pgs(ul).add("dropdown-content")
22
+ pgs(ul).add("menu-vertical")
23
+ }
24
+ });
25
+ });
26
+
27
+ pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
28
+
29
+ MENU.querySelectorAll('.menu-item-has-children').forEach((li, index) => {
30
+ const ul = li.querySelector("ul");
31
+
32
+ if (!ul) return
33
+
34
+ const button = document.createElement("button");
35
+ button.className = "icon-down buttonIcon";
36
+ button.type = "button";
37
+
38
+ // ID unico per aria-controls
39
+ const submenuId = `vertical-submenu-${index}`;
40
+ ul.id = submenuId;
41
+
42
+ // Stato iniziale
43
+ pgs(button).add("buttonIcon")
44
+ button.setAttribute("aria-expanded", "false");
45
+ button.setAttribute("aria-controls", submenuId);
46
+ button.setAttribute("aria-label", "Apri sottomenu");
47
+ button.innerHTML = "<span aria-hidden='true'>&#9207;</span>";
48
+ li.querySelector("a").insertAdjacentElement("afterend", button);
49
+
50
+ function toggleMenu() {
51
+ // const isOpena = ul.classList.toggle("open");
52
+ const isOpen = pgs(ul).state.toggle("open");
53
+ button.setAttribute("aria-expanded", isOpen);
54
+ button.setAttribute("aria-label", isOpen ? "Chiudi sottomenu" : "Apri sottomenu");
55
+ };
56
+
57
+ // Click
58
+ button.addEventListener("click", toggleMenu);
59
+ button.addEventListener("keydown", (e) => {
60
+ if (e.key === "Enter" || e.key === " ") {
61
+ e.preventDefault();
62
+ toggleMenu();
63
+ }
64
+ });
65
+ });
66
+
67
+ // pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
68
+
69
+ // MENU.querySelectorAll('.menu-item-has-children').forEach(li => {
70
+ // if (li.querySelector("ul")) {
71
+ // const ul = li.querySelector("ul");
72
+
73
+ // const button = document.createElement("button");
74
+ // button.className = "icon-down";
75
+ // button.type = "button";
76
+ // button.innerHTML = "<span>&#9207;</span>";
77
+ // li.querySelector("a").insertAdjacentElement("afterend", button);
78
+
79
+
80
+ // pgs(button).add("buttonIcon")
81
+ // button.addEventListener("click", () => {
82
+ // ul.classList.toggle("open")
83
+ // })
84
+ // }
85
+ // });
86
+ // });
87
+ });
88
+ pgs_dropdown()
89
+ }
90
+
91
+ //# INIT PGS_menu
92
+ PGS_menu()
@@ -0,0 +1,123 @@
1
+ //# MODAL
2
+ PGS_modal()
3
+ export function PGS_modal(selector = "modal") {
4
+ pgs(document).querySelectorAll(selector).forEach(MODAL => {
5
+
6
+ const BUTTON_OPEN = pgs(MODAL).querySelector("modal-button");
7
+ const DIALOG = MODAL.querySelector("dialog");
8
+ if (!BUTTON_OPEN || !DIALOG) return;
9
+
10
+ //== SELECTOR
11
+ const DOMButtonClose = '<button pgs="buttonClose modal-close" type="button" tabindex="0" aria-label="Chiudi"><i class="fa-solid fa-close"></i></button>';
12
+ const modalContentHeader = pgs(MODAL)?.querySelector("modal-dialog-content-header")
13
+
14
+
15
+ //== OPTION ATTRIBUTES MODAL
16
+ const disableBackdropClose = pgs(MODAL).option.contains("disableBackdropClose")
17
+ const data_history = pgs(MODAL).option.contains("history");
18
+ const data_container = pgs(MODAL).option.getValueBrackets("containerID");
19
+ const data_containerPGS = pgs(MODAL).option.getValueBrackets("containerPGS");
20
+
21
+ //== OPTION ATTRIBUTES DIALOG
22
+ const topLevel = pgs(DIALOG).option.contains("topLevel")
23
+
24
+
25
+ //== BUTTON CLOSE
26
+ if (pgs(MODAL).querySelector("modal-close")) null
27
+ else if (modalContentHeader) modalContentHeader.insertAdjacentHTML("beforeend", DOMButtonClose)
28
+ else DIALOG.insertAdjacentHTML("beforeend", DOMButtonClose)
29
+ const BUTTON_CLOSE = pgs(MODAL).querySelector("modal-close")
30
+
31
+
32
+ //== SET
33
+ pgs(DIALOG).add("dialog modal-dialog");
34
+
35
+ //== BUTTON OPEN
36
+ BUTTON_OPEN.setAttribute("role", "button");
37
+ BUTTON_OPEN.setAttribute("aria-label", "apri modale");
38
+
39
+
40
+ //== POSITION
41
+ if(!topLevel){
42
+ if (data_container) document.querySelector("#" + data_container)?.append(DIALOG);
43
+ else if (data_containerPGS) pgs(document).querySelector(data_containerPGS)?.append(DIALOG);
44
+ else document.body.append(DIALOG);
45
+ }
46
+
47
+
48
+ //+ FN STATUS
49
+ function statusModal(status = true) {
50
+ BUTTON_OPEN?.setAttribute("aria-expanded", status);
51
+ DIALOG?.setAttribute("aria-expanded", status);
52
+ }
53
+
54
+ //+ FN OPEN
55
+ function openModal(e) {
56
+ e?.stopImmediatePropagation();
57
+ if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
58
+ statusModal(true);
59
+ DIALOG.open ? closeModal(e) : topLevel ? DIALOG.showModal() : DIALOG.show();
60
+ // modalCustomEvents('modal:open', { event: e });
61
+ MODAL.dispatchEvent(new CustomEvent('modal:open'));
62
+ DIALOG.dispatchEvent(new CustomEvent('modal:open'));
63
+ }
64
+
65
+ //+ FN CLOSE
66
+ function closeModal(e) {
67
+ e?.stopImmediatePropagation()
68
+ statusModal(false);
69
+ DIALOG.close();
70
+ // modalCustomEvents('modal:close', { event: e });
71
+ MODAL.dispatchEvent(new CustomEvent('modal:close'));
72
+ DIALOG.dispatchEvent(new CustomEvent('modal:close'));
73
+ }
74
+
75
+ //+ fn OPEN ON HISTORY
76
+ function openModalOnHistory() {
77
+ const params = new URLSearchParams(window.location.search);
78
+ if (params.get('modal') !== BUTTON_OPEN.id) return;
79
+ document.getElementById(BUTTON_OPEN.id)?.scrollIntoView({ behavior: 'smooth' });
80
+ openModal();
81
+ }
82
+
83
+
84
+ //= OPEN
85
+ BUTTON_OPEN.addEventListener("click", (e) => openModal(e));
86
+ BUTTON_OPEN.addEventListener("keypress", (e) => !DIALOG.open && (e.key === "Enter" || e.key === " ") && openModal(e));
87
+
88
+ //= CLOSE
89
+ DIALOG.addEventListener("close", () => statusModal(false));
90
+ DIALOG.addEventListener("click", e => { if (e.target == DIALOG && !disableBackdropClose) closeModal(e) });
91
+ BUTTON_CLOSE?.addEventListener("click", e => closeModal(e));
92
+
93
+ //= UPDATE HISTORY
94
+ if (data_history && BUTTON_OPEN.id) {
95
+ setTimeout(openModalOnHistory, 1);
96
+
97
+ //== Aggiorna URL quando cambia l'attributo "open" del dialog
98
+ const obs = new MutationObserver(() => {
99
+ let isOpen = DIALOG.hasAttribute("open");
100
+ try {
101
+ const url = new URL(window.location.href);
102
+ const params = new URLSearchParams(url.search);
103
+ isOpen ? params.set('modal', BUTTON_OPEN.id) : params.delete('modal');
104
+ url.search = params.toString() ? `?${params.toString()}` : "";
105
+ window.history.pushState({ modal: BUTTON_OPEN.id, open: isOpen }, "", url);
106
+ } catch (_) { }
107
+ });
108
+ obs.observe(DIALOG, { attributes: true, attributeFilter: ["open"] });
109
+
110
+ //== Gestisce back/forward del browser per aprire/chiudere il dialog coerentemente
111
+ window.addEventListener("popstate", () => {
112
+ try {
113
+ const params = new URLSearchParams(window.location.search);
114
+ const shouldOpen = params.get('modal') === BUTTON_OPEN.id;
115
+ if (shouldOpen && !DIALOG.open) DIALOG.showModal();
116
+ if (!shouldOpen && DIALOG.open) closeModal()
117
+ } catch (_) { }
118
+ });
119
+ }
120
+ });
121
+ }
122
+
123
+ //# INIT PGS_modal
@@ -0,0 +1,183 @@
1
+ import { PGS_scrollHorizontal } from "../functions/_scrollY"
2
+ const API = new WeakMap();
3
+
4
+ class PGS_Slides {
5
+ //- CONSTRUCTOR
6
+ constructor({ selector, viewRatio = 0.97, optionIntersectionObserver = {}, scrollOptions = {} } = {}) {
7
+ this.selector = selector;
8
+ this.viewRatio = viewRatio;
9
+
10
+ this.optionIntersectionObserver = {
11
+ threshold: Array.from({ length: 101 }, (_, i) => i / 100), // 0%,1%,2%...100%
12
+ rootMargin: "0px",
13
+ ...optionIntersectionObserver,
14
+ };
15
+
16
+ this.scrollOptions = {
17
+ behavior: "smooth",
18
+ inline: "center",
19
+ block: "nearest",
20
+ container: "nearest",
21
+ ...scrollOptions,
22
+ };
23
+
24
+ this.container = this.selector ? pgs(this.selector).querySelector("slides-container") : null;
25
+ }
26
+
27
+ //+ CREATE BUTTON
28
+ #createButtonsAndDots() {
29
+ const EL = this.selector
30
+
31
+ //== PULSANTI
32
+ if (!pgs(EL).querySelector('slides-prec') && !pgs(EL).querySelector('slides-next')) {
33
+ EL.insertAdjacentHTML("afterbegin", `<button pgs="slides-prec button" type="button" class="precButton" aria-label="slide precedente"> <span> <i class="fa-solid fa-arrow-left"></i></span></button>`);
34
+ EL.insertAdjacentHTML("beforeend", `<button pgs="slides-next button" type="button" class="nextButton" aria-label="prossima slide"> <span> <i class="fa-solid fa-arrow-right"></i></span></button>`);
35
+ }
36
+
37
+ //== DOTS
38
+ if (!pgs(EL).querySelector('slides-dots')) {
39
+ EL.insertAdjacentHTML("beforeend", `<div pgs="slides-dots" class="slides-dots"></div>`);
40
+
41
+ Array.from(this.container.children).forEach(() => {
42
+ pgs(EL).querySelector('slides-dots')
43
+ .insertAdjacentHTML("beforeend", `<button type="button" class="slide-dot" aria-label="vai alla prossima slide"></button>`);
44
+ });
45
+ }
46
+ }
47
+
48
+ //+ PREV
49
+ #previousSlide() {
50
+ const currents = this.container.querySelectorAll('.view');
51
+ let current;
52
+
53
+
54
+ if (pgs(this.selector).option.contains('singleScroll')) current = currents[currents.length - 1];
55
+ else current = currents[0];
56
+
57
+ const prev = current?.previousElementSibling;
58
+
59
+ prev?.scrollIntoView(this.scrollOptions);
60
+ prev?.focus({ preventScroll: true });
61
+ }
62
+
63
+ //+ NEXT
64
+ #nextSlide() {
65
+ const currents = this.container.querySelectorAll('.view');
66
+ let current;
67
+
68
+
69
+
70
+ if (pgs(this.selector).option.contains('singleScroll')) current = currents[0];
71
+ else current = currents[currents.length - 1];
72
+
73
+ const next = current?.nextElementSibling;
74
+ console.log(current, next);
75
+
76
+ next?.scrollIntoView(this.scrollOptions);
77
+ next?.focus({ preventScroll: true });
78
+ }
79
+
80
+ //+ GO TO NUMBER SLIDE
81
+ #goToNumberSlide(index) {
82
+ this.container.children[index].scrollIntoView(this.scrollOptions)
83
+ }
84
+
85
+ //+ CALLBACK
86
+ #callback(allLi, container, precButton, nextButton, dots) {
87
+ allLi.forEach(LI => {
88
+ const visiblePercent = 0.9 + LI.intersectionRatio * 0.1;
89
+ const isView = visiblePercent >= 0.98;
90
+
91
+ //== SCROLL ANIMATION
92
+ if (!pgs(LI.target).option.contains('notScrollAnimation')) {
93
+ LI.target.firstElementChild.style.setProperty('--visible-percent', `${visiblePercent}`);
94
+ };
95
+
96
+ //== VIEW & NOT-VIEW
97
+ LI.target.classList.toggle("view", isView);
98
+ LI.target.classList.toggle("notView", !isView);
99
+
100
+ //== VIEW PREC e NEXT
101
+ const all = LI.target.parentNode.children;
102
+ const atStart = all[0].classList.contains("view");
103
+ const atEnd = all[all.length - 1].classList.contains("view");
104
+ nextButton.disabled = atEnd;
105
+ precButton.disabled = atStart;
106
+ nextButton.setAttribute('aria-disabled', String(atEnd));
107
+ precButton.setAttribute('aria-disabled', String(atStart));
108
+
109
+ //== ACTIVE DOT
110
+ const viewElements = Array.from(container.children).filter(el => el.classList.contains('view'));
111
+ dots.forEach((btn, i) => {
112
+ const isActive = viewElements.some(el => Array.from(container.children).indexOf(el) === i);
113
+ btn.classList.toggle('active', isActive);
114
+ btn.setAttribute('aria-current', isActive ? 'true' : 'false');
115
+ });
116
+ })
117
+ }
118
+
119
+ //= EXECUTE
120
+ execute() {
121
+ const slides = this.selector;
122
+ if (!this.container) return
123
+
124
+ //== elements
125
+ this.#createButtonsAndDots();
126
+ const precButton = pgs(slides).querySelector('slides-prec');
127
+ const nextButton = pgs(slides).querySelector('slides-next');
128
+ const dots = Array.from(pgs(slides).querySelector('slides-dots').children);
129
+
130
+ //== option
131
+ const notScrollWithMouse = pgs(slides).option.contains('notScrollWithMouse');
132
+
133
+ //== scroll
134
+ if (!notScrollWithMouse) PGS_scrollHorizontal(this.container, 5);
135
+
136
+ //==Listener: DOT, PREC, NEXT
137
+ dots.forEach((dot, index) => dot.addEventListener("click", e => this.#goToNumberSlide(index)));
138
+ precButton.addEventListener("click", e => this.#previousSlide(), { passive: true });
139
+ nextButton.addEventListener("click", e => this.#nextSlide(), { passive: true });
140
+
141
+ //== observer
142
+ const observer = new IntersectionObserver(
143
+ (allLi) => this.#callback(allLi, this.container, precButton, nextButton, dots),
144
+ { root: this.container, ...this.optionIntersectionObserver }
145
+ );
146
+ Array.from(this.container.children).forEach(allLi => observer.observe(allLi));
147
+
148
+
149
+ //- API
150
+ API.set(this.selector, {
151
+ element: this.selector,
152
+ container: this.container,
153
+ previous: () => this.#previousSlide(),
154
+ next: () => this.#nextSlide(),
155
+ goTo: (index) => this.#goToNumberSlide(index),
156
+ getCurrentIndexes: () => Array.from(this.container.children).map((el, i) => el.classList.contains("view") ? i : -1).filter(i => i !== -1),
157
+ getCurrentElements: () => Array.from(this.container.children).filter(el => el.classList.contains("view")),
158
+ getTotal: () => this.container.children.length,
159
+ isAtStart: () => this.container.children[0]?.classList.contains("view") || false,
160
+ isAtEnd: () => {
161
+ const children = this.container.children;
162
+ const last = children[children.length - 1];
163
+ return last?.classList.contains("view") || false;
164
+ },
165
+ });
166
+ }
167
+ }
168
+ PGS_slides_init();
169
+
170
+ //# INIT
171
+ export function PGS_slides_init(root = document) {
172
+ pgs(root).querySelectorAll("slides").forEach(el => {
173
+ if (API.has(el)) return;
174
+
175
+ const instance = new PGS_Slides({ selector: el });
176
+ instance.execute();
177
+ });
178
+ }
179
+
180
+ //# API
181
+ export function PGS_slides_api(selector) {
182
+ return API.get(selector);
183
+ }
@@ -0,0 +1,27 @@
1
+
2
+ export function PGS_ol() {
3
+ pgs(document).querySelectorAll("steps").forEach(steps => {
4
+
5
+ pgs(steps).querySelectorAll("steps-step").forEach((li, index) => {
6
+
7
+ //= CIRCLE
8
+ let circleLi;
9
+ if (!pgs(li).querySelector("steps-step-circle")) {
10
+ circleLi = document.createElement("span");
11
+ pgs(circleLi).add("steps-step-circle")
12
+ circleLi.textContent = index + 1;
13
+ li.insertAdjacentElement("afterbegin", circleLi);
14
+ } else{
15
+ circleLi = pgs(li).querySelector("steps-step-circle");
16
+ }
17
+
18
+ //= line
19
+ const line = document.createElement("span");
20
+ pgs(line).add("steps-step-line")
21
+ li.insertAdjacentElement("afterbegin", line);
22
+ });
23
+ });
24
+ }
25
+
26
+ //# INIT PGS_ol
27
+ PGS_ol()
@@ -0,0 +1,134 @@
1
+ const API = new WeakMap();
2
+ PGS_tabs()
3
+
4
+ export function PGS_tabs() {
5
+ pgs(document).querySelectorAll("tabs").forEach(tabsWizard => {
6
+
7
+ //= INIT
8
+ // if (tabsWizard.getAttribute("data-initialize") == "true") return;
9
+ // tabsWizard.setAttribute("data-initialize", "true");
10
+
11
+ //= SELECTOR
12
+ const prev = pgs(tabsWizard).querySelector("tabs-prev")
13
+ const next = pgs(tabsWizard).querySelector("tabs-next")
14
+ const restart = pgs(tabsWizard).querySelector("tabs-restart")
15
+ const dots = pgs(tabsWizard).querySelector("tabs-dots")
16
+ const tabsContainer = pgs(tabsWizard).querySelector("tabs-container");
17
+ const allTab = pgs(tabsContainer).querySelectorAll("tab");
18
+
19
+ //= SETTING
20
+ const total = allTab.length;
21
+ const defaultTabLocked = Array.from(allTab).filter(tab => tab.getAttribute("data-tab-locked") === "true")
22
+ let current = 0;
23
+ prev.disabled = true;
24
+
25
+ //- CREAZIONE DOTS
26
+ const tabDots = [];
27
+ if (dots) {
28
+ dots.innerHTML = "";
29
+
30
+ allTab.forEach((tab, index) => {
31
+
32
+ const iconClass = tab.getAttribute("data-tab-icon") || "fa-circle";
33
+
34
+ const dot = document.createElement("button");
35
+ dot.type = "button";
36
+ dot.className = "tab-dot";
37
+ dot.setAttribute("data-step", index);
38
+ dot.innerHTML = `<i class="fa-solid ${iconClass}"></i>`;
39
+
40
+ dot.addEventListener("click", () => {
41
+ if (dot.classList.contains("is-completed")) {
42
+ goTo(index, true);
43
+ }
44
+ });
45
+
46
+ dots.appendChild(dot);
47
+ tabDots.push(dot);
48
+ });
49
+ }
50
+
51
+ //+ DOTS
52
+ function updateDots() {
53
+ tabDots.forEach((dot, i) => {
54
+ dot.classList.toggle("is-active", i === current);
55
+ dot.classList.toggle("is-completed", i < current);
56
+ });
57
+ }
58
+
59
+ //+ Step
60
+ function goTo(index) {
61
+ current = Math.min(Math.max(index, 0), total - 1);
62
+ const tab = allTab[current]
63
+
64
+ prev.disabled = (current === 0);
65
+ next.disabled = (current === total - 1 || tab.getAttribute("data-tab-locked") === "true");
66
+
67
+ allTab.forEach((tab, i) => tab.classList.toggle("is-active", i === current));
68
+ tab?.focus();
69
+ tabsWizard?.scrollIntoView({ behavior: "smooth", block: "start" });
70
+ updateDots();
71
+ tabsWizard.dispatchEvent(new CustomEvent('tabs:change', { detail: { current, total } }));
72
+ }
73
+
74
+ //+ restart
75
+ function restartTab() {
76
+ goTo(0);
77
+ defaultTabLocked.forEach(tab => tab.setAttribute("data-tab-locked", "true"));
78
+ }
79
+
80
+ //= INIT
81
+ goTo(0);
82
+
83
+ //= data-tab-locked
84
+ const observer = new MutationObserver(() => goTo(current));
85
+ allTab?.forEach(tabEl => observer.observe(tabEl, { attributes: true, attributeFilter: ["data-tab-locked"], }));
86
+
87
+
88
+ //= Click su Avanti/Indietro
89
+ prev?.addEventListener("click", e => goTo(current - 1));
90
+ next?.addEventListener("click", e => goTo(current + 1));
91
+ restart?.addEventListener("click", e => restartTab(), { capture: true });
92
+
93
+ //-(API)
94
+ // tabsWizard.addEventListener("tabs:reset", () => restartTab());
95
+ API.set(tabsWizard, {
96
+ restart: restartTab,
97
+ goTo,
98
+ next: () => goTo(current + 1),
99
+ prev: () => goTo(current - 1),
100
+ toggleLock: (step, lock = true) => typeof step === "number" && allTab[step] && (allTab[step].setAttribute("data-tab-locked", lock.toString()), goTo(current)),
101
+ getCurrent: () => current,
102
+ getState: () => ({ current, total }),
103
+ });
104
+ });
105
+ }
106
+
107
+ export function PGS_tabs_api(selector) {
108
+ return API.get(selector);
109
+ }
110
+
111
+
112
+ /*
113
+ / EXAMPLE
114
+ // vai allo step 2
115
+ w.dispatchEvent(new CustomEvent("tabs:go", { detail: { step: 2 } }));
116
+
117
+ // next
118
+ w.dispatchEvent(new CustomEvent("tabs:next"));
119
+
120
+ // prev
121
+ w.dispatchEvent(new CustomEvent("tabs:prev"));
122
+
123
+ // reset a 0 senza relock
124
+ w.dispatchEvent(new CustomEvent("tabs:reset"));
125
+
126
+ // lock step 3
127
+ w.dispatchEvent(new CustomEvent("tabs:toggle-lock", { detail: { step: 3, lock: true } }));
128
+
129
+ // unlock step 3
130
+ w.dispatchEvent(new CustomEvent("tabs:toggle-lock", { detail: { step: 3, lock: false } }));
131
+
132
+ // leggi stato
133
+ w.dispatchEvent(new CustomEvent("tabs:get", { detail: { reply: (state) => console.log(state) } }));
134
+ */