mypgs 1.6.0 → 2.1.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.
- package/AGENTS.md +2 -2
- package/README.md +25 -25
- package/assets/javascript/components/_accordion.js +2 -2
- package/assets/javascript/components/_modals.js +159 -136
- package/assets/javascript/components/_notifications.js +19 -9
- package/assets/javascript/components/_search.js +2 -2
- package/assets/javascript/components/_slides.js +66 -32
- package/assets/javascript/components/_stepTabs.js +4 -4
- package/assets/javascript/components/_steps.js +2 -2
- package/assets/javascript/components/_summary.js +2 -2
- package/assets/javascript/functions/_formValidate.js +97 -53
- package/assets/javascript/functions/_scrollY.js +10 -10
- package/assets/javascript/layout/_header.js +3 -0
- package/assets/scss/base/_html.scss +2 -2
- package/assets/scss/base/_variables.scss +2 -2
- package/assets/scss/components/_accordion.scss +0 -2
- package/assets/scss/components/_button.scss +1 -1
- package/assets/scss/components/_form.scss +2 -18
- package/assets/scss/components/_formAddon.scss +18 -0
- package/assets/scss/components/_modals.scss +5 -3
- package/assets/scss/components/_notification.scss +23 -30
- package/assets/scss/components/_search.scss +29 -23
- package/assets/scss/components/_slides.scss +0 -1
- package/assets/scss/components/_tooltip.scss +0 -1
- package/assets/scss/index.scss +1 -0
- package/assets/scss/layout/_footer.scss +0 -2
- package/assets/scss/layout/_header.scss +9 -1
- package/assets/scss/layout/_pageShell.scss +24 -17
- package/assets/scss/mixin/_mx-button.scss +30 -76
- package/assets/scss/mixin/_mx-card.scss +11 -9
- package/assets/scss/mixin/_mx-form.scss +10 -12
- package/assets/scss/mixin/{_mx-form-addon.scss → _mx-formAddon.scss} +23 -26
- package/assets/scss/mixin/_mx-hover.scss +75 -0
- package/assets/scss/mixin/_settings.scss +2 -1
- package/assets/scss/mixin/mixin.scss +2 -1
- package/{templates/html → demo}/demo.html +1 -1
- package/demo/demo.js +241 -0
- package/dist/css/index.css +1317 -1674
- package/dist/css/index.css.map +1 -1
- package/dist/css/index.min.css +1 -1
- package/dist/javascript/index.js +356 -255
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/index.min.js +1 -1
- package/docs/componenti-e-markup.md +32 -32
- package/docs/components/accordion.md +61 -0
- package/docs/components/badges.md +67 -0
- package/docs/components/breadcumbs.md +43 -0
- package/docs/components/button.md +59 -0
- package/docs/components/card.md +50 -0
- package/docs/components/dropdown.md +135 -0
- package/docs/components/form.md +136 -0
- package/docs/components/formAddon.md +79 -0
- package/docs/components/logo.md +36 -0
- package/docs/components/menu.md +90 -0
- package/docs/components/modal.md +131 -0
- package/docs/components/notification.md +81 -0
- package/docs/components/search.md +118 -0
- package/docs/components/slides.md +85 -0
- package/docs/components/stepTabs.md +93 -0
- package/docs/components/steps.md +56 -0
- package/docs/components/summary.md +49 -0
- package/docs/components/table.md +42 -0
- package/docs/components/tooltip.md +53 -0
- package/docs/convenzioni.md +11 -11
- package/docs/export-e-sviluppo.md +3 -3
- package/docs/helper-javascript.md +73 -8
- package/docs/layout/body.md +41 -0
- package/docs/layout/flex.md +116 -0
- package/docs/layout/footer.md +71 -0
- package/docs/layout/grid.md +116 -0
- package/docs/layout/header.md +116 -0
- package/docs/layout/pageShell.md +94 -0
- package/docs/layout/section.md +69 -0
- package/docs/patterns/cookieConsent.md +89 -0
- package/docs/utilizzo-css-scss.md +8 -8
- package/package.json +2 -1
- package/scripts/generate-component-docs.js +557 -0
- package/templates/html/components/accordion.html +36 -7
- package/templates/html/components/badges.html +28 -5
- package/templates/html/components/breadcumbs.html +15 -1
- package/templates/html/components/button.html +28 -6
- package/templates/html/components/card.html +28 -8
- package/templates/html/components/dropdown.html +42 -8
- package/templates/html/components/form.html +110 -9
- package/templates/html/components/formAddon.html +72 -0
- package/templates/html/components/logo.html +22 -1
- package/templates/html/components/menu.html +33 -6
- package/templates/html/components/modal.html +58 -14
- package/templates/html/components/notification.html +68 -32
- package/templates/html/components/search.html +85 -8
- package/templates/html/components/slides.html +46 -3
- package/templates/html/components/stepTabs.html +55 -8
- package/templates/html/components/steps.html +24 -0
- package/templates/html/components/summary.html +30 -3
- package/templates/html/components/table.html +14 -2
- package/templates/html/components/tooltip.html +35 -0
- package/templates/html/layout/body.html +20 -6
- package/templates/html/layout/flex.html +53 -33
- package/templates/html/layout/footer.html +32 -4
- package/templates/html/layout/grid.html +53 -33
- package/templates/html/layout/header.html +47 -6
- package/templates/html/layout/pageShell.html +19 -0
- package/templates/html/layout/section.html +41 -19
- package/templates/html/patterns/cookieConsent.html +44 -13
- package/templates/react/components/accordion.jsx +4 -4
- package/templates/react/components/breadcumbs.jsx +1 -1
- package/templates/react/components/button.jsx +5 -5
- package/templates/react/components/card.jsx +4 -4
- package/templates/react/components/dropdown.jsx +8 -8
- package/templates/react/components/form.jsx +5 -5
- package/templates/react/components/modal.jsx +14 -14
- package/templates/react/components/notification.jsx +7 -7
- package/templates/react/components/search.jsx +5 -5
- package/templates/react/components/slides.jsx +3 -3
- package/templates/react/components/stepTabs.jsx +8 -8
- package/templates/react/components/summary.jsx +3 -3
- package/templates/react/components/table.jsx +2 -2
- package/templates/react/layout/flex.jsx +8 -8
- package/templates/react/layout/grid.jsx +8 -8
- package/templates/react/layout/section.jsx +12 -12
- package/templates/react/patterns/cookieConsent.jsx +8 -8
- package/templates/react/patterns/footer.jsx +4 -4
- package/templates/react/patterns/header.jsx +3 -3
- package/templates/html/demo.js +0 -130
- /package/{templates/html → demo}/demo.css +0 -0
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { PGS_scrollHorizontal } from "../functions/_scrollY"
|
|
1
|
+
import { PGS_scrollHorizontal } from "../functions/_scrollY.js";
|
|
2
2
|
const API = new WeakMap();
|
|
3
3
|
|
|
4
|
+
function getSlides(root) {
|
|
5
|
+
const slides = root instanceof Element && pgs(root).contains("slides") ? [root] : [];
|
|
6
|
+
slides.push(...pgs(root).querySelectorAll("slides"));
|
|
7
|
+
return slides;
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
class PGS_Slides {
|
|
5
11
|
//- CONSTRUCTOR
|
|
6
|
-
constructor({
|
|
7
|
-
this.
|
|
12
|
+
constructor({ element, viewRatio = 0.97, optionIntersectionObserver = {}, scrollOptions = {} } = {}) {
|
|
13
|
+
this.element = element;
|
|
8
14
|
this.viewRatio = viewRatio;
|
|
9
15
|
|
|
10
16
|
this.optionIntersectionObserver = {
|
|
@@ -21,28 +27,36 @@ class PGS_Slides {
|
|
|
21
27
|
...scrollOptions,
|
|
22
28
|
};
|
|
23
29
|
|
|
24
|
-
this.container = this.
|
|
30
|
+
this.container = this.element ? pgs(this.element).querySelector("slides-container") : null;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
//+ CREATE BUTTON
|
|
28
34
|
#createButtonsAndDots() {
|
|
29
|
-
const EL = this.
|
|
35
|
+
const EL = this.element;
|
|
30
36
|
|
|
31
37
|
//== PULSANTI
|
|
32
|
-
if (!pgs(EL).querySelector('slides-prec')
|
|
38
|
+
if (!pgs(EL).querySelector('slides-prec')) {
|
|
33
39
|
EL.insertAdjacentHTML("afterbegin", `<button pgs="slides-prec buttonIcon" type="button" class="precButton" aria-label="slide precedente"> <span> <i class="fa-solid fa-arrow-left"></i></span></button>`);
|
|
40
|
+
}
|
|
41
|
+
if (!pgs(EL).querySelector('slides-next')) {
|
|
34
42
|
EL.insertAdjacentHTML("beforeend", `<button pgs="slides-next buttonIcon" type="button" class="nextButton" aria-label="prossima slide"> <span> <i class="fa-solid fa-arrow-right"></i></span></button>`);
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
//== DOTS
|
|
38
46
|
if (!pgs(EL).querySelector('slides-dots')) {
|
|
39
47
|
EL.insertAdjacentHTML("beforeend", `<div pgs="slides-dots" class="slides-dots"></div>`);
|
|
48
|
+
}
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
const dotsContainer = pgs(EL).querySelector('slides-dots');
|
|
51
|
+
while (dotsContainer.children.length < this.container.children.length) {
|
|
52
|
+
dotsContainer.insertAdjacentHTML("beforeend", `<button type="button" class="slide-dot"></button>`);
|
|
53
|
+
}
|
|
54
|
+
while (dotsContainer.children.length > this.container.children.length) {
|
|
55
|
+
dotsContainer.lastElementChild.remove();
|
|
45
56
|
}
|
|
57
|
+
Array.from(dotsContainer.children).forEach((dot, index) => {
|
|
58
|
+
dot.setAttribute("aria-label", `vai alla slide ${index + 1}`);
|
|
59
|
+
});
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
//+ PREV
|
|
@@ -51,7 +65,7 @@ class PGS_Slides {
|
|
|
51
65
|
let current;
|
|
52
66
|
|
|
53
67
|
|
|
54
|
-
if (pgs(this.
|
|
68
|
+
if (pgs(this.element).option.contains('singleScroll')) current = currents[currents.length - 1];
|
|
55
69
|
else current = currents[0];
|
|
56
70
|
|
|
57
71
|
const prev = current?.previousElementSibling;
|
|
@@ -67,19 +81,17 @@ class PGS_Slides {
|
|
|
67
81
|
|
|
68
82
|
|
|
69
83
|
|
|
70
|
-
if (pgs(this.
|
|
84
|
+
if (pgs(this.element).option.contains('singleScroll')) current = currents[0];
|
|
71
85
|
else current = currents[currents.length - 1];
|
|
72
86
|
|
|
73
87
|
const next = current?.nextElementSibling;
|
|
74
|
-
console.log(current, next);
|
|
75
|
-
|
|
76
88
|
next?.scrollIntoView(this.scrollOptions);
|
|
77
89
|
next?.focus({ preventScroll: true });
|
|
78
90
|
}
|
|
79
91
|
|
|
80
92
|
//+ GO TO NUMBER SLIDE
|
|
81
93
|
#goToNumberSlide(index) {
|
|
82
|
-
this.container.children[index]
|
|
94
|
+
this.container.children[index]?.scrollIntoView(this.scrollOptions);
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
//+ CALLBACK
|
|
@@ -118,8 +130,10 @@ class PGS_Slides {
|
|
|
118
130
|
|
|
119
131
|
//= EXECUTE
|
|
120
132
|
execute() {
|
|
121
|
-
const slides = this.
|
|
122
|
-
if (!this.container) return
|
|
133
|
+
const slides = this.element;
|
|
134
|
+
if (!this.container) return;
|
|
135
|
+
const eventController = new AbortController();
|
|
136
|
+
const { signal } = eventController;
|
|
123
137
|
|
|
124
138
|
//== elements
|
|
125
139
|
this.#createButtonsAndDots();
|
|
@@ -131,12 +145,14 @@ class PGS_Slides {
|
|
|
131
145
|
const notScrollWithMouse = pgs(slides).option.contains('notScrollWithMouse');
|
|
132
146
|
|
|
133
147
|
//== scroll
|
|
134
|
-
|
|
148
|
+
const removeHorizontalScroll = notScrollWithMouse
|
|
149
|
+
? null
|
|
150
|
+
: PGS_scrollHorizontal(this.container, 5);
|
|
135
151
|
|
|
136
152
|
//==Listener: DOT, PREC, NEXT
|
|
137
|
-
dots.forEach((dot, index) => dot.addEventListener("click",
|
|
138
|
-
precButton.addEventListener("click",
|
|
139
|
-
nextButton.addEventListener("click",
|
|
153
|
+
dots.forEach((dot, index) => dot.addEventListener("click", () => this.#goToNumberSlide(index), { signal }));
|
|
154
|
+
precButton.addEventListener("click", () => this.#previousSlide(), { passive: true, signal });
|
|
155
|
+
nextButton.addEventListener("click", () => this.#nextSlide(), { passive: true, signal });
|
|
140
156
|
|
|
141
157
|
//== observer
|
|
142
158
|
const observer = new IntersectionObserver(
|
|
@@ -146,9 +162,18 @@ class PGS_Slides {
|
|
|
146
162
|
Array.from(this.container.children).forEach(allLi => observer.observe(allLi));
|
|
147
163
|
|
|
148
164
|
|
|
165
|
+
let api;
|
|
166
|
+
const destroy = () => {
|
|
167
|
+
if (API.get(this.element) !== api) return;
|
|
168
|
+
eventController.abort();
|
|
169
|
+
observer.disconnect();
|
|
170
|
+
removeHorizontalScroll?.();
|
|
171
|
+
API.delete(this.element);
|
|
172
|
+
};
|
|
173
|
+
|
|
149
174
|
//- API
|
|
150
|
-
|
|
151
|
-
element: this.
|
|
175
|
+
api = {
|
|
176
|
+
element: this.element,
|
|
152
177
|
container: this.container,
|
|
153
178
|
previous: () => this.#previousSlide(),
|
|
154
179
|
next: () => this.#nextSlide(),
|
|
@@ -163,19 +188,28 @@ class PGS_Slides {
|
|
|
163
188
|
return last?.classList.contains("view") || false;
|
|
164
189
|
},
|
|
165
190
|
refresh: () => {
|
|
166
|
-
|
|
167
|
-
|
|
191
|
+
if (API.get(this.element) !== api) return API.get(this.element);
|
|
192
|
+
destroy();
|
|
193
|
+
const instance = new PGS_Slides({
|
|
194
|
+
element: this.element,
|
|
195
|
+
viewRatio: this.viewRatio,
|
|
196
|
+
optionIntersectionObserver: this.optionIntersectionObserver,
|
|
197
|
+
scrollOptions: this.scrollOptions,
|
|
198
|
+
});
|
|
199
|
+
instance.execute();
|
|
200
|
+
return API.get(this.element);
|
|
168
201
|
},
|
|
169
|
-
}
|
|
202
|
+
};
|
|
203
|
+
API.set(this.element, api);
|
|
170
204
|
}
|
|
171
205
|
}
|
|
172
206
|
|
|
173
207
|
//# INIT
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (API.has(
|
|
208
|
+
function PGS_slides_init(root = document) {
|
|
209
|
+
getSlides(root).forEach(element => {
|
|
210
|
+
if (API.has(element)) return;
|
|
177
211
|
|
|
178
|
-
const instance = new PGS_Slides({
|
|
212
|
+
const instance = new PGS_Slides({ element });
|
|
179
213
|
instance.execute();
|
|
180
214
|
});
|
|
181
215
|
}
|
|
@@ -183,8 +217,8 @@ export function PGS_slides_init(root = document) {
|
|
|
183
217
|
PGS_slides_init();
|
|
184
218
|
|
|
185
219
|
//# API
|
|
186
|
-
|
|
187
|
-
return API.get(
|
|
220
|
+
function PGS_slides_api(element) {
|
|
221
|
+
return API.get(element);
|
|
188
222
|
}
|
|
189
223
|
|
|
190
224
|
export const PGS_slides = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const API = new WeakMap();
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function PGS_stepTabs_init(root = document) {
|
|
4
4
|
pgs(root).querySelectorAll("stepTabs").forEach(tabsWizard => {
|
|
5
5
|
if (tabsWizard.dataset.stepTabsInitialized === "true") return;
|
|
6
6
|
tabsWizard.dataset.stepTabsInitialized = "true";
|
|
@@ -32,7 +32,7 @@ export function PGS_stepTabs_init(root = document) {
|
|
|
32
32
|
const dot = document.createElement("button");
|
|
33
33
|
dot.type = "button";
|
|
34
34
|
pgs(dot).add("stepTabs-dots-dot");
|
|
35
|
-
dot.
|
|
35
|
+
pgs(dot).option.setValueBrackets("step", index);
|
|
36
36
|
dot.innerHTML = `<i class="fa-solid ${iconClass}"></i>`;
|
|
37
37
|
|
|
38
38
|
dot.addEventListener("click", () => {
|
|
@@ -97,7 +97,7 @@ export function PGS_stepTabs_init(root = document) {
|
|
|
97
97
|
//= INIT
|
|
98
98
|
goTo(0, false);
|
|
99
99
|
|
|
100
|
-
//=
|
|
100
|
+
//= tab-locked
|
|
101
101
|
const observer = new MutationObserver(() => {
|
|
102
102
|
if (isRendering) return;
|
|
103
103
|
updateControls();
|
|
@@ -135,7 +135,7 @@ export function PGS_stepTabs_init(root = document) {
|
|
|
135
135
|
|
|
136
136
|
PGS_stepTabs_init()
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
function PGS_stepTabs_api(selector) {
|
|
139
139
|
return API.get(selector);
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const API = new WeakMap();
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function PGS_steps_init(root = document) {
|
|
4
4
|
pgs(root).querySelectorAll("steps").forEach(steps => {
|
|
5
5
|
if (API.has(steps)) return;
|
|
6
6
|
|
|
@@ -43,7 +43,7 @@ export function PGS_steps_init(root = document) {
|
|
|
43
43
|
PGS_steps_init()
|
|
44
44
|
|
|
45
45
|
//# API
|
|
46
|
-
|
|
46
|
+
function PGS_steps_api(selector) {
|
|
47
47
|
return API.get(selector);
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -20,7 +20,7 @@ function directPgsChild(element, token) {
|
|
|
20
20
|
return Array.from(element.children).find(child => pgs(child).contains(token));
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
function PGS_summary_init(root = document) {
|
|
24
24
|
pgs(root).querySelectorAll("summary").forEach((summary) => {
|
|
25
25
|
if (API.has(summary)) return;
|
|
26
26
|
|
|
@@ -95,7 +95,7 @@ export function PGS_summary_init(root = document) {
|
|
|
95
95
|
PGS_summary_init();
|
|
96
96
|
|
|
97
97
|
//# API
|
|
98
|
-
|
|
98
|
+
function PGS_summary_api(selector) {
|
|
99
99
|
return API.get(selector);
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -1,40 +1,43 @@
|
|
|
1
|
+
import { pgs } from "../_pgs.js";
|
|
1
2
|
import { PGS_notification } from "../components/_notifications.js";
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
export class PGS_formValidate {
|
|
5
|
-
|
|
6
|
+
#message = {};
|
|
7
|
+
#insideValidatedCallback = false;
|
|
8
|
+
|
|
9
|
+
constructor(form, options = {}) {
|
|
10
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
11
|
+
throw new TypeError("options must be an object");
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
this.container = form;
|
|
7
15
|
this._rules = [];
|
|
8
|
-
|
|
16
|
+
this.message = {
|
|
17
|
+
fieldError: "Please complete this field.",
|
|
18
|
+
fieldsError: "Please complete all required fields.",
|
|
19
|
+
success: "Submitted successfully."
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (options.message !== undefined) this.message = options.message;
|
|
23
|
+
this.container?.setAttribute("novalidate", "");
|
|
9
24
|
}
|
|
10
25
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
field.setAttribute("data-form-field-status", "error");
|
|
14
|
-
if (i == 0) field.scrollIntoView();
|
|
15
|
-
|
|
16
|
-
let message = field.getAttribute("data-form-field-message");
|
|
17
|
-
|
|
18
|
-
if (i == 0 && message) PGS_notification.toast.error(message);
|
|
19
|
-
else if (i == 0) PGS_notification.toast.error("Compila tutti i campi!");
|
|
26
|
+
get message() {
|
|
27
|
+
return { ...this.#message };
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
set message(value) {
|
|
31
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
32
|
+
throw new TypeError("message must be an object");
|
|
33
|
+
}
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
allFields.forEach(element => {
|
|
29
|
-
element.addEventListener("click", e => this.removeError(element))
|
|
30
|
-
});
|
|
35
|
+
this.#message = { ...this.#message, ...value };
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
help = {
|
|
37
|
-
// supporta sia required nativo, sia data-required="true"
|
|
38
|
+
// - Helpers
|
|
39
|
+
#help = {
|
|
40
|
+
// supporta sia required nativo
|
|
38
41
|
isRequired(field) {
|
|
39
42
|
if (!field) return false;
|
|
40
43
|
|
|
@@ -77,26 +80,26 @@ export class PGS_formValidate {
|
|
|
77
80
|
if (input.type === "hidden") return false;
|
|
78
81
|
if (input.type === "checkbox" || input.type === "radio" || input.type === "file") return false;
|
|
79
82
|
|
|
80
|
-
// valida solo se required
|
|
81
|
-
if (!this
|
|
83
|
+
// valida solo se required
|
|
84
|
+
if (!this.#help.isRequired(input)) return false;
|
|
82
85
|
|
|
83
|
-
return this
|
|
86
|
+
return this.#help.isEmptyTextLike(input);
|
|
84
87
|
});
|
|
85
88
|
|
|
86
89
|
//== TEXTAREA
|
|
87
90
|
// required vuote
|
|
88
91
|
const textareas = Array.from(container.querySelectorAll("textarea")).filter((ta) => {
|
|
89
92
|
if (ta.disabled) return false;
|
|
90
|
-
if (!this
|
|
91
|
-
return this
|
|
93
|
+
if (!this.#help.isRequired(ta)) return false;
|
|
94
|
+
return this.#help.isEmptyTextLike(ta);
|
|
92
95
|
});
|
|
93
96
|
|
|
94
97
|
//== SELECT
|
|
95
98
|
// required vuoti
|
|
96
99
|
const selects = Array.from(container.querySelectorAll("select")).filter((sel) => {
|
|
97
100
|
if (sel.disabled) return false;
|
|
98
|
-
if (!this
|
|
99
|
-
return this
|
|
101
|
+
if (!this.#help.isRequired(sel)) return false;
|
|
102
|
+
return this.#help.isEmptySelect(sel);
|
|
100
103
|
});
|
|
101
104
|
|
|
102
105
|
//== RADIO
|
|
@@ -104,8 +107,8 @@ export class PGS_formValidate {
|
|
|
104
107
|
const radios = Array.from(container.querySelectorAll('input[type="radio"]')).filter((r) => !r.disabled);
|
|
105
108
|
const requiredRadioGroups = new Map(); // name -> [elements]
|
|
106
109
|
for (const r of radios) {
|
|
107
|
-
if (!this
|
|
108
|
-
const name = this
|
|
110
|
+
if (!this.#help.isRequired(r)) continue;
|
|
111
|
+
const name = this.#help.getGroupName(r);
|
|
109
112
|
if (!name) continue;
|
|
110
113
|
if (!requiredRadioGroups.has(name)) requiredRadioGroups.set(name, []);
|
|
111
114
|
requiredRadioGroups.get(name).push(r);
|
|
@@ -126,9 +129,9 @@ export class PGS_formValidate {
|
|
|
126
129
|
const requiredCheckboxSingles = [];
|
|
127
130
|
const requiredCheckboxGroups = new Map(); // name -> [elements]
|
|
128
131
|
for (const c of checkboxes) {
|
|
129
|
-
if (!this
|
|
132
|
+
if (!this.#help.isRequired(c)) continue;
|
|
130
133
|
|
|
131
|
-
const name = this
|
|
134
|
+
const name = this.#help.getGroupName(c);
|
|
132
135
|
if (!name) {
|
|
133
136
|
// checkbox senza name: trattala come singola required
|
|
134
137
|
if (!c.checked) requiredCheckboxSingles.push(c);
|
|
@@ -151,7 +154,7 @@ export class PGS_formValidate {
|
|
|
151
154
|
// required: se vuoi includerlo
|
|
152
155
|
const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')).filter((f) => {
|
|
153
156
|
if (f.disabled) return false;
|
|
154
|
-
if (!this
|
|
157
|
+
if (!this.#help.isRequired(f)) return false;
|
|
155
158
|
return !(f.files && f.files.length > 0);
|
|
156
159
|
});
|
|
157
160
|
|
|
@@ -167,12 +170,37 @@ export class PGS_formValidate {
|
|
|
167
170
|
ruleInvalidFields
|
|
168
171
|
];
|
|
169
172
|
|
|
170
|
-
return invalidFields.flat();
|
|
173
|
+
return [...new Set(invalidFields.flat())];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//+ ADD
|
|
177
|
+
addFieldError(field, i = 0, total = 1) {
|
|
178
|
+
pgs(field).option.add("error");
|
|
179
|
+
if (i === 0) field.scrollIntoView();
|
|
180
|
+
|
|
181
|
+
if (i !== 0) return;
|
|
182
|
+
|
|
183
|
+
if (total > 1) {
|
|
184
|
+
PGS_notification.toast.error(this.message.fieldsError);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const message = pgs(field).option.getValueBrackets("message");
|
|
189
|
+
PGS_notification.toast.error(message || this.message.fieldError);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//+ REMOVE
|
|
193
|
+
removeFieldError(field) {
|
|
194
|
+
pgs(field).option.remove("error");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// + SUCCESS
|
|
198
|
+
success(text = this.message.success) {
|
|
199
|
+
if (this.#insideValidatedCallback || this.validate() === true) PGS_notification.toast.success(text)
|
|
171
200
|
}
|
|
172
201
|
|
|
173
|
-
|
|
174
|
-
// + VALIDATE
|
|
175
|
-
// + -------------------------
|
|
202
|
+
|
|
203
|
+
// + VALIDATE
|
|
176
204
|
validate() {
|
|
177
205
|
const invalid = this.#inputValue(this.container);
|
|
178
206
|
const allFields = this.container.querySelectorAll("input, textarea, select")
|
|
@@ -183,34 +211,50 @@ export class PGS_formValidate {
|
|
|
183
211
|
|
|
184
212
|
//== per radio/checkbox in gruppo:
|
|
185
213
|
// rimuovi l'errore solo sull'elemento che lo ospita (qui: se presente)
|
|
186
|
-
for (const el of allFields) { if (!invalid.includes(el)) this.
|
|
214
|
+
for (const el of allFields) { if (!invalid.includes(el)) this.removeFieldError(el); }
|
|
187
215
|
|
|
188
216
|
//== aggiungo errori dove serve
|
|
189
|
-
invalid.forEach((el, i) => this.
|
|
217
|
+
invalid.forEach((el, i) => this.addFieldError(el, i, invalid.length))
|
|
190
218
|
|
|
191
219
|
//== rimuove l'errore al click
|
|
192
|
-
this
|
|
220
|
+
allFields.forEach(element => element.addEventListener("click", e => this.removeFieldError(element)));
|
|
193
221
|
|
|
194
222
|
//== status form
|
|
195
223
|
if (invalid.length) {
|
|
196
|
-
this.container.
|
|
224
|
+
pgs(this.container).option.remove("success").add("error");
|
|
197
225
|
return false;
|
|
198
226
|
} else {
|
|
199
|
-
this.container.
|
|
227
|
+
pgs(this.container).option.remove("error").add("success");
|
|
200
228
|
return true;
|
|
201
229
|
}
|
|
202
230
|
}
|
|
203
231
|
|
|
204
|
-
|
|
205
|
-
|
|
232
|
+
// + EVENT VALIDATOR
|
|
233
|
+
validator(callback, eventName = "submit") {
|
|
234
|
+
if (typeof callback !== "function") throw new TypeError("callback must be a function");
|
|
235
|
+
if (typeof eventName !== "string" || !eventName.trim()) throw new TypeError("eventName must be a non-empty string");
|
|
236
|
+
|
|
237
|
+
this.container.addEventListener(eventName, event => {
|
|
238
|
+
event.preventDefault();
|
|
239
|
+
if (!this.validate()) return;
|
|
240
|
+
|
|
241
|
+
this.#insideValidatedCallback = true;
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
this.success();
|
|
245
|
+
callback(event);
|
|
246
|
+
} finally {
|
|
247
|
+
this.#insideValidatedCallback = false;
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
return this;
|
|
206
252
|
}
|
|
207
253
|
|
|
208
|
-
// +
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (typeof container !== "function") throw new Error("Rule must be a function");
|
|
213
|
-
this._rules.push(container);
|
|
254
|
+
// + ADD RULE
|
|
255
|
+
addNewRule(rule) {
|
|
256
|
+
if (typeof rule !== "function") throw new Error("Rule must be a function");
|
|
257
|
+
this._rules.push(rule);
|
|
214
258
|
return this;
|
|
215
259
|
}
|
|
216
260
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function PGS_scrollHorizontal(
|
|
1
|
+
export function PGS_scrollHorizontal(element, speed) {
|
|
2
2
|
// Se hai più contenitori, selezionali tutti:
|
|
3
3
|
// Semplice "singleton" per stimare se la sorgente è trackpad
|
|
4
4
|
const TrackpadDetector = (() => {
|
|
@@ -40,10 +40,7 @@ export function PGS_scrollHorizontal(querySelector, dataSpeed) {
|
|
|
40
40
|
|
|
41
41
|
//= Scorrimento orizzontale con rotella (evita il trackpad)
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
el.addEventListener('wheel', (e) => {
|
|
45
|
-
const speed = dataSpeed;
|
|
46
|
-
|
|
43
|
+
const onWheel = (e) => {
|
|
47
44
|
//== lascia lo scroll naturale del trackpad
|
|
48
45
|
if (TrackpadDetector.update(e)) return;
|
|
49
46
|
|
|
@@ -54,11 +51,11 @@ export function PGS_scrollHorizontal(querySelector, dataSpeed) {
|
|
|
54
51
|
//== Converti delta in px per lo shift orizzontale
|
|
55
52
|
let delta = e.deltaY;
|
|
56
53
|
if (e.deltaMode === 1) delta *= 16;
|
|
57
|
-
else if (e.deltaMode === 2) delta *=
|
|
54
|
+
else if (e.deltaMode === 2) delta *= element.clientHeight;
|
|
58
55
|
|
|
59
56
|
//== Verifica se il contenitore può ancora scrollare orizzontalmente
|
|
60
|
-
const atStart =
|
|
61
|
-
const atEnd =
|
|
57
|
+
const atStart = element.scrollLeft <= 0;
|
|
58
|
+
const atEnd = element.scrollLeft + element.clientWidth >= element.scrollWidth - 1;
|
|
62
59
|
const scrollingRight = delta > 0;
|
|
63
60
|
const scrollingLeft = delta < 0;
|
|
64
61
|
const canScrollHoriz =
|
|
@@ -72,6 +69,9 @@ export function PGS_scrollHorizontal(querySelector, dataSpeed) {
|
|
|
72
69
|
e.preventDefault();
|
|
73
70
|
|
|
74
71
|
//== rotella giù => destra
|
|
75
|
-
|
|
76
|
-
}
|
|
72
|
+
element.scrollLeft += delta * speed;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
element.addEventListener('wheel', onWheel, { passive: false });
|
|
76
|
+
return () => element.removeEventListener('wheel', onWheel);
|
|
77
77
|
}
|
|
@@ -8,7 +8,10 @@ function PGS_header(selectHeader = document) {
|
|
|
8
8
|
|
|
9
9
|
const headerElements = pgs(header).querySelectorAll("header-element");
|
|
10
10
|
|
|
11
|
+
if (!headerElements.length) console.log('For the header to work correctly, insert "header-element" under "header"');
|
|
11
12
|
if (!headerElements.length) return;
|
|
13
|
+
|
|
14
|
+
|
|
12
15
|
|
|
13
16
|
headerElements.forEach(selectHeader => {
|
|
14
17
|
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
margin: 0;
|
|
6
6
|
padding: 0;
|
|
7
7
|
box-sizing: border-box;
|
|
8
|
-
scroll-margin-top:
|
|
8
|
+
scroll-margin-top: var(--page-topScroll);
|
|
9
9
|
|
|
10
10
|
// Reset properties
|
|
11
11
|
* {
|
|
12
12
|
margin: 0;
|
|
13
13
|
padding: 0;
|
|
14
14
|
box-sizing: border-box;
|
|
15
|
-
scroll-margin-top:
|
|
15
|
+
scroll-margin-top: var(--page-topScroll);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
&:root,
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
--text-shadow: 0px 0px 50px #000000;
|
|
20
20
|
--backdrop: #0000003e;
|
|
21
21
|
--blur: blur(20px);
|
|
22
|
-
--page-top: calc(var(--heightOfHeader) +
|
|
23
|
-
--page-topScroll: calc(var(--heightOfHeaderScroll) +
|
|
22
|
+
--page-top: calc(var(--heightOfHeader) + var(--heightOfHeader));
|
|
23
|
+
--page-topScroll: calc(var(--heightOfHeaderScroll) + var(--heightOfHeader));
|
|
24
24
|
--page-width: 1280px;
|
|
25
25
|
--page-space: clamp(var(--padding-page), calc((100% - var(--section-width)) / 2 + var(--padding-page)), 100%);
|
|
26
26
|
--gap-texts: 1.0rem;
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
&:not([pgs-state~=open]) {
|
|
13
13
|
@include button(true);
|
|
14
|
-
--button-background: var(--color-box);
|
|
15
14
|
--button-size: var(--padding-2);
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -59,7 +58,6 @@
|
|
|
59
58
|
//= OPEN
|
|
60
59
|
&[pgs-state~=open] {
|
|
61
60
|
@include button(false);
|
|
62
|
-
--button-background: var(--color-box);
|
|
63
61
|
--button-size: var(--padding-2);
|
|
64
62
|
margin-top: var(--padding);
|
|
65
63
|
|
|
@@ -25,22 +25,6 @@
|
|
|
25
25
|
@include select();
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
[pgs~=checkboxBackground] {
|
|
29
|
-
@include checkboxBackground();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
[pgs~=twoState] {
|
|
33
|
-
@include twoState();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
[pgs~=toggle] {
|
|
37
|
-
@include toggle();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
[pgs~=chips] {
|
|
41
|
-
@include chips();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
28
|
[pgs~=radio],
|
|
45
29
|
[pgs~=checkbox] {
|
|
46
30
|
@include checkbox();
|
|
@@ -50,6 +34,6 @@
|
|
|
50
34
|
@include form();
|
|
51
35
|
}
|
|
52
36
|
|
|
53
|
-
[pgs~=
|
|
54
|
-
@include
|
|
37
|
+
[pgs~=formValidate] {
|
|
38
|
+
@include formValidate();
|
|
55
39
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@use "../mixin/mixin" as *;
|
|
2
|
+
|
|
3
|
+
//# FORM ADDON
|
|
4
|
+
[pgs~=checkboxBackground] {
|
|
5
|
+
@include checkboxBackground();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
[pgs~=twoState] {
|
|
9
|
+
@include twoState();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
[pgs~=toggle] {
|
|
13
|
+
@include toggle();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[pgs~=chips] {
|
|
17
|
+
@include chips();
|
|
18
|
+
}
|