mypgs 1.3.2 → 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.
- package/AI_GUIDELINES.md +353 -0
- package/README.md +483 -53
- package/assets/javascript/_imports.js +12 -11
- package/assets/javascript/_pgs.js +16 -1
- package/assets/javascript/components/_accordion.js +18 -9
- package/assets/javascript/components/_dropdown.js +176 -120
- package/assets/javascript/components/_menu.js +15 -116
- package/assets/javascript/components/_modals.js +0 -1
- package/assets/javascript/components/_notifications.js +2 -3
- package/assets/javascript/components/_slides.js +0 -1
- package/assets/javascript/components/_stepTabs.js +0 -1
- package/assets/javascript/components/_steps.js +0 -1
- package/assets/javascript/patterns/_cookieConsent.js +8 -2
- package/assets/javascript/pgs.d.ts +12 -1
- package/assets/scss/base/_html.scss +23 -1
- package/assets/scss/components/_dropdown.scss +24 -88
- package/assets/scss/components/_menu.scss +129 -15
- package/assets/scss/components/_modals.scss +15 -3
- package/assets/scss/components/_notification.scss +11 -14
- package/assets/scss/components/_tooltip.scss +2 -9
- package/assets/scss/index.scss +0 -1
- package/assets/scss/layout/_gap.scss +7 -1
- package/assets/scss/layout/_layout.scss +0 -12
- package/assets/scss/layout/_pageShell.scss +104 -105
- package/assets/scss/mixin/_mx-form.scss +1 -3
- package/assets/scss/mixin/_mx-responsive.scss +2 -2
- package/assets/scss/mixin/_mx-semantic.scss +0 -60
- package/assets/scss/mixin/mixin.scss +0 -1
- package/assets/scss/patterns/_footer.scss +1 -0
- package/assets/scss/patterns/_header.scss +20 -18
- package/dist/css/index.css +324 -1160
- package/dist/css/index.css.map +1 -1
- package/dist/css/index.min.css +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/javascript/index.js +277 -272
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/index.min.js +1 -1
- package/package.json +1 -1
- package/templates/components/{md-accordion.html → accordion.html} +2 -2
- package/templates/components/dropdown.html +91 -0
- package/templates/components/menu.html +41 -0
- package/templates/components/modal.html +78 -0
- package/templates/components/notification.html +35 -0
- package/templates/components/{md-slides.html → slides.html} +5 -5
- package/templates/components/{md-steps.html → steps.html} +7 -7
- package/templates/components/{md-tooltip.html → tooltip.html} +4 -2
- package/templates/demo.css +18 -0
- package/templates/demo.html +4 -5
- package/templates/demo.js +53 -52
- package/templates/layout/flex.html +89 -0
- package/templates/layout/grid.html +89 -0
- package/templates/layout/pageShell.html +59 -0
- package/templates/layout/section.html +40 -0
- package/templates/{layout/md-footer.html → patterns/footer.html} +1 -0
- package/templates/{layout/md-header.html → patterns/header.html} +6 -9
- package/assets/scss/base/_reset.scss +0 -15
- package/assets/scss/mixin/_mx-menu.scss +0 -154
- package/templates/components/md-dropdown.html +0 -16
- package/templates/components/md-menu.html +0 -40
- package/templates/components/md-modal.html +0 -19
- package/templates/components/md-notification.html +0 -13
- package/templates/layout/md-pageShell.html +0 -22
- package/templates/layout/md-section.html +0 -25
- /package/templates/components/{md-breadcumbs.html → breadcumbs.html} +0 -0
- /package/templates/components/{md-button.html → button.html} +0 -0
- /package/templates/components/{md-card.html → card.html} +0 -0
- /package/templates/components/{md-form.html → form.html} +0 -0
- /package/templates/components/{md-logo.html → logo.html} +0 -0
- /package/templates/components/{md-searchbar.html → searchbar.html} +0 -0
- /package/templates/components/{md-stepTabs.html → stepTabs.html} +0 -0
- /package/templates/components/{md-table.html → table.html} +0 -0
- /package/templates/layout/{md-body.html → body.html} +0 -0
- /package/templates/{layout/md-cookieConsent.html → patterns/cookieConsent.html} +0 -0
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
//= ACCORDION
|
|
2
2
|
const API = new WeakMap();
|
|
3
|
+
let accordionId = 0;
|
|
4
|
+
|
|
5
|
+
function nextAccordionId() {
|
|
6
|
+
accordionId += 1;
|
|
7
|
+
return accordionId;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function directPgsChild(element, token) {
|
|
11
|
+
return Array.from(element.children).find(child => pgs(child).contains(token));
|
|
12
|
+
}
|
|
3
13
|
|
|
4
14
|
export function PGS_accordion_init(root = document) {
|
|
5
|
-
pgs(root).querySelectorAll("accordion").forEach((accordion
|
|
15
|
+
pgs(root).querySelectorAll("accordion").forEach((accordion) => {
|
|
6
16
|
if (API.has(accordion)) return;
|
|
7
17
|
|
|
8
|
-
const BUTTON =
|
|
9
|
-
const CONTENT =
|
|
18
|
+
const BUTTON = directPgsChild(accordion, "accordion-button");
|
|
19
|
+
const CONTENT = directPgsChild(accordion, "accordion-content");
|
|
10
20
|
if (!BUTTON || !CONTENT) return;
|
|
11
21
|
|
|
12
22
|
//== ID univoci per aria-controls / aria-labelledby
|
|
13
|
-
const ID =
|
|
23
|
+
const ID = nextAccordionId();
|
|
14
24
|
const btnId = `acc-btn-${ID}`;
|
|
15
25
|
const panelId = `acc-panel-${ID}`;
|
|
16
26
|
|
|
@@ -20,12 +30,12 @@ export function PGS_accordion_init(root = document) {
|
|
|
20
30
|
//== Accessibilità (setup una volta)
|
|
21
31
|
BUTTON.setAttribute("role", "button");
|
|
22
32
|
BUTTON.setAttribute("tabindex", "0");
|
|
23
|
-
BUTTON.setAttribute("id", btnId);
|
|
24
|
-
BUTTON.setAttribute("aria-controls", panelId);
|
|
33
|
+
if (!BUTTON.id) BUTTON.setAttribute("id", btnId);
|
|
25
34
|
|
|
26
|
-
CONTENT.setAttribute("id", panelId);
|
|
35
|
+
if (!CONTENT.id) CONTENT.setAttribute("id", panelId);
|
|
36
|
+
BUTTON.setAttribute("aria-controls", CONTENT.id);
|
|
27
37
|
CONTENT.setAttribute("role", "region");
|
|
28
|
-
CONTENT.setAttribute("aria-labelledby",
|
|
38
|
+
CONTENT.setAttribute("aria-labelledby", BUTTON.id);
|
|
29
39
|
|
|
30
40
|
//+ Accessibility (applica stato aperto/chiuso)
|
|
31
41
|
function accordionAccessibility(isOpen, button, content) {
|
|
@@ -110,7 +120,6 @@ export function PGS_accordion_api(selector) {
|
|
|
110
120
|
}
|
|
111
121
|
|
|
112
122
|
export const PGS_accordion = {
|
|
113
|
-
PGS_name: "PGS_accordion",
|
|
114
123
|
init: PGS_accordion_init,
|
|
115
124
|
api: PGS_accordion_api
|
|
116
125
|
};
|
|
@@ -1,153 +1,209 @@
|
|
|
1
|
-
// + dropdown
|
|
1
|
+
// + dropdown
|
|
2
2
|
const API = new WeakMap();
|
|
3
|
+
const OPEN_DROPDOWNS = new Set();
|
|
4
|
+
const VIEWPORT_GAP = 8;
|
|
5
|
+
let dropdownId = 0;
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
function nextDropdownId() {
|
|
8
|
+
dropdownId += 1;
|
|
9
|
+
return dropdownId;
|
|
10
|
+
}
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!BUTTON || !CONTENT) return;
|
|
12
|
-
|
|
13
|
-
// = INIT
|
|
14
|
-
if (DROPDOWN.getAttribute("data-initialize") === "true") return;
|
|
15
|
-
DROPDOWN.setAttribute("data-initialize", "true");
|
|
16
|
-
|
|
17
|
-
// == CSS dropdown-anchor
|
|
18
|
-
const ANCHOR_NAME = `--dropdown-anchor-${index}`;
|
|
19
|
-
DROPDOWN.style.setProperty("--dropdown-anchor", ANCHOR_NAME);
|
|
20
|
-
|
|
21
|
-
// == IDs + ACCESSIBILITY
|
|
22
|
-
if (!BUTTON.id) BUTTON.id = `dropdown-btn-${index}`;
|
|
23
|
-
if (!CONTENT.id) CONTENT.id = `dropdown-panel-${index}`;
|
|
24
|
-
BUTTON.setAttribute("type", "button");
|
|
25
|
-
BUTTON.setAttribute("aria-haspopup", "true");
|
|
26
|
-
BUTTON.setAttribute("aria-controls", CONTENT.id);
|
|
27
|
-
BUTTON.setAttribute("aria-expanded", "false");
|
|
28
|
-
CONTENT.setAttribute("aria-labelledby", BUTTON.id);
|
|
29
|
-
|
|
30
|
-
// == POPVER SETUP
|
|
31
|
-
if (!CONTENT.hasAttribute("popover")) CONTENT.setAttribute("popover", "auto");
|
|
32
|
-
BUTTON.setAttribute("popovertarget", CONTENT.id);
|
|
33
|
-
BUTTON.setAttribute("popovertargetaction", "toggle");
|
|
34
|
-
|
|
35
|
-
//-( Safari / legacy fallback: popover is in the top layer, so fixed coords are viewport-based.
|
|
36
|
-
const HAS_ANCHOR_POSITIONING =
|
|
37
|
-
CSS.supports("anchor-name: --dropdown-anchor") &&
|
|
38
|
-
CSS.supports("position-anchor: --dropdown-anchor") &&
|
|
39
|
-
CSS.supports("position-area: bottom") &&
|
|
40
|
-
CSS.supports("top: anchor(bottom)");
|
|
41
|
-
const USE_FALLBACK_POSITIONING = pgs(DROPDOWN).contains("tooltip") || !HAS_ANCHOR_POSITIONING;
|
|
42
|
-
|
|
43
|
-
const updatePopoverPosition = () => {
|
|
44
|
-
if (!USE_FALLBACK_POSITIONING) return;
|
|
45
|
-
|
|
46
|
-
const buttonRect = BUTTON.getBoundingClientRect();
|
|
47
|
-
const style = getComputedStyle(DROPDOWN);
|
|
48
|
-
const offset = parseFloat(style.getPropertyValue("--dropdown-offset")) || 10;
|
|
49
|
-
const padding = parseFloat(style.getPropertyValue("--dropdown-padding")) || 0;
|
|
50
|
-
const arrowSize = parseFloat(style.getPropertyValue("--dropdown-arrow-size")) || 12;
|
|
51
|
-
const viewportGap = 8;
|
|
52
|
-
const viewportWidth = window.innerWidth;
|
|
53
|
-
const maxWidth = viewportWidth - viewportGap * 2;
|
|
54
|
-
const contentStyle = getComputedStyle(CONTENT);
|
|
55
|
-
const cssMaxWidth = parseFloat(contentStyle.maxWidth);
|
|
56
|
-
const dropdownMaxWidth = Number.isFinite(cssMaxWidth) ? Math.min(cssMaxWidth, maxWidth) : maxWidth;
|
|
57
|
-
const contentWidth = Math.min(
|
|
58
|
-
Math.max(CONTENT.scrollWidth + padding * 2, buttonRect.width),
|
|
59
|
-
dropdownMaxWidth
|
|
60
|
-
);
|
|
61
|
-
const top = buttonRect.bottom + offset;
|
|
62
|
-
const centeredLeft = buttonRect.left + buttonRect.width / 2 - contentWidth / 2;
|
|
63
|
-
const left = Math.min(
|
|
64
|
-
Math.max(centeredLeft, viewportGap),
|
|
65
|
-
viewportWidth - contentWidth - viewportGap
|
|
66
|
-
);
|
|
67
|
-
const buttonCenter = buttonRect.left + buttonRect.width / 2;
|
|
68
|
-
const arrowLeft = Math.min(
|
|
69
|
-
Math.max(buttonCenter - left, padding + arrowSize),
|
|
70
|
-
contentWidth - padding - arrowSize
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
DROPDOWN.style.setProperty("--dropdown-fallback-top", `${top}px`);
|
|
74
|
-
DROPDOWN.style.setProperty("--dropdown-fallback-left", `${left}px`);
|
|
75
|
-
DROPDOWN.style.setProperty("--dropdown-arrow-left", `${arrowLeft}px`);
|
|
76
|
-
};
|
|
12
|
+
function isDropdownContent(element) {
|
|
13
|
+
return element instanceof Element && pgs(element).contains("dropdown-content");
|
|
14
|
+
}
|
|
77
15
|
|
|
78
|
-
|
|
79
|
-
|
|
16
|
+
function getDropdownTrigger(dropdown, content) {
|
|
17
|
+
const children = Array.from(dropdown.children).filter(child => child !== content);
|
|
18
|
+
const dropdownButton = children.find(child => pgs(child).contains("dropdown-button"));
|
|
80
19
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
CONTENT.hidePopover();
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
20
|
+
return dropdownButton || children.find(child => !isDropdownContent(child)) || dropdown;
|
|
21
|
+
}
|
|
86
22
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
23
|
+
function getDropdownContent(dropdown) {
|
|
24
|
+
return Array.from(dropdown.children).find(isDropdownContent) || pgs(dropdown).querySelector("dropdown-content");
|
|
25
|
+
}
|
|
90
26
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (open) {
|
|
97
|
-
updatePopoverPosition();
|
|
98
|
-
CONTENT.querySelector('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])')?.focus();
|
|
99
|
-
}
|
|
100
|
-
});
|
|
27
|
+
function getDropdowns(root) {
|
|
28
|
+
const dropdowns = root instanceof Element && pgs(root).contains("dropdown") ? [root] : [];
|
|
29
|
+
dropdowns.push(...pgs(root).querySelectorAll("dropdown"));
|
|
30
|
+
return dropdowns;
|
|
31
|
+
}
|
|
101
32
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
function open() {
|
|
110
|
-
if (CONTENT.matches(":popover-open")) return;
|
|
111
|
-
updatePopoverPosition();
|
|
112
|
-
CONTENT.showPopover();
|
|
113
|
-
}
|
|
33
|
+
function getposition(dropdown) {
|
|
34
|
+
const option = pgs(dropdown).option;
|
|
35
|
+
const optionValue = option.getValueBrackets("position");
|
|
36
|
+
const raw = (optionValue || "bottom center").trim().toLowerCase();
|
|
37
|
+
const parts = raw.split(/\s+/).filter(Boolean);
|
|
38
|
+
const side = parts.find(part => ["top", "right", "bottom", "left"].includes(part)) || "bottom";
|
|
39
|
+
const align = parts.find(part => ["top", "right", "bottom", "left", "center"].includes(part) && part !== side) || "center";
|
|
114
40
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
41
|
+
return { side, align };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function clamp(value, min, max) {
|
|
45
|
+
return Math.min(Math.max(value, min), max);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function updateposition(dropdown) {
|
|
49
|
+
const data = API.get(dropdown);
|
|
50
|
+
if (!data || !data.isOpen()) return;
|
|
51
|
+
|
|
52
|
+
const { trigger, content } = data;
|
|
53
|
+
const { side, align } = getposition(dropdown);
|
|
54
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
55
|
+
const contentRect = content.getBoundingClientRect();
|
|
56
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
57
|
+
const maxLeft = Math.max(VIEWPORT_GAP, viewportWidth - contentRect.width - VIEWPORT_GAP);
|
|
58
|
+
let left = triggerRect.left + (triggerRect.width - contentRect.width) / 2;
|
|
59
|
+
let top = triggerRect.bottom + VIEWPORT_GAP;
|
|
60
|
+
|
|
61
|
+
if (side === "top" || side === "bottom") {
|
|
62
|
+
top = side === "top"
|
|
63
|
+
? triggerRect.top - contentRect.height - VIEWPORT_GAP
|
|
64
|
+
: triggerRect.bottom + VIEWPORT_GAP;
|
|
65
|
+
|
|
66
|
+
if (align === "left") left = triggerRect.left;
|
|
67
|
+
if (align === "right") left = triggerRect.right - contentRect.width;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (side === "left" || side === "right") {
|
|
71
|
+
left = side === "left"
|
|
72
|
+
? triggerRect.left - contentRect.width - VIEWPORT_GAP
|
|
73
|
+
: triggerRect.right + VIEWPORT_GAP;
|
|
74
|
+
top = triggerRect.top + (triggerRect.height - contentRect.height) / 2;
|
|
75
|
+
|
|
76
|
+
if (align === "top") top = triggerRect.top;
|
|
77
|
+
if (align === "bottom") top = triggerRect.bottom - contentRect.height;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (side === "left" && left < VIEWPORT_GAP) {
|
|
81
|
+
left = triggerRect.right + VIEWPORT_GAP;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (side === "right" && left + contentRect.width > viewportWidth - VIEWPORT_GAP) {
|
|
85
|
+
left = triggerRect.left - contentRect.width - VIEWPORT_GAP;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
left = clamp(left, VIEWPORT_GAP, maxLeft);
|
|
89
|
+
|
|
90
|
+
content.style.setProperty("--dropdown-left", `${Math.round(left)}px`);
|
|
91
|
+
content.style.setProperty("--dropdown-top", `${Math.round(top)}px`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function updateOpenDropdowns() {
|
|
95
|
+
OPEN_DROPDOWNS.forEach(updateposition);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function closeDropdown(dropdown) {
|
|
99
|
+
const data = API.get(dropdown);
|
|
100
|
+
if (!data || !data.isOpen()) return;
|
|
101
|
+
|
|
102
|
+
pgs(dropdown).state.remove("open");
|
|
103
|
+
data.trigger.setAttribute("aria-expanded", "false");
|
|
104
|
+
OPEN_DROPDOWNS.delete(dropdown);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function openDropdown(dropdown) {
|
|
108
|
+
const data = API.get(dropdown);
|
|
109
|
+
if (!data || data.isOpen()) return;
|
|
119
110
|
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
OPEN_DROPDOWNS.forEach(item => {
|
|
112
|
+
if (item !== dropdown) closeDropdown(item);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
pgs(dropdown).state.add("open");
|
|
116
|
+
data.trigger.setAttribute("aria-expanded", "true");
|
|
117
|
+
OPEN_DROPDOWNS.add(dropdown);
|
|
118
|
+
updateposition(dropdown);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function toggleDropdown(dropdown) {
|
|
122
|
+
const data = API.get(dropdown);
|
|
123
|
+
if (!data) return;
|
|
124
|
+
|
|
125
|
+
if (data.isOpen()) closeDropdown(dropdown);
|
|
126
|
+
else openDropdown(dropdown);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function isInsideAnyDropdown(target) {
|
|
130
|
+
return Array.from(OPEN_DROPDOWNS).some(dropdown => dropdown.contains(target));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function PGS_dropdown_init(root = document) {
|
|
134
|
+
getDropdowns(root).forEach((DROPDOWN) => {
|
|
135
|
+
if (API.has(DROPDOWN)) return;
|
|
136
|
+
|
|
137
|
+
const CONTENT = getDropdownContent(DROPDOWN);
|
|
138
|
+
if (!CONTENT) return;
|
|
139
|
+
|
|
140
|
+
const TRIGGER = getDropdownTrigger(DROPDOWN, CONTENT);
|
|
141
|
+
const id = nextDropdownId();
|
|
142
|
+
|
|
143
|
+
if (!TRIGGER.id) TRIGGER.id = `dropdown-btn-${id}`;
|
|
144
|
+
if (!CONTENT.id) CONTENT.id = `dropdown-panel-${id}`;
|
|
145
|
+
|
|
146
|
+
if (TRIGGER.matches("button") && !TRIGGER.hasAttribute("type")) {
|
|
147
|
+
TRIGGER.setAttribute("type", "button");
|
|
122
148
|
}
|
|
123
149
|
|
|
124
|
-
|
|
150
|
+
TRIGGER.setAttribute("aria-haspopup", "true");
|
|
151
|
+
TRIGGER.setAttribute("aria-controls", CONTENT.id);
|
|
152
|
+
TRIGGER.setAttribute("aria-expanded", String(pgs(DROPDOWN).state.contains("open")));
|
|
153
|
+
CONTENT.setAttribute("aria-labelledby", TRIGGER.id);
|
|
154
|
+
|
|
155
|
+
const data = {
|
|
125
156
|
element: DROPDOWN,
|
|
126
|
-
|
|
157
|
+
trigger: TRIGGER,
|
|
127
158
|
content: CONTENT,
|
|
128
|
-
open,
|
|
129
|
-
close,
|
|
130
|
-
toggle,
|
|
131
|
-
updatePosition: updatePopoverPosition,
|
|
159
|
+
open: () => openDropdown(DROPDOWN),
|
|
160
|
+
close: () => closeDropdown(DROPDOWN),
|
|
161
|
+
toggle: () => toggleDropdown(DROPDOWN),
|
|
132
162
|
refresh: () => {
|
|
133
163
|
PGS_dropdown_init(DROPDOWN.parentNode || document);
|
|
164
|
+
updateposition(DROPDOWN);
|
|
134
165
|
return API.get(DROPDOWN);
|
|
135
166
|
},
|
|
136
|
-
isOpen: () =>
|
|
167
|
+
isOpen: () => pgs(DROPDOWN).state.contains("open")
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
TRIGGER.addEventListener("click", (event) => {
|
|
171
|
+
if (isDropdownContent(event.target)) return;
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
event.stopPropagation();
|
|
174
|
+
toggleDropdown(DROPDOWN);
|
|
137
175
|
});
|
|
176
|
+
|
|
177
|
+
CONTENT.addEventListener("click", event => event.stopPropagation());
|
|
178
|
+
API.set(DROPDOWN, data);
|
|
179
|
+
|
|
180
|
+
if (data.isOpen()) OPEN_DROPDOWNS.add(DROPDOWN);
|
|
181
|
+
updateposition(DROPDOWN);
|
|
138
182
|
});
|
|
139
183
|
}
|
|
140
184
|
|
|
185
|
+
document.addEventListener("click", (event) => {
|
|
186
|
+
if (isInsideAnyDropdown(event.target)) return;
|
|
187
|
+
OPEN_DROPDOWNS.forEach(closeDropdown);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
document.addEventListener("keydown", (event) => {
|
|
191
|
+
if (event.key !== "Escape") return;
|
|
192
|
+
OPEN_DROPDOWNS.forEach(closeDropdown);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
window.addEventListener("resize", updateOpenDropdowns);
|
|
196
|
+
window.addEventListener("scroll", updateOpenDropdowns, true);
|
|
197
|
+
|
|
141
198
|
// # INIT
|
|
142
199
|
PGS_dropdown_init();
|
|
143
200
|
|
|
144
201
|
// # API
|
|
145
|
-
|
|
202
|
+
function PGS_dropdown_api(selector) {
|
|
146
203
|
return API.get(selector);
|
|
147
204
|
}
|
|
148
205
|
|
|
149
206
|
export const PGS_dropdown = {
|
|
150
|
-
PGS_name: "PGS_dropdown",
|
|
151
207
|
init: PGS_dropdown_init,
|
|
152
208
|
api: PGS_dropdown_api
|
|
153
209
|
};
|
|
@@ -1,157 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PGS_dropdown } from "./_dropdown";
|
|
2
2
|
|
|
3
3
|
const API = new WeakMap();
|
|
4
4
|
|
|
5
5
|
//= DROP DOWN MENU
|
|
6
|
-
|
|
6
|
+
function PGS_menu_init(root = document) {
|
|
7
7
|
|
|
8
|
-
pgs(root).querySelectorAll('menu
|
|
8
|
+
pgs(root).querySelectorAll('menu').forEach(MENU => {
|
|
9
9
|
if (API.has(MENU)) return;
|
|
10
10
|
|
|
11
|
-
MENU.querySelectorAll('
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
MENU.querySelectorAll('li').forEach(li => {
|
|
12
|
+
const ul = li.querySelector("ul");
|
|
13
|
+
|
|
14
|
+
if (ul) {
|
|
15
15
|
|
|
16
16
|
const button = document.createElement("button");
|
|
17
|
-
button.className = "icon-down";
|
|
18
17
|
button.type = "button";
|
|
19
18
|
button.innerHTML = "<span>⏷</span>";
|
|
19
|
+
pgs(button).add("menu-buttonIcon");
|
|
20
20
|
li.querySelector("a").insertAdjacentElement("afterend", button);
|
|
21
21
|
|
|
22
22
|
pgs(li).add("dropdown")
|
|
23
23
|
pgs(button).add("dropdown-button")
|
|
24
24
|
pgs(button).add("buttonNohover")
|
|
25
25
|
pgs(ul).add("dropdown-content")
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
API.set(MENU, {
|
|
31
31
|
element: MENU,
|
|
32
32
|
type: "horizontal",
|
|
33
|
-
items: () => Array.from(MENU.querySelectorAll('nav > ul > li')),
|
|
34
|
-
submenus: () => Array.from(MENU.querySelectorAll('.menu-item-has-children > ul')),
|
|
35
|
-
dropdowns: () => Array.from(MENU.querySelectorAll('.menu-item-has-children')).map(PGS_dropdown_api).filter(Boolean),
|
|
33
|
+
// items: () => Array.from(MENU.querySelectorAll('nav > ul > li')),
|
|
34
|
+
// submenus: () => Array.from(MENU.querySelectorAll('.menu-item-has-children > ul')),
|
|
35
|
+
// dropdowns: () => Array.from(MENU.querySelectorAll('.menu-item-has-children')).map(PGS_dropdown_api).filter(Boolean),
|
|
36
36
|
refresh: () => {
|
|
37
37
|
PGS_menu_init(MENU.parentNode || document);
|
|
38
38
|
return API.get(MENU);
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
|
+
PGS_dropdown.init(MENU);
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
pgs(root).querySelectorAll('menu-vertical').forEach(MENU => {
|
|
44
|
-
if (API.has(MENU)) return;
|
|
45
|
-
|
|
46
|
-
MENU.querySelectorAll('.menu-item-has-children').forEach((li, index) => {
|
|
47
|
-
const ul = li.querySelector("ul");
|
|
48
|
-
|
|
49
|
-
if (!ul) return
|
|
50
|
-
if (li.querySelector(":scope > button")) return;
|
|
51
|
-
|
|
52
|
-
const button = document.createElement("button");
|
|
53
|
-
button.className = "icon-down buttonIcon";
|
|
54
|
-
button.type = "button";
|
|
55
|
-
|
|
56
|
-
// ID unico per aria-controls
|
|
57
|
-
const submenuId = `vertical-submenu-${index}`;
|
|
58
|
-
ul.id = submenuId;
|
|
59
|
-
|
|
60
|
-
// Stato iniziale
|
|
61
|
-
pgs(button).add("buttonIcon")
|
|
62
|
-
button.setAttribute("aria-expanded", "false");
|
|
63
|
-
button.setAttribute("aria-controls", submenuId);
|
|
64
|
-
button.setAttribute("aria-label", "Apri sottomenu");
|
|
65
|
-
button.innerHTML = "<span aria-hidden='true'>⏷</span>";
|
|
66
|
-
li.querySelector("a").insertAdjacentElement("afterend", button);
|
|
67
|
-
|
|
68
|
-
function toggleMenu() {
|
|
69
|
-
// const isOpena = ul.classList.toggle("open");
|
|
70
|
-
const isOpen = pgs(ul).state.toggle("open");
|
|
71
|
-
button.setAttribute("aria-expanded", isOpen);
|
|
72
|
-
button.setAttribute("aria-label", isOpen ? "Chiudi sottomenu" : "Apri sottomenu");
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// Click
|
|
76
|
-
button.addEventListener("click", toggleMenu);
|
|
77
|
-
button.addEventListener("keydown", (e) => {
|
|
78
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
79
|
-
e.preventDefault();
|
|
80
|
-
toggleMenu();
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
function submenu(index) {
|
|
86
|
-
return MENU.querySelectorAll('.menu-item-has-children > ul')[index];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function setSubmenu(index, open) {
|
|
90
|
-
const ul = submenu(index);
|
|
91
|
-
const button = ul?.parentElement?.querySelector(":scope > button");
|
|
92
|
-
if (!ul || !button) return;
|
|
93
|
-
|
|
94
|
-
pgs(ul).state.toggle("open", open);
|
|
95
|
-
button.setAttribute("aria-expanded", String(open));
|
|
96
|
-
button.setAttribute("aria-label", open ? "Chiudi sottomenu" : "Apri sottomenu");
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
API.set(MENU, {
|
|
100
|
-
element: MENU,
|
|
101
|
-
type: "vertical",
|
|
102
|
-
items: () => Array.from(MENU.querySelectorAll(':scope > li')),
|
|
103
|
-
submenus: () => Array.from(MENU.querySelectorAll('.menu-item-has-children > ul')),
|
|
104
|
-
openSubmenu: (index) => setSubmenu(index, true),
|
|
105
|
-
closeSubmenu: (index) => setSubmenu(index, false),
|
|
106
|
-
toggleSubmenu: (index) => {
|
|
107
|
-
const ul = submenu(index);
|
|
108
|
-
if (!ul) return;
|
|
109
|
-
setSubmenu(index, !pgs(ul).state.contains("open"));
|
|
110
|
-
},
|
|
111
|
-
isSubmenuOpen: (index) => {
|
|
112
|
-
const ul = submenu(index);
|
|
113
|
-
return ul ? pgs(ul).state.contains("open") : false;
|
|
114
|
-
},
|
|
115
|
-
refresh: () => {
|
|
116
|
-
PGS_menu_init(MENU.parentNode || document);
|
|
117
|
-
return API.get(MENU);
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
|
|
122
|
-
|
|
123
|
-
// MENU.querySelectorAll('.menu-item-has-children').forEach(li => {
|
|
124
|
-
// if (li.querySelector("ul")) {
|
|
125
|
-
// const ul = li.querySelector("ul");
|
|
126
|
-
|
|
127
|
-
// const button = document.createElement("button");
|
|
128
|
-
// button.className = "icon-down";
|
|
129
|
-
// button.type = "button";
|
|
130
|
-
// button.innerHTML = "<span>⏷</span>";
|
|
131
|
-
// li.querySelector("a").insertAdjacentElement("afterend", button);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// pgs(button).add("buttonIcon")
|
|
135
|
-
// button.addEventListener("click", () => {
|
|
136
|
-
// ul.classList.toggle("open")
|
|
137
|
-
// })
|
|
138
|
-
// }
|
|
139
|
-
// });
|
|
140
|
-
// });
|
|
141
|
-
});
|
|
142
|
-
PGS_dropdown_init()
|
|
143
44
|
}
|
|
144
45
|
|
|
145
|
-
//# INIT PGS_menu
|
|
146
46
|
PGS_menu_init()
|
|
147
47
|
|
|
148
|
-
|
|
149
|
-
export function PGS_menu_api(selector) {
|
|
48
|
+
function PGS_menu_api(selector) {
|
|
150
49
|
return API.get(selector);
|
|
151
50
|
}
|
|
152
51
|
|
|
52
|
+
//# EXPORT
|
|
153
53
|
export const PGS_menu = {
|
|
154
|
-
PGS_name: "PGS_menu",
|
|
155
54
|
init: PGS_menu_init,
|
|
156
55
|
api: PGS_menu_api
|
|
157
56
|
};
|
|
@@ -139,17 +139,16 @@ export function PGS_notificationTrigger_init(root = document) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
export const PGS_notification = {
|
|
142
|
-
PGS_name: "PGS_notification",
|
|
143
142
|
trigger: PGS_notificationTrigger_init,
|
|
144
143
|
alert: {
|
|
145
|
-
error: (text = "Errore", link = null, timeout = 0, icon = '<i class="fa-solid fa-
|
|
144
|
+
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),
|
|
146
145
|
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),
|
|
147
146
|
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),
|
|
148
147
|
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),
|
|
149
148
|
deleteAll: () => fn_notification.deleteAll("notification")
|
|
150
149
|
},
|
|
151
150
|
toast: {
|
|
152
|
-
error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-
|
|
151
|
+
error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-circle-xmark"></i>',) => fn_notification.initNotification("error", "toast", icon, text, timeout),
|
|
153
152
|
success: (text = "Aggiornato", timeout = 4000, icon = '<i class="fa-solid fa-check"></i>',) => fn_notification.initNotification("success", "toast", icon, text, timeout),
|
|
154
153
|
info: (text = "Aggiornamento", timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => fn_notification.initNotification("info", "toast", icon, text, timeout),
|
|
155
154
|
warning: (text = "Attenzione", timeout = 4000, icon = '<i class="fa-solid fa-triangle-exclamation"></i>',) => fn_notification.initNotification("warning", "toast", icon, text, timeout),
|
|
@@ -96,7 +96,7 @@ function assignCookieRuntimeAttributes({ root, analyticsToggle, acceptAllButton,
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
//= CookieConsent
|
|
99
|
-
|
|
99
|
+
function initCookieConsent() {
|
|
100
100
|
const root = pgs(document).querySelector('cookieConsent');
|
|
101
101
|
if (!root) return;
|
|
102
102
|
|
|
@@ -206,4 +206,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
206
206
|
} else {
|
|
207
207
|
setBannerVisibility(true);
|
|
208
208
|
}
|
|
209
|
-
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (document.readyState === 'loading') {
|
|
212
|
+
document.addEventListener('DOMContentLoaded', initCookieConsent);
|
|
213
|
+
} else {
|
|
214
|
+
initCookieConsent();
|
|
215
|
+
}
|
|
@@ -31,7 +31,6 @@ declare global {
|
|
|
31
31
|
value: string | null;
|
|
32
32
|
state: PgsStateApi;
|
|
33
33
|
option: PgsOptionApi;
|
|
34
|
-
modules: PgsOptionApi;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
interface PgsDocumentApi extends PgsQueryableApi {
|
|
@@ -45,7 +44,19 @@ declare global {
|
|
|
45
44
|
(root: Element): PgsElementApi;
|
|
46
45
|
(root: Document | Element): PgsApi;
|
|
47
46
|
registerImport(...modules: unknown[]): PgsFunction;
|
|
47
|
+
registerModules(modules: Record<string, any>): PgsFunction;
|
|
48
48
|
import(...names: string[]): Record<string, any>;
|
|
49
|
+
accordion?: any;
|
|
50
|
+
dropdown?: any;
|
|
51
|
+
menu?: any;
|
|
52
|
+
modal?: any;
|
|
53
|
+
notification?: any;
|
|
54
|
+
slides?: any;
|
|
55
|
+
stepTabs?: any;
|
|
56
|
+
steps?: any;
|
|
57
|
+
formValidate?: any;
|
|
58
|
+
scrollHorizontal?: any;
|
|
59
|
+
[moduleName: string]: any;
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
interface PgsBag extends PgsElementApi {}
|