@madj2k/fe-frontend-kit 2.0.4 → 2.0.6

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 (47) hide show
  1. package/index.js +7 -4
  2. package/index.scss +8 -1
  3. package/menus/flyout-menu/{flyout-menu-2.0.0.js → flyout-menu-2.0.js} +149 -51
  4. package/menus/flyout-menu/index.js +1 -1
  5. package/menus/flyout-menu/index.scss +1 -1
  6. package/menus/pulldown-menu/index.js +1 -1
  7. package/menus/pulldown-menu/index.scss +1 -1
  8. package/package.json +1 -1
  9. package/readme.md +23 -13
  10. package/tools/banner/index.js +1 -1
  11. package/tools/banner/index.scss +1 -1
  12. package/tools/owl-thumbnail/index.js +2 -0
  13. package/tools/owl-thumbnail/index.scss +1 -0
  14. package/tools/resize-end/index.js +1 -1
  15. package/tools/resize-end/index.scss +1 -1
  16. package/tools/scrolling/index.js +1 -1
  17. package/tools/scrolling/index.scss +1 -1
  18. package/tools/toggled-overlay/index.js +2 -0
  19. package/tools/toggled-overlay/index.scss +1 -0
  20. package/tools/toggled-overlay/toggled-overlay-2.0.js +125 -0
  21. package/tools/toggled-overlay/toggled-overlay-2.0.scss +11 -0
  22. package/tools/owl/index.js +0 -2
  23. package/tools/owl/index.scss +0 -1
  24. /package/menus/flyout-menu/{flyout-menu-2.0.0.scss → flyout-menu-2.0.scss} +0 -0
  25. /package/menus/pulldown-menu/{pulldown-menu-2.0.0.js → pulldown-menu-2.0.js} +0 -0
  26. /package/menus/pulldown-menu/{pulldown-menu-2.0.0.scss → pulldown-menu-2.0.scss} +0 -0
  27. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_accessibility.scss +0 -0
  28. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_colors.scss +0 -0
  29. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_flex-box.scss +0 -0
  30. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_form.scss +0 -0
  31. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_format.scss +0 -0
  32. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_icons.scss +0 -0
  33. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_nav.scss +0 -0
  34. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_page.scss +0 -0
  35. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_section.scss +0 -0
  36. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_toggle-list.scss +0 -0
  37. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/_unit.scss +0 -0
  38. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/10_mixins/index.scss +0 -0
  39. /package/sass/{bootstrap-5.3.0 → bootstrap-5.3}/index.scss +0 -0
  40. /package/tools/banner/{banner-2.0.0.js → banner-2.0.js} +0 -0
  41. /package/tools/banner/{banner-2.0.0.scss → banner-2.0.scss} +0 -0
  42. /package/tools/{owl/owl-thumbnail-2.0.0.js → owl-thumbnail/owl-thumbnail-2.0.js} +0 -0
  43. /package/tools/{owl/owl-thumbnail-2.0.0.scss → owl-thumbnail/owl-thumbnail-2.0.scss} +0 -0
  44. /package/tools/resize-end/{resize-end-2.0.0.js → resize-end-2.0.js} +0 -0
  45. /package/tools/resize-end/{resize-end-2.0.0.scss → resize-end-2.0.scss} +0 -0
  46. /package/tools/scrolling/{scrolling-2.0.0.js → scrolling-2.0.js} +0 -0
  47. /package/tools/scrolling/{scrolling-2.0.0.scss → scrolling-2.0.scss} +0 -0
package/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  // Tools
2
- export { Madj2kOwlThumbnail } from './tools/owl/owl-thumbnail.js';
3
- export { Madj2kScrolling } from './tools/scrolling/scrolling.js';
2
+ export { Madj2kBanner } from './tools/banner';
3
+ export { Madj2kOwlThumbnail } from './tools/owl-thumbnail';
4
+ export { Madj2kResizeEnd } from './tools/resize-end';
5
+ export { Madj2kScrolling } from './tools/scrolling';
6
+ export { Madj2kToggledOverlay } from './tools/toggled-overlay';
4
7
 
5
8
  // Menus
6
- export { Madj2kFlyoutMenu } from './menus/flyout-menu-1.0';
7
- export { Madj2kPulldownMenu } from './menus/pulldown-menu-1.0';
9
+ export { Madj2kFlyoutMenu } from './menus/flyout-menu';
10
+ export { Madj2kPulldownMenu } from './menus/pulldown-menu';
package/index.scss CHANGED
@@ -1,6 +1,13 @@
1
1
  // Forward all mixins
2
- @forward './sass/bootstrap-5.3.0/index';
2
+ @forward 'sass/bootstrap-5.3/index';
3
3
 
4
4
  // Forward all menu styles
5
5
  @forward './menus/flyout-menu';
6
6
  @forward './menus/pulldown-menu';
7
+
8
+ // Forward all tools
9
+ @forward 'tools/banner/index';
10
+ @forward 'tools/owl-thumbnail/index';
11
+ @forward 'tools/resize-end/index';
12
+ @forward 'tools/scrolling/index';
13
+ @forward 'tools/toggled-overlay/index';
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @author Steffen Kroggel <developer@steffenkroggel.de>
9
9
  * @copyright 2025 Steffen Kroggel
10
- * @version 2.0.0
10
+ * @version 2.0.1
11
11
  * @license GNU General Public License v3.0
12
12
  * @see https://www.gnu.org/licenses/gpl-3.0.en.html
13
13
  *
@@ -49,7 +49,7 @@ class Madj2kFlyoutMenu {
49
49
  menuCloseClass: "js-flyout-close",
50
50
  menuContainerClass: "js-flyout-container",
51
51
  menuInnerClass: "js-flyout-inner",
52
- heightMode: 'maxContent',
52
+ heightMode: 'full',
53
53
  paddingBehavior: 0,
54
54
  paddingViewPortMinWidth: 0,
55
55
  animationDuration: 500
@@ -76,25 +76,7 @@ class Madj2kFlyoutMenu {
76
76
  this.resizeAndPositionMenu();
77
77
  this.paddingMenu();
78
78
  this.bindEvents();
79
- }
80
-
81
- /**
82
- * Binds all necessary event listeners
83
- */
84
- bindEvents() {
85
- if (this.settings.$closeBtn) {
86
- this.settings.$closeBtn.addEventListener('click', e => this.closeEvent(e));
87
- this.settings.$closeBtn.addEventListener('keydown', e => this.keyboardEvent(e));
88
- }
89
-
90
- this.$element.addEventListener('click', e => this.toggleEvent(e));
91
- this.$element.addEventListener('keydown', e => this.keyboardEvent(e));
92
-
93
- this.settings.$menu.querySelectorAll('a,button,input,textarea,select')
94
- .forEach(el => el.addEventListener('keydown', e => this.keyboardEvent(e)));
95
-
96
- document.addEventListener('madj2k-flyoutmenu-close', e => this.closeEvent(e));
97
- document.addEventListener('madj2k-flyoutmenu-resize', e => this.resizeAndPositionMenuEvent(e));
79
+ this.initObservers();
98
80
  }
99
81
 
100
82
  /**
@@ -128,6 +110,88 @@ class Madj2kFlyoutMenu {
128
110
  }
129
111
  }
130
112
 
113
+ /**
114
+ * Binds all necessary event listeners
115
+ */
116
+ bindEvents() {
117
+ if (this.settings.$closeBtn) {
118
+ this.settings.$closeBtn.addEventListener('click', e => this.closeEvent(e));
119
+ this.settings.$closeBtn.addEventListener('keydown', e => this.keyboardEvent(e));
120
+ }
121
+
122
+ this.$element.addEventListener('click', e => this.toggleEvent(e));
123
+ this.$element.addEventListener('keydown', e => this.keyboardEvent(e));
124
+
125
+ this.settings.$menu.querySelectorAll('a,button,input,textarea,select')
126
+ .forEach(el => el.addEventListener('keydown', e => this.keyboardEvent(e)));
127
+
128
+ document.addEventListener('madj2k-flyoutmenu-close', e => this.closeEvent(e));
129
+ document.addEventListener('madj2k-flyoutmenu-resize', e => this.resizeAndPositionMenuEvent(e));
130
+ }
131
+
132
+ /**
133
+ * Initializes ResizeObserver to auto-resize menu
134
+ */
135
+ initObservers() {
136
+ // check if supported
137
+ if (typeof ResizeObserver === 'undefined') {
138
+ console.warn('ResizeObserver is not supported in this browser.');
139
+ return;
140
+ }
141
+
142
+ // create observer
143
+ this.resizeObserver = new ResizeObserver(entries => {
144
+ for (let entry of entries) {
145
+ this.resizeMenu();
146
+ }
147
+ });
148
+
149
+ // observe inner container
150
+ if (this.settings.$menuInner) {
151
+ this.resizeObserver.observe(this.settings.$menuInner);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Unbinds all event listeners
157
+ */
158
+ destroyEvents() {
159
+ if (this.settings.$closeBtn) {
160
+ this.settings.$closeBtn.removeEventListener('click', e => this.closeEvent(e));
161
+ this.settings.$closeBtn.removeEventListener('keydown', e => this.keyboardEvent(e));
162
+ }
163
+
164
+ this.$element.removeEventListener('click', e => this.toggleEvent(e));
165
+ this.$element.removeEventListener('keydown', e => this.keyboardEvent(e));
166
+
167
+ this.settings.$menu.querySelectorAll('a,button,input,textarea,select')
168
+ .forEach(el => el.removeEventListener('keydown', e => this.keyboardEvent(e)));
169
+
170
+ document.removeEventListener('madj2k-flyoutmenu-close', e => this.closeEvent(e));
171
+ document.removeEventListener('madj2k-flyoutmenu-resize', e => this.resizeAndPositionMenuEvent(e));
172
+ }
173
+
174
+ /**
175
+ * Destroys ResizeObserver
176
+ */
177
+ destroyResizeObserver() {
178
+ if (this.resizeObserver && this.settings.$menuInner) {
179
+ this.resizeObserver.unobserve(this.settings.$menuInner);
180
+ this.resizeObserver.disconnect();
181
+ this.resizeObserver = null;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Destroys flyout menu instance
187
+ */
188
+ destroy() {
189
+ this.destroyEvents();
190
+ this.destroyResizeObserver();
191
+ this.close();
192
+ }
193
+
194
+
131
195
  /**
132
196
  * Handles toggle click event
133
197
  * @param {Event} e - The click event
@@ -153,6 +217,15 @@ class Madj2kFlyoutMenu {
153
217
  }
154
218
  }
155
219
 
220
+ /**
221
+ * Sets focus to the toggle element
222
+ * @param {number} timeout - Delay before focusing
223
+ */
224
+ focusToggle(timeout = 0) {
225
+ setTimeout(() => this.$element.focus(), timeout);
226
+ }
227
+
228
+
156
229
  /**
157
230
  * Opens the flyout menu
158
231
  */
@@ -184,6 +257,14 @@ class Madj2kFlyoutMenu {
184
257
  }
185
258
  }
186
259
 
260
+ /**
261
+ * Returns true if menu is currently open
262
+ * @returns {boolean}
263
+ */
264
+ isOpen() {
265
+ return this.settings.$menu.classList.contains(this.settings.openStatusClass);
266
+ }
267
+
187
268
  /**
188
269
  * Handles close event
189
270
  * @param {Event} e - The close event
@@ -237,29 +318,54 @@ class Madj2kFlyoutMenu {
237
318
  }
238
319
 
239
320
  /**
240
- * Resizes and positions the menu based on reference elements
321
+ * Resizes and positions the menu
241
322
  */
242
323
  resizeAndPositionMenu() {
324
+ this.positionMenu();
325
+ this.resizeMenu();
326
+ }
327
+
328
+ /**
329
+ * Resizes the menu based on height mode and inner content
330
+ */
331
+ resizeMenu() {
243
332
  const refObj = this.settings.$positionReference || this.$element;
244
333
  const refPos = refObj.getBoundingClientRect();
245
334
  const flyoutTop = refPos.top + refObj.offsetHeight;
246
335
  let height = this.settings.$menuInner.offsetHeight || this.settings.$menu.offsetHeight;
247
336
 
248
- this.settings.$menu.style.top = `${flyoutTop}px`;
337
+ if ('fullHeight' in this.settings) {
338
+ console.warn('Option "fullHeight" is deprecated. Please use "heightMode" instead.');
339
+ }
249
340
 
250
- // deprecated fullHeight-setting as fallback
341
+ // heightMode "full" with deprecated fullHeight-setting as fallback
251
342
  if (this.settings.heightMode === 'full' || this.settings.fullHeight === true) {
252
- height = window.innerHeight - refPos.top - refObj.offsetHeight;
343
+ const viewPortHeight = window.innerHeight;
344
+ if (height < viewPortHeight) {
345
+ height = viewPortHeight - flyoutTop;
346
+ }
253
347
  this.settings.$menu.style.height = `${height}px`;
254
348
 
255
- } else if (this.settings.heightMode === 'maxContent'){
349
+ } else if (this.settings.heightMode === 'maxContent') {
256
350
  this.settings.$menu.style.height = `max-content`;
351
+ console.warn('heightMode: maxContent is not working on Apple Safari. Please use heightMode: full instead.');
257
352
 
258
353
  } else {
259
354
  this.settings.$menu.style.height = `${height}px`;
260
355
  }
261
356
  }
262
357
 
358
+ /**
359
+ * Positions the menu based on the reference element
360
+ */
361
+ positionMenu() {
362
+ const refObj = this.settings.$positionReference || this.$element;
363
+ const refPos = refObj.getBoundingClientRect();
364
+ const flyoutTop = refPos.top + refObj.offsetHeight;
365
+
366
+ this.settings.$menu.style.top = `${flyoutTop}px`;
367
+ }
368
+
263
369
  /**
264
370
  * Adjusts menu padding based on settings
265
371
  */
@@ -275,6 +381,23 @@ class Madj2kFlyoutMenu {
275
381
  this.settings.$menuInner.setAttribute('data-padding-set', 'true');
276
382
  }
277
383
 
384
+ /**
385
+ * Initializes the no-scroll helper elements
386
+ */
387
+ initNoScrollHelper() {
388
+ const body = document.body;
389
+ let helper = body.querySelector('.no-scroll-helper');
390
+ const content = document.querySelector(`.${this.settings.contentSectionClass}`);
391
+
392
+ if (!helper) {
393
+ if (content) {
394
+ content.innerHTML = `<div class="no-scroll-helper"><div class="no-scroll-helper-inner">${content.innerHTML}</div></div>`;
395
+ } else {
396
+ body.innerHTML = `<div class="no-scroll-helper"><div class="no-scroll-helper-inner">${body.innerHTML}</div></div>`;
397
+ }
398
+ }
399
+ }
400
+
278
401
  /**
279
402
  * Toggles scroll behavior of the page
280
403
  */
@@ -303,29 +426,4 @@ class Madj2kFlyoutMenu {
303
426
  window.scrollTo({top: scrollTop, behavior: 'instant'});
304
427
  }
305
428
  }
306
-
307
- /**
308
- * Initializes the no-scroll helper elements
309
- */
310
- initNoScrollHelper() {
311
- const body = document.body;
312
- let helper = body.querySelector('.no-scroll-helper');
313
- const content = document.querySelector(`.${this.settings.contentSectionClass}`);
314
-
315
- if (!helper) {
316
- if (content) {
317
- content.innerHTML = `<div class="no-scroll-helper"><div class="no-scroll-helper-inner">${content.innerHTML}</div></div>`;
318
- } else {
319
- body.innerHTML = `<div class="no-scroll-helper"><div class="no-scroll-helper-inner">${body.innerHTML}</div></div>`;
320
- }
321
- }
322
- }
323
-
324
- /**
325
- * Sets focus to the toggle element
326
- * @param {number} timeout - Delay before focusing
327
- */
328
- focusToggle(timeout = 0) {
329
- setTimeout(() => this.$element.focus(), timeout);
330
- }
331
429
  }
@@ -1,2 +1,2 @@
1
- import Madj2kFlyoutMenu from './flyout-menu-2.0.0.js';
1
+ import Madj2kFlyoutMenu from './flyout-menu-2.0.js';
2
2
  export { Madj2kFlyoutMenu };
@@ -1 +1 @@
1
- @forward './flyout-menu-2.0.0';
1
+ @forward './flyout-menu-2.0';
@@ -1,2 +1,2 @@
1
- import Madj2kPulldownMenu from './pulldown-menu-2.0.0.js';
1
+ import Madj2kPulldownMenu from './pulldown-menu-2.0.js';
2
2
  export { Madj2kPulldownMenu };
@@ -1 +1 @@
1
- @forward './pulldown-menu-2.0.0';
1
+ @forward './pulldown-menu-2.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madj2k/fe-frontend-kit",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Shared frontend utilities, menus and mixins for projects",
5
5
  "main": "index.js",
6
6
  "style": "index.scss",
package/readme.md CHANGED
@@ -26,6 +26,25 @@ Or import individual mixins:
26
26
  ### Menu components (JS and SCSS):
27
27
  Each menu component can be used separately.
28
28
 
29
+ # JS: Banner
30
+ A lightweight class to show a full-page overlay (banner, popup, hint or cookie layer),
31
+ with opening and closing animation and optional cookie persistence.
32
+
33
+ # JS: OWL-Thumbnails
34
+ A JavaScript helper class to create a main OWL carousel with a synchronized thumbnail navigation carousel.
35
+
36
+ Supports flexible configurations for both the main and the thumbnail carousels,
37
+ including:
38
+ - Custom navigation
39
+ - Syncing main carousel to clicked thumbnails
40
+ - Syncing thumbnails to main carousel changes
41
+ - Optionally equalizing thumbnail heights
42
+ - Optionally preventing the centered thumbnail stage shift (for designs where thumbs should stay left aligned)
43
+ - Responsive and CMS-friendly (works with dynamic content)
44
+
45
+ This is especially useful for image galleries or product carousels in CMS setups (e.g. TYPO3, WordPress, etc.)
46
+ where content may change dynamically.
47
+
29
48
  # JS: Resize-End
30
49
  A lightweight helper class that triggers a debounced 'madj2k-resize-end' event
31
50
  when the user finishes resizing the browser window.
@@ -43,20 +62,11 @@ A lightweight scrolling helper class that enables:
43
62
  The class is fully configurable via options and is designed to be used in CMS contexts
44
63
  where elements can be added, removed or re-ordered dynamically.
45
64
 
46
- # JS: OWL-Thumbnails
47
- A JavaScript helper class to create a main OWL carousel with a synchronized thumbnail navigation carousel.
48
-
49
- Supports flexible configurations for both the main and the thumbnail carousels,
50
- including:
51
- - Custom navigation
52
- - Syncing main carousel to clicked thumbnails
53
- - Syncing thumbnails to main carousel changes
54
- - Optionally equalizing thumbnail heights
55
- - Optionally preventing the centered thumbnail stage shift (for designs where thumbs should stay left aligned)
56
- - Responsive and CMS-friendly (works with dynamic content)
65
+ # JS: Toggled Overlay
66
+ This class toggles the visibility of any target element referenced by the `aria-controls`
67
+ attribute of a trigger element (button, link, etc.). It manages ARIA attributes for accessibility
68
+ and allows overlays to be closed externally via a custom event.
57
69
 
58
- This is especially useful for image galleries or product carousels in CMS setups (e.g. TYPO3, WordPress, etc.)
59
- where content may change dynamically.
60
70
 
61
71
  # Flyout-Navigation
62
72
  ## Usage
@@ -1,2 +1,2 @@
1
- import Madj2kBanner from './banner-2.0.0.js';
1
+ import Madj2kBanner from './banner-2.0.js';
2
2
  export { Madj2kBanner };
@@ -1 +1 @@
1
- @forward './banner-2.0.0';
1
+ @forward './banner-2.0';
@@ -0,0 +1,2 @@
1
+ import Madj2kOwlThumbnail from './owl-thumbnail-2.0.js';
2
+ export { Madj2kOwlThumbnail };
@@ -0,0 +1 @@
1
+ @forward 'owl-thumbnail-2.0';
@@ -1,2 +1,2 @@
1
- import Madj2kResizeEnd from './resize-end-2.0.0.js';
1
+ import Madj2kResizeEnd from './resize-end-2.0.js';
2
2
  export { Madj2kResizeEnd };
@@ -1 +1 @@
1
- @forward './resize-end-2.0.0';
1
+ @forward './resize-end-2.0';
@@ -1,2 +1,2 @@
1
- import Madj2kScrolling from './scrolling-2.0.0.js';
1
+ import Madj2kScrolling from './scrolling-2.0.js';
2
2
  export { Madj2kScrolling };
@@ -1 +1 @@
1
- @forward './scrolling-2.0.0';
1
+ @forward './scrolling-2.0';
@@ -0,0 +1,2 @@
1
+ import Madj2kToggledOverlay from './toggled-overlay-2.0.js';
2
+ export { Madj2kToggledOverlay };
@@ -0,0 +1 @@
1
+ @forward './toggled-overlay-2.0';
@@ -0,0 +1,125 @@
1
+ /**!
2
+ * ToggledOverlay
3
+ *
4
+ * @author Steffen Kroggel <developer@steffenkroggel.de>
5
+ * @copyright 2025 Steffen Kroggel
6
+ * @version 2.0.0
7
+ * @license GNU General Public License v3.0
8
+ * @see https://www.gnu.org/licenses/gpl-3.0.en.html
9
+ *
10
+ * This class toggles the visibility of any target element referenced by the `aria-controls`
11
+ * attribute of a trigger element (button, link, etc.). It manages ARIA attributes for accessibility
12
+ * and allows overlays to be closed externally via a custom event.
13
+ *
14
+ * @example
15
+ * Example HTML:
16
+ * <button class="js-toggled-overlay toggled-overlay-button"
17
+ * aria-label="Open overlay"
18
+ * aria-controls="my-overlay"
19
+ * aria-expanded="false">
20
+ * <span class="icon icon-info"></span>
21
+ * </button>
22
+ *
23
+ * <div id="my-overlay" class="toggled-overlay" aria-hidden="true">
24
+ * <!-- Overlay content -->
25
+ * </div>
26
+ *
27
+ * Example JavaScript:
28
+ * const overlayToggle = new Madj2kToggledOverlay('.js-toggled-overlay');
29
+ *
30
+ * // External close trigger
31
+ * window.dispatchEvent(new CustomEvent('madj2k-toggledoverlay-close'));
32
+ *
33
+ * Example CSS:
34
+ * .toggled-overlay {
35
+ * opacity: 0;
36
+ * visibility: hidden;
37
+ * transition: opacity 0.5s ease-in-out, visibility 0s linear 0.5s;
38
+ *
39
+ * &.is-visible {
40
+ * opacity: 1;
41
+ * visibility: visible;
42
+ * transition: opacity 0.5s ease-in-out, visibility 0s linear 0s;
43
+ * }
44
+ * }
45
+ *
46
+ * .toggled-overlay-button[aria-expanded="true"] .icon-info::before {
47
+ * content: "\e8bb"; // Example: "close" icon (replace with actual icon code)
48
+ * }
49
+ */
50
+ class Madj2kToggledOverlay {
51
+ /**
52
+ * Creates a new ToggledOverlay instance.
53
+ * @param {string} toggleSelector - CSS selector to identify all toggle buttons.
54
+ */
55
+ constructor(toggleSelector) {
56
+ /** @type {NodeListOf<HTMLElement>} */
57
+ this.toggles = document.querySelectorAll(toggleSelector);
58
+ this.init();
59
+ this.registerEvents();
60
+ }
61
+
62
+ /**
63
+ * Initializes toggle buttons and sets up toggle behavior.
64
+ */
65
+ init() {
66
+ this.toggles.forEach(toggle => {
67
+ const targetId = toggle.getAttribute('aria-controls');
68
+ const target = document.getElementById(targetId);
69
+ if (!target) return;
70
+
71
+ // Set initial ARIA state
72
+ target.setAttribute('aria-hidden', 'true');
73
+ toggle.setAttribute('aria-expanded', 'false');
74
+
75
+ toggle.addEventListener('click', () => {
76
+ const isExpanded = toggle.getAttribute('aria-expanded') === 'true';
77
+ toggle.setAttribute('aria-expanded', String(!isExpanded));
78
+ target.setAttribute('aria-hidden', String(isExpanded));
79
+ target.classList.toggle('is-visible', !isExpanded);
80
+ });
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Closes all overlays by removing the 'is-visible' class and updating ARIA attributes.
86
+ */
87
+ close() {
88
+ this.toggles.forEach(toggle => {
89
+ const targetId = toggle.getAttribute('aria-controls');
90
+ const target = document.getElementById(targetId);
91
+ if (!target) return;
92
+
93
+ toggle.setAttribute('aria-expanded', 'false');
94
+ target.setAttribute('aria-hidden', 'true');
95
+ target.classList.remove('is-visible');
96
+ });
97
+ }
98
+
99
+ /**
100
+ * Handles clicks outside the overlay and toggles to close them.
101
+ * @param {MouseEvent} event
102
+ */
103
+ handleClickOutside(event) {
104
+ this.toggles.forEach(toggle => {
105
+ const targetId = toggle.getAttribute('aria-controls');
106
+ const target = document.getElementById(targetId);
107
+ if (!target) return;
108
+
109
+ const clickedInsideToggle = toggle.contains(event.target);
110
+ const clickedInsideTarget = target.contains(event.target);
111
+
112
+ if (!clickedInsideToggle && !clickedInsideTarget && toggle.getAttribute('aria-expanded') === 'true') {
113
+ this.close();
114
+ }
115
+ });
116
+ }
117
+
118
+ /**
119
+ * Registers all global event listeners.
120
+ */
121
+ registerEvents() {
122
+ document.addEventListener('click', this.handleClickOutside.bind(this));
123
+ document.addEventListener('madj2k-toggledoverlay-close', this.close.bind(this));
124
+ }
125
+ }
@@ -0,0 +1,11 @@
1
+ .toggled-overlay {
2
+ opacity: 0;
3
+ visibility: hidden;
4
+ transition: opacity 0.5s ease-in-out, visibility 0s linear 0.5s;
5
+
6
+ &.is-visible {
7
+ opacity: 1;
8
+ visibility: visible;
9
+ transition: opacity 0.5s ease-in-out, visibility 0s linear 0s;
10
+ }
11
+ }
@@ -1,2 +0,0 @@
1
- import Madj2kOwlThumbnail from './owl-thumbnail-2.0.0.js';
2
- export { Madj2kOwlThumbnail };
@@ -1 +0,0 @@
1
- @forward './owl-thumbnail-2.0.0';
File without changes