mypgs 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -5
- package/README.md +1 -1
- package/assets/javascript/_imports.js +4 -0
- package/assets/javascript/_pgs.js +58 -0
- package/assets/javascript/base/_darkmode.js +27 -105
- package/assets/javascript/base/_svg.js +103 -0
- package/assets/javascript/components/_accordion.js +2 -2
- package/assets/javascript/components/_menu.js +1 -3
- package/assets/javascript/components/_modals.js +159 -136
- package/assets/javascript/components/_notifications.js +19 -9
- package/assets/javascript/components/_search.js +391 -0
- 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/index.js +2 -0
- package/assets/javascript/layout/_header.js +29 -7
- package/assets/scss/base/_color.scss +5 -5
- package/assets/scss/base/_html.scss +2 -2
- package/assets/scss/base/_variables.scss +4 -2
- package/assets/scss/components/_dropdown.scss +2 -1
- package/assets/scss/components/_form.scss +2 -2
- package/assets/scss/components/_logo.scss +2 -2
- package/assets/scss/components/_menu.scss +20 -27
- package/assets/scss/components/_modals.scss +11 -1
- package/assets/scss/components/_notification.scss +23 -30
- package/assets/scss/components/_search.scss +140 -0
- package/assets/scss/index.scss +2 -2
- package/assets/scss/layout/_header.scss +1 -1
- package/assets/scss/layout/_pageShell.scss +19 -15
- package/assets/scss/mixin/_mx-form.scss +7 -7
- package/{templates/html → demo}/demo.html +1 -1
- package/demo/demo.js +240 -0
- package/dist/css/index.css +188 -125
- package/dist/css/index.css.map +1 -1
- package/dist/css/index.min.css +1 -1
- package/dist/index.d.ts +70 -0
- package/dist/javascript/index.js +1038 -405
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/index.min.js +1 -1
- package/docs/componenti-e-markup.md +62 -27
- 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 +113 -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 +117 -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/helper-javascript.md +71 -3
- 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/package.json +2 -1
- package/scripts/generate-component-docs.js +557 -0
- package/templates/html/components/accordion.html +33 -4
- package/templates/html/components/badges.html +23 -0
- package/templates/html/components/breadcumbs.html +14 -0
- package/templates/html/components/button.html +22 -0
- package/templates/html/components/card.html +20 -0
- package/templates/html/components/dropdown.html +34 -0
- package/templates/html/components/form.html +82 -4
- package/templates/html/components/logo.html +22 -1
- package/templates/html/components/menu.html +40 -1
- package/templates/html/components/modal.html +44 -0
- package/templates/html/components/notification.html +68 -32
- package/templates/html/components/search.html +107 -0
- package/templates/html/components/slides.html +43 -0
- package/templates/html/components/stepTabs.html +47 -0
- package/templates/html/components/steps.html +24 -0
- package/templates/html/components/summary.html +27 -0
- package/templates/html/components/table.html +12 -0
- package/templates/html/components/tooltip.html +35 -0
- package/templates/html/layout/body.html +20 -5
- package/templates/html/layout/flex.html +20 -0
- package/templates/html/layout/footer.html +29 -1
- package/templates/html/layout/grid.html +20 -0
- package/templates/html/layout/header.html +52 -5
- package/templates/html/layout/pageShell.html +19 -0
- package/templates/html/layout/section.html +32 -10
- package/templates/html/patterns/cookieConsent.html +31 -0
- package/templates/react/components/form.jsx +3 -3
- package/templates/react/components/logo.jsx +1 -1
- package/templates/react/components/notification.jsx +4 -4
- package/templates/react/components/{searchbar.jsx → search.jsx} +9 -7
- package/templates/react/patterns/footer.jsx +1 -1
- package/templates/react/patterns/header.jsx +16 -10
- package/assets/scss/components/_searchbar.scss +0 -70
- package/templates/html/components/searchbar.html +0 -29
- package/templates/html/demo.js +0 -137
- /package/{templates/html → demo}/demo.css +0 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
const API = new WeakMap();
|
|
2
|
+
const OPEN_SEARCHES = new Set();
|
|
3
|
+
let searchId = 0;
|
|
4
|
+
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
minLength: 2,
|
|
7
|
+
debounce: 200,
|
|
8
|
+
limit: 6,
|
|
9
|
+
submitOnSelect: false,
|
|
10
|
+
searchOnFocus: true,
|
|
11
|
+
source: null,
|
|
12
|
+
onSelect: null,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function nextSearchId() {
|
|
16
|
+
searchId += 1;
|
|
17
|
+
return searchId;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getSearches(root) {
|
|
21
|
+
const searches = root instanceof Element && pgs(root).contains("search") ? [root] : [];
|
|
22
|
+
searches.push(...pgs(root).querySelectorAll("search"));
|
|
23
|
+
return searches;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function directPgsChild(element, token) {
|
|
27
|
+
return Array.from(element.children).find(child => pgs(child).contains(token));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function normalizeItem(item) {
|
|
31
|
+
if (typeof item === "string" || typeof item === "number") {
|
|
32
|
+
const value = String(item).trim();
|
|
33
|
+
return value ? { label: value, value, disabled: false, data: item } : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!item || typeof item !== "object") return null;
|
|
37
|
+
|
|
38
|
+
const label = String(item.label ?? item.value ?? "").trim();
|
|
39
|
+
if (!label) return null;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
label,
|
|
43
|
+
value: String(item.value ?? label),
|
|
44
|
+
disabled: Boolean(item.disabled),
|
|
45
|
+
data: Object.prototype.hasOwnProperty.call(item, "data") ? item.data : item,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function normalizeOptions(current, options = {}) {
|
|
50
|
+
const next = { ...current, ...options };
|
|
51
|
+
next.minLength = Math.max(0, Number.parseInt(next.minLength, 10) || 0);
|
|
52
|
+
next.debounce = Math.max(0, Number.parseInt(next.debounce, 10) || 0);
|
|
53
|
+
next.limit = Math.max(1, Number.parseInt(next.limit, 10) || DEFAULT_OPTIONS.limit);
|
|
54
|
+
next.submitOnSelect = Boolean(next.submitOnSelect);
|
|
55
|
+
next.searchOnFocus = Boolean(next.searchOnFocus);
|
|
56
|
+
next.source = typeof next.source === "function" || Array.isArray(next.source) ? next.source : null;
|
|
57
|
+
next.onSelect = typeof next.onSelect === "function" ? next.onSelect : null;
|
|
58
|
+
return next;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function closeSearch(search) {
|
|
62
|
+
const data = API.get(search);
|
|
63
|
+
if (!data) return;
|
|
64
|
+
|
|
65
|
+
pgs(search).state.remove("open");
|
|
66
|
+
data.input.setAttribute("aria-expanded", "false");
|
|
67
|
+
data.input.removeAttribute("aria-activedescendant");
|
|
68
|
+
data.list.setAttribute("aria-hidden", "true");
|
|
69
|
+
data.setActiveIndex(-1);
|
|
70
|
+
OPEN_SEARCHES.delete(search);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function openSearch(search) {
|
|
74
|
+
const data = API.get(search);
|
|
75
|
+
if (!data || data.items().length === 0) return;
|
|
76
|
+
|
|
77
|
+
pgs(search).state.add("open");
|
|
78
|
+
data.input.setAttribute("aria-expanded", "true");
|
|
79
|
+
data.list.setAttribute("aria-hidden", "false");
|
|
80
|
+
OPEN_SEARCHES.add(search);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function PGS_search_init(root = document) {
|
|
84
|
+
getSearches(root).forEach(search => {
|
|
85
|
+
if (API.has(search)) return;
|
|
86
|
+
|
|
87
|
+
const input = search.querySelector('input[type="search"]');
|
|
88
|
+
const list = directPgsChild(search, "search-suggestions");
|
|
89
|
+
if (!input || !list) return;
|
|
90
|
+
|
|
91
|
+
const id = nextSearchId();
|
|
92
|
+
if (!input.id) input.id = `search-input-${id}`;
|
|
93
|
+
if (!list.id) list.id = `search-suggestions-${id}`;
|
|
94
|
+
|
|
95
|
+
input.setAttribute("role", "combobox");
|
|
96
|
+
input.setAttribute("aria-autocomplete", "list");
|
|
97
|
+
input.setAttribute("aria-haspopup", "listbox");
|
|
98
|
+
input.setAttribute("aria-controls", list.id);
|
|
99
|
+
input.setAttribute("aria-expanded", "false");
|
|
100
|
+
input.setAttribute("autocomplete", "off");
|
|
101
|
+
list.setAttribute("role", "listbox");
|
|
102
|
+
list.setAttribute("aria-labelledby", input.id);
|
|
103
|
+
list.setAttribute("aria-hidden", "true");
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
let options = { ...DEFAULT_OPTIONS };
|
|
107
|
+
let items = [];
|
|
108
|
+
let activeIndex = -1;
|
|
109
|
+
let timer = null;
|
|
110
|
+
let controller = null;
|
|
111
|
+
let requestNumber = 0;
|
|
112
|
+
|
|
113
|
+
function setLoading(loading) {
|
|
114
|
+
pgs(search).state.toggle("loading", loading);
|
|
115
|
+
input.setAttribute("aria-busy", String(loading));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function setActiveIndex(index) {
|
|
119
|
+
activeIndex = index;
|
|
120
|
+
const elements = Array.from(list.querySelectorAll('[pgs~="search-suggestions-item"]'));
|
|
121
|
+
|
|
122
|
+
elements.forEach((element, itemIndex) => {
|
|
123
|
+
const selected = itemIndex === activeIndex;
|
|
124
|
+
element.setAttribute("aria-selected", String(selected));
|
|
125
|
+
pgs(element).state.toggle("selected", selected);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const active = elements[activeIndex];
|
|
129
|
+
if (active) {
|
|
130
|
+
input.setAttribute("aria-activedescendant", active.id);
|
|
131
|
+
active.scrollIntoView({ block: "nearest" });
|
|
132
|
+
} else {
|
|
133
|
+
input.removeAttribute("aria-activedescendant");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function moveActive(step) {
|
|
138
|
+
if (!items.length) return;
|
|
139
|
+
|
|
140
|
+
let next = activeIndex;
|
|
141
|
+
for (let checked = 0; checked < items.length; checked += 1) {
|
|
142
|
+
next = (next + step + items.length) % items.length;
|
|
143
|
+
if (!items[next].disabled) {
|
|
144
|
+
setActiveIndex(next);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function clear() {
|
|
151
|
+
items = [];
|
|
152
|
+
activeIndex = -1;
|
|
153
|
+
list.replaceChildren();
|
|
154
|
+
closeSearch(search);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function cancel() {
|
|
158
|
+
if (timer !== null) window.clearTimeout(timer);
|
|
159
|
+
timer = null;
|
|
160
|
+
if (controller) controller.abort();
|
|
161
|
+
controller = null;
|
|
162
|
+
requestNumber += 1;
|
|
163
|
+
setLoading(false);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function render(nextItems) {
|
|
167
|
+
items = Array.from(nextItems || [])
|
|
168
|
+
.map(normalizeItem)
|
|
169
|
+
.filter(Boolean)
|
|
170
|
+
.slice(0, options.limit);
|
|
171
|
+
|
|
172
|
+
const fragment = document.createDocumentFragment();
|
|
173
|
+
items.forEach((item, index) => {
|
|
174
|
+
const option = document.createElement("li");
|
|
175
|
+
pgs(option).add("search-suggestions-item");
|
|
176
|
+
pgs(option).add("flexRow");
|
|
177
|
+
option.id = `${list.id}-option-${index}`;
|
|
178
|
+
option.dataset.index = String(index);
|
|
179
|
+
option.setAttribute("role", "option");
|
|
180
|
+
option.setAttribute("aria-selected", "false");
|
|
181
|
+
option.setAttribute("aria-disabled", String(item.disabled));
|
|
182
|
+
option.innerHTML = '<i class="fa-solid fa-magnifying-glass"></i>' + item.label;
|
|
183
|
+
fragment.append(option);
|
|
184
|
+
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
activeIndex = -1;
|
|
188
|
+
list.replaceChildren(fragment);
|
|
189
|
+
pgs(search).state.remove("error");
|
|
190
|
+
|
|
191
|
+
if (items.length) openSearch(search);
|
|
192
|
+
else closeSearch(search);
|
|
193
|
+
|
|
194
|
+
return items;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function resolveSource(query, signal) {
|
|
198
|
+
if (Array.isArray(options.source)) {
|
|
199
|
+
const normalizedQuery = query.toLocaleLowerCase();
|
|
200
|
+
return options.source.filter(item => {
|
|
201
|
+
const normalized = normalizeItem(item);
|
|
202
|
+
return normalized && normalized.label.toLocaleLowerCase().includes(normalizedQuery);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (typeof options.source !== "function") return [];
|
|
207
|
+
return await options.source({
|
|
208
|
+
query,
|
|
209
|
+
signal,
|
|
210
|
+
limit: options.limit,
|
|
211
|
+
element: search,
|
|
212
|
+
input,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function runSearch(query = input.value) {
|
|
217
|
+
cancel();
|
|
218
|
+
clear();
|
|
219
|
+
|
|
220
|
+
const normalizedQuery = String(query ?? "").trim();
|
|
221
|
+
if (normalizedQuery.length < options.minLength || !options.source) return [];
|
|
222
|
+
|
|
223
|
+
const currentRequest = requestNumber;
|
|
224
|
+
controller = new AbortController();
|
|
225
|
+
const currentController = controller;
|
|
226
|
+
setLoading(true);
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const result = await resolveSource(normalizedQuery, currentController.signal);
|
|
230
|
+
if (currentRequest !== requestNumber || currentController.signal.aborted) return [];
|
|
231
|
+
return render(result);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (error?.name === "AbortError") return [];
|
|
234
|
+
if (currentRequest !== requestNumber) return [];
|
|
235
|
+
|
|
236
|
+
clear();
|
|
237
|
+
pgs(search).state.add("error");
|
|
238
|
+
search.dispatchEvent(new CustomEvent("pgs:search:error", {
|
|
239
|
+
bubbles: true,
|
|
240
|
+
detail: { error, query: normalizedQuery },
|
|
241
|
+
}));
|
|
242
|
+
return [];
|
|
243
|
+
} finally {
|
|
244
|
+
if (controller === currentController) controller = null;
|
|
245
|
+
if (currentRequest === requestNumber) setLoading(false);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function schedule() {
|
|
250
|
+
cancel();
|
|
251
|
+
clear();
|
|
252
|
+
pgs(search).state.remove("error");
|
|
253
|
+
|
|
254
|
+
if (input.value.trim().length < options.minLength || !options.source) return;
|
|
255
|
+
timer = window.setTimeout(() => {
|
|
256
|
+
timer = null;
|
|
257
|
+
runSearch(input.value);
|
|
258
|
+
}, options.debounce);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function select(index = activeIndex, submit = options.submitOnSelect) {
|
|
262
|
+
const item = items[index];
|
|
263
|
+
if (!item || item.disabled) return null;
|
|
264
|
+
|
|
265
|
+
input.value = item.value;
|
|
266
|
+
cancel();
|
|
267
|
+
clear();
|
|
268
|
+
|
|
269
|
+
const detail = { item, index, value: item.value, input, element: search };
|
|
270
|
+
search.dispatchEvent(new CustomEvent("pgs:search:select", { bubbles: true, detail }));
|
|
271
|
+
options.onSelect?.(detail);
|
|
272
|
+
|
|
273
|
+
input.focus();
|
|
274
|
+
if (submit && typeof search.requestSubmit === "function") search.requestSubmit();
|
|
275
|
+
return item;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function configure(nextOptions = {}) {
|
|
279
|
+
options = normalizeOptions(options, nextOptions);
|
|
280
|
+
return api;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function onInput() {
|
|
284
|
+
schedule();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function onFocus() {
|
|
288
|
+
if (items.length) openSearch(search);
|
|
289
|
+
else if (options.searchOnFocus) schedule();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function onKeydown(event) {
|
|
293
|
+
if (event.key === "ArrowDown") {
|
|
294
|
+
if (!pgs(search).state.contains("open")) schedule();
|
|
295
|
+
if (items.length) {
|
|
296
|
+
event.preventDefault();
|
|
297
|
+
moveActive(1);
|
|
298
|
+
}
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (event.key === "ArrowUp" && items.length) {
|
|
303
|
+
event.preventDefault();
|
|
304
|
+
moveActive(-1);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (event.key === "Enter" && activeIndex >= 0) {
|
|
309
|
+
event.preventDefault();
|
|
310
|
+
select(activeIndex);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (event.key === "Escape") {
|
|
315
|
+
event.preventDefault();
|
|
316
|
+
cancel();
|
|
317
|
+
closeSearch(search);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (event.key === "Tab") closeSearch(search);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function onListPointerDown(event) {
|
|
325
|
+
const option = event.target.closest('[pgs~="search-suggestions-item"]');
|
|
326
|
+
if (!option || !list.contains(option)) return;
|
|
327
|
+
event.preventDefault();
|
|
328
|
+
select(Number.parseInt(option.dataset.index, 10));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function onSubmit() {
|
|
332
|
+
cancel();
|
|
333
|
+
closeSearch(search);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function destroy() {
|
|
337
|
+
cancel();
|
|
338
|
+
clear();
|
|
339
|
+
input.removeEventListener("input", onInput);
|
|
340
|
+
input.removeEventListener("focus", onFocus);
|
|
341
|
+
input.removeEventListener("keydown", onKeydown);
|
|
342
|
+
list.removeEventListener("pointerdown", onListPointerDown);
|
|
343
|
+
search.removeEventListener("submit", onSubmit);
|
|
344
|
+
API.delete(search);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const api = {
|
|
348
|
+
element: search,
|
|
349
|
+
input,
|
|
350
|
+
list,
|
|
351
|
+
configure,
|
|
352
|
+
setSource: source => configure({ source }),
|
|
353
|
+
search: runSearch,
|
|
354
|
+
open: () => openSearch(search),
|
|
355
|
+
close: () => closeSearch(search),
|
|
356
|
+
clear,
|
|
357
|
+
cancel,
|
|
358
|
+
select,
|
|
359
|
+
refresh: () => runSearch(input.value),
|
|
360
|
+
destroy,
|
|
361
|
+
items: () => [...items],
|
|
362
|
+
isOpen: () => pgs(search).state.contains("open"),
|
|
363
|
+
isLoading: () => pgs(search).state.contains("loading"),
|
|
364
|
+
setActiveIndex,
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
input.addEventListener("input", onInput);
|
|
368
|
+
input.addEventListener("focus", onFocus);
|
|
369
|
+
input.addEventListener("keydown", onKeydown);
|
|
370
|
+
list.addEventListener("pointerdown", onListPointerDown);
|
|
371
|
+
search.addEventListener("submit", onSubmit);
|
|
372
|
+
API.set(search, api);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
document.addEventListener("pointerdown", event => {
|
|
377
|
+
OPEN_SEARCHES.forEach(search => {
|
|
378
|
+
if (!search.contains(event.target)) closeSearch(search);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
PGS_search_init();
|
|
383
|
+
|
|
384
|
+
function PGS_search_api(selector) {
|
|
385
|
+
return API.get(selector);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export const PGS_search = {
|
|
389
|
+
init: PGS_search_init,
|
|
390
|
+
api: PGS_search_api,
|
|
391
|
+
};
|
|
@@ -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
|
|