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.
Files changed (108) hide show
  1. package/AGENTS.md +8 -5
  2. package/README.md +1 -1
  3. package/assets/javascript/_imports.js +4 -0
  4. package/assets/javascript/_pgs.js +58 -0
  5. package/assets/javascript/base/_darkmode.js +27 -105
  6. package/assets/javascript/base/_svg.js +103 -0
  7. package/assets/javascript/components/_accordion.js +2 -2
  8. package/assets/javascript/components/_menu.js +1 -3
  9. package/assets/javascript/components/_modals.js +159 -136
  10. package/assets/javascript/components/_notifications.js +19 -9
  11. package/assets/javascript/components/_search.js +391 -0
  12. package/assets/javascript/components/_slides.js +66 -32
  13. package/assets/javascript/components/_stepTabs.js +4 -4
  14. package/assets/javascript/components/_steps.js +2 -2
  15. package/assets/javascript/components/_summary.js +2 -2
  16. package/assets/javascript/functions/_formValidate.js +97 -53
  17. package/assets/javascript/functions/_scrollY.js +10 -10
  18. package/assets/javascript/index.js +2 -0
  19. package/assets/javascript/layout/_header.js +29 -7
  20. package/assets/scss/base/_color.scss +5 -5
  21. package/assets/scss/base/_html.scss +2 -2
  22. package/assets/scss/base/_variables.scss +4 -2
  23. package/assets/scss/components/_dropdown.scss +2 -1
  24. package/assets/scss/components/_form.scss +2 -2
  25. package/assets/scss/components/_logo.scss +2 -2
  26. package/assets/scss/components/_menu.scss +20 -27
  27. package/assets/scss/components/_modals.scss +11 -1
  28. package/assets/scss/components/_notification.scss +23 -30
  29. package/assets/scss/components/_search.scss +140 -0
  30. package/assets/scss/index.scss +2 -2
  31. package/assets/scss/layout/_header.scss +1 -1
  32. package/assets/scss/layout/_pageShell.scss +19 -15
  33. package/assets/scss/mixin/_mx-form.scss +7 -7
  34. package/{templates/html → demo}/demo.html +1 -1
  35. package/demo/demo.js +240 -0
  36. package/dist/css/index.css +188 -125
  37. package/dist/css/index.css.map +1 -1
  38. package/dist/css/index.min.css +1 -1
  39. package/dist/index.d.ts +70 -0
  40. package/dist/javascript/index.js +1038 -405
  41. package/dist/javascript/index.js.map +1 -1
  42. package/dist/javascript/index.min.js +1 -1
  43. package/docs/componenti-e-markup.md +62 -27
  44. package/docs/components/accordion.md +61 -0
  45. package/docs/components/badges.md +67 -0
  46. package/docs/components/breadcumbs.md +43 -0
  47. package/docs/components/button.md +59 -0
  48. package/docs/components/card.md +50 -0
  49. package/docs/components/dropdown.md +135 -0
  50. package/docs/components/form.md +113 -0
  51. package/docs/components/logo.md +36 -0
  52. package/docs/components/menu.md +90 -0
  53. package/docs/components/modal.md +131 -0
  54. package/docs/components/notification.md +81 -0
  55. package/docs/components/search.md +117 -0
  56. package/docs/components/slides.md +85 -0
  57. package/docs/components/stepTabs.md +93 -0
  58. package/docs/components/steps.md +56 -0
  59. package/docs/components/summary.md +49 -0
  60. package/docs/components/table.md +42 -0
  61. package/docs/components/tooltip.md +53 -0
  62. package/docs/helper-javascript.md +71 -3
  63. package/docs/layout/body.md +41 -0
  64. package/docs/layout/flex.md +116 -0
  65. package/docs/layout/footer.md +71 -0
  66. package/docs/layout/grid.md +116 -0
  67. package/docs/layout/header.md +116 -0
  68. package/docs/layout/pageShell.md +94 -0
  69. package/docs/layout/section.md +69 -0
  70. package/docs/patterns/cookieConsent.md +89 -0
  71. package/package.json +2 -1
  72. package/scripts/generate-component-docs.js +557 -0
  73. package/templates/html/components/accordion.html +33 -4
  74. package/templates/html/components/badges.html +23 -0
  75. package/templates/html/components/breadcumbs.html +14 -0
  76. package/templates/html/components/button.html +22 -0
  77. package/templates/html/components/card.html +20 -0
  78. package/templates/html/components/dropdown.html +34 -0
  79. package/templates/html/components/form.html +82 -4
  80. package/templates/html/components/logo.html +22 -1
  81. package/templates/html/components/menu.html +40 -1
  82. package/templates/html/components/modal.html +44 -0
  83. package/templates/html/components/notification.html +68 -32
  84. package/templates/html/components/search.html +107 -0
  85. package/templates/html/components/slides.html +43 -0
  86. package/templates/html/components/stepTabs.html +47 -0
  87. package/templates/html/components/steps.html +24 -0
  88. package/templates/html/components/summary.html +27 -0
  89. package/templates/html/components/table.html +12 -0
  90. package/templates/html/components/tooltip.html +35 -0
  91. package/templates/html/layout/body.html +20 -5
  92. package/templates/html/layout/flex.html +20 -0
  93. package/templates/html/layout/footer.html +29 -1
  94. package/templates/html/layout/grid.html +20 -0
  95. package/templates/html/layout/header.html +52 -5
  96. package/templates/html/layout/pageShell.html +19 -0
  97. package/templates/html/layout/section.html +32 -10
  98. package/templates/html/patterns/cookieConsent.html +31 -0
  99. package/templates/react/components/form.jsx +3 -3
  100. package/templates/react/components/logo.jsx +1 -1
  101. package/templates/react/components/notification.jsx +4 -4
  102. package/templates/react/components/{searchbar.jsx → search.jsx} +9 -7
  103. package/templates/react/patterns/footer.jsx +1 -1
  104. package/templates/react/patterns/header.jsx +16 -10
  105. package/assets/scss/components/_searchbar.scss +0 -70
  106. package/templates/html/components/searchbar.html +0 -29
  107. package/templates/html/demo.js +0 -137
  108. /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({ selector, viewRatio = 0.97, optionIntersectionObserver = {}, scrollOptions = {} } = {}) {
7
- this.selector = selector;
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.selector ? pgs(this.selector).querySelector("slides-container") : null;
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.selector
35
+ const EL = this.element;
30
36
 
31
37
  //== PULSANTI
32
- if (!pgs(EL).querySelector('slides-prec') && !pgs(EL).querySelector('slides-next')) {
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
- 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
- });
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.selector).option.contains('singleScroll')) current = currents[currents.length - 1];
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.selector).option.contains('singleScroll')) current = currents[0];
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].scrollIntoView(this.scrollOptions)
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.selector;
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
- if (!notScrollWithMouse) PGS_scrollHorizontal(this.container, 5);
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", e => this.#goToNumberSlide(index)));
138
- precButton.addEventListener("click", e => this.#previousSlide(), { passive: true });
139
- nextButton.addEventListener("click", e => this.#nextSlide(), { passive: true });
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
- API.set(this.selector, {
151
- element: this.selector,
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
- PGS_slides_init(this.selector.parentNode || document);
167
- return API.get(this.selector);
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
- export function PGS_slides_init(root = document) {
175
- pgs(root).querySelectorAll("slides").forEach(el => {
176
- if (API.has(el)) return;
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({ selector: el });
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
- export function PGS_slides_api(selector) {
187
- return API.get(selector);
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
- export function PGS_stepTabs_init(root = document) {
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.setAttribute("data-step", index);
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
- //= data-tab-locked
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
- export function PGS_stepTabs_api(selector) {
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
- export function PGS_steps_init(root = document) {
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
- export function PGS_steps_api(selector) {
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
- export function PGS_summary_init(root = document) {
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
- export function PGS_summary_api(selector) {
98
+ function PGS_summary_api(selector) {
99
99
  return API.get(selector);
100
100
  }
101
101