@schukai/monster 4.43.1 → 4.43.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +1 -1
  3. package/source/components/accessibility/locale-picker.mjs +538 -538
  4. package/source/components/accessibility/locale-select.mjs +172 -172
  5. package/source/components/content/viewer.mjs +823 -823
  6. package/source/components/datatable/constants.mjs +15 -15
  7. package/source/components/datatable/datatable/header.mjs +253 -253
  8. package/source/components/datatable/datatable.mjs +1284 -1284
  9. package/source/components/datatable/filter.mjs +1339 -1342
  10. package/source/components/datatable/pagination.mjs +502 -502
  11. package/source/components/datatable/stylesheet/datatable.mjs +13 -6
  12. package/source/components/form/quantity.mjs +229 -229
  13. package/source/components/form/select.mjs +2963 -2963
  14. package/source/components/form/stylesheet/quantity.mjs +13 -6
  15. package/source/components/form/stylesheet/select.mjs +13 -6
  16. package/source/components/navigation/site-navigation.mjs +383 -210
  17. package/source/components/navigation/style/site-navigation.pcss +103 -15
  18. package/source/components/navigation/stylesheet/site-navigation.mjs +14 -7
  19. package/source/components/style/typography.css +4 -2
  20. package/source/dom/customelement.mjs +959 -963
  21. package/source/dom/slotted.mjs +87 -87
  22. package/source/i18n/util.mjs +149 -149
  23. package/source/monster.mjs +3 -0
  24. package/source/types/is.mjs +64 -64
  25. package/source/types/typeof.mjs +16 -16
  26. package/source/types/version.mjs +1 -1
  27. package/test/cases/monster.mjs +1 -1
  28. package/test/web/test.html +2 -2
  29. package/test/web/tests.js +2724 -1287
@@ -12,34 +12,24 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- /**
16
- * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
17
- * Node module: @schukai/monster
18
- *
19
- * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
20
- * SPDX-License-Identifier: AGPL-3.0
21
- */
22
-
23
15
  import {
24
- CustomElement,
25
- getSlottedElements,
26
- registerCustomElement,
27
- assembleMethodSymbol,
16
+ CustomElement,
17
+ getSlottedElements,
18
+ registerCustomElement,
19
+ assembleMethodSymbol,
28
20
  } from "../../dom/customelement.mjs";
29
21
  import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
30
22
  import { SiteNavigationStyleSheet } from "./stylesheet/site-navigation.mjs";
31
- // --- NEW: Import Floating UI ---
32
23
  import {
33
- computePosition,
34
- autoUpdate,
35
- flip,
36
- shift,
37
- offset,
38
- } from "https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.6.3/+esm";
24
+ computePosition,
25
+ autoUpdate,
26
+ flip,
27
+ shift,
28
+ offset,
29
+ } from "@floating-ui/dom";
39
30
 
40
31
  export { SiteNavigation };
41
32
 
42
- // Symbols for private class members
43
33
  const resizeObserverSymbol = Symbol("resizeObserver");
44
34
  const timerCallbackSymbol = Symbol("timerCallback");
45
35
  const navElementSymbol = Symbol("navElement");
@@ -48,223 +38,406 @@ const hiddenElementsSymbol = Symbol("hiddenElements");
48
38
  const hamburgerButtonSymbol = Symbol("hamburgerButton");
49
39
  const hamburgerNavSymbol = Symbol("hamburgerNav");
50
40
  const instanceSymbol = Symbol("instanceSymbol");
41
+ const activeSubmenuHiderSymbol = Symbol("activeSubmenuHider");
51
42
 
52
43
  /**
53
- * A responsive site navigation element that automatically moves items
54
- * that don't fit into a hamburger menu and handles submenus.
44
+ * Responsive site navigation component.
45
+ *
46
+ * @fragments /fragments/components/navigation/site-navigation/
47
+ *
48
+ * @example /examples/components/navigation/site-navigation-simple
49
+ *
50
+ * @since 4.41.0
51
+ * @copyright schukai GmbH
52
+ * @summary Responsive site navigation with hamburger menu and submenus
55
53
  */
56
54
  class SiteNavigation extends CustomElement {
57
- static get [instanceSymbol]() {
58
- return Symbol.for("@schukai/monster/components/navigation/site@@instance");
59
- }
60
-
61
- get defaults() {
62
- return Object.assign({}, super.defaults, {
63
- templates: { main: getTemplate() },
64
- });
65
- }
66
-
67
- [assembleMethodSymbol]() {
68
- super[assembleMethodSymbol]();
69
- initControlReferences.call(this);
70
- initEventHandler.call(this);
71
- }
72
-
73
- static getCSSStyleSheet() {
74
- return [SiteNavigationStyleSheet];
75
- }
76
-
77
- static getTag() {
78
- return "monster-site-navigation";
79
- }
80
-
81
- connectedCallback() {
82
- super.connectedCallback();
83
- attachResizeObserver.call(this);
84
- setTimeout(() => populateTabs.call(this), 0);
85
- }
86
-
87
- disconnectedCallback() {
88
- super.disconnectedCallback();
89
- detachResizeObserver.call(this);
90
- }
55
+ /**
56
+ * Returns a unique symbol for the instance.
57
+ * @returns {symbol}
58
+ */
59
+ static get [instanceSymbol]() {
60
+ return Symbol.for("@schukai/monster/components/navigation/site@@instance");
61
+ }
62
+
63
+ /**
64
+ * Returns the default options for the component.
65
+ * @returns {object}
66
+ */
67
+ get defaults() {
68
+ return Object.assign({}, super.defaults, {
69
+ templates: { main: getTemplate() },
70
+ });
71
+ }
72
+
73
+ /**
74
+ * Assembles the component and initializes controls and event handlers.
75
+ * @returns {void}
76
+ */
77
+ [assembleMethodSymbol]() {
78
+ super[assembleMethodSymbol]();
79
+ initControlReferences.call(this);
80
+ initEventHandler.call(this);
81
+ }
82
+
83
+ /**
84
+ * Returns the CSS stylesheet for the component.
85
+ * @returns {Array<CSSStyleSheet>}
86
+ */
87
+ static getCSSStyleSheet() {
88
+ return [SiteNavigationStyleSheet];
89
+ }
90
+
91
+ /**
92
+ * Returns the custom element tag name.
93
+ * @returns {string}
94
+ */
95
+ static getTag() {
96
+ return "monster-site-navigation";
97
+ }
98
+
99
+ /**
100
+ * Called when the component is connected to the DOM.
101
+ * @returns {void}
102
+ */
103
+ connectedCallback() {
104
+ super.connectedCallback();
105
+ attachResizeObserver.call(this);
106
+ setTimeout(() => populateTabs.call(this), 0);
107
+ }
108
+
109
+ /**
110
+ * Called when the component is disconnected from the DOM.
111
+ * @returns {void}
112
+ */
113
+ disconnectedCallback() {
114
+ super.disconnectedCallback();
115
+ detachResizeObserver.call(this);
116
+ }
91
117
  }
92
118
 
119
+ /**
120
+ * Initializes references to important control elements.
121
+ * @private
122
+ * @this {SiteNavigation}
123
+ * @returns {void}
124
+ */
93
125
  function initControlReferences() {
94
- if (!this.shadowRoot) throw new Error("Component requires a shadowRoot.");
95
- this[navElementSymbol] = this.shadowRoot.querySelector(
96
- '[data-monster-role="navigation"]',
97
- );
98
- this[visibleElementsSymbol] =
99
- this.shadowRoot.querySelector("#visible-elements");
100
- this[hiddenElementsSymbol] =
101
- this.shadowRoot.querySelector("#hidden-elements");
102
- this[hamburgerButtonSymbol] =
103
- this.shadowRoot.querySelector("#hamburger-button");
104
- this[hamburgerNavSymbol] = this.shadowRoot.querySelector(
105
- '[data-monster-role="hamburger-nav"]',
106
- );
126
+ if (!this.shadowRoot) throw new Error("Component requires a shadowRoot.");
127
+ this[navElementSymbol] = this.shadowRoot.querySelector(
128
+ '[data-monster-role="navigation"]',
129
+ );
130
+ this[visibleElementsSymbol] =
131
+ this.shadowRoot.querySelector("#visible-elements");
132
+ this[hiddenElementsSymbol] =
133
+ this.shadowRoot.querySelector("#hidden-elements");
134
+ this[hamburgerButtonSymbol] =
135
+ this.shadowRoot.querySelector("#hamburger-button");
136
+ this[hamburgerNavSymbol] = this.shadowRoot.querySelector(
137
+ '[data-monster-role="hamburger-nav"]',
138
+ );
107
139
  }
108
140
 
141
+ /**
142
+ * Initializes event handlers for hamburger menu and submenu interactions.
143
+ * @private
144
+ * @this {SiteNavigation}
145
+ * @returns {void}
146
+ */
109
147
  function initEventHandler() {
110
- if (!this.shadowRoot) throw new Error("Component requires a shadowRoot.");
111
- const hamburgerButton = this[hamburgerButtonSymbol];
112
- if (hamburgerButton) {
113
- hamburgerButton.addEventListener("click", () => {
114
- this.classList.toggle("is-open");
115
- });
116
- }
148
+ if (!this.shadowRoot) throw new Error("Component requires a shadowRoot.");
149
+
150
+ const hamburgerButton = this[hamburgerButtonSymbol];
151
+ const hamburgerNav = this[hamburgerNavSymbol];
152
+ let cleanup;
153
+
154
+ if (!hamburgerButton || !hamburgerNav) return;
155
+
156
+ const showMenu = () => {
157
+ hamburgerNav.style.display = "block";
158
+ cleanup = autoUpdate(hamburgerButton, hamburgerNav, () => {
159
+ computePosition(hamburgerButton, hamburgerNav, {
160
+ placement: "bottom-end",
161
+ middleware: [offset(8), flip(), shift({ padding: 8 })],
162
+ }).then(({ x, y }) => {
163
+ Object.assign(hamburgerNav.style, {
164
+ left: `${x}px`,
165
+ top: `${y}px`,
166
+ });
167
+ });
168
+ });
169
+ setTimeout(() => document.addEventListener("click", handleOutsideClick), 0);
170
+ };
171
+
172
+ const hideMenu = () => {
173
+ hamburgerNav.style.display = "none";
174
+ if (cleanup) {
175
+ cleanup();
176
+ }
177
+ document.removeEventListener("click", handleOutsideClick);
178
+ };
179
+
180
+ const handleOutsideClick = (event) => {
181
+ if (
182
+ !hamburgerButton.contains(event.target) &&
183
+ !hamburgerNav.contains(event.target)
184
+ ) {
185
+ hideMenu();
186
+ }
187
+ };
188
+
189
+ hamburgerButton.addEventListener("click", (event) => {
190
+ event.stopPropagation();
191
+ const isVisible = hamburgerNav.style.display === "block";
192
+ if (isVisible) {
193
+ hideMenu();
194
+ } else {
195
+ showMenu();
196
+ }
197
+ });
117
198
  }
118
199
 
200
+ /**
201
+ * Attaches a ResizeObserver to re-calculate tabs when the component's size changes.
202
+ * @private
203
+ * @this {SiteNavigation}
204
+ * @returns {void}
205
+ */
119
206
  function attachResizeObserver() {
120
- this[resizeObserverSymbol] = new ResizeObserver(() => {
121
- if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
122
- try {
123
- this[timerCallbackSymbol].touch();
124
- return;
125
- } catch (e) {
126
- delete this[timerCallbackSymbol];
127
- }
128
- }
129
- this[timerCallbackSymbol] = new DeadMansSwitch(200, () =>
130
- populateTabs.call(this),
131
- );
132
- });
133
- this[resizeObserverSymbol].observe(this[navElementSymbol]);
207
+ this[resizeObserverSymbol] = new ResizeObserver(() => {
208
+ if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
209
+ try {
210
+ this[timerCallbackSymbol].touch();
211
+ return;
212
+ } catch (e) {
213
+ delete this[timerCallbackSymbol];
214
+ }
215
+ }
216
+ this[timerCallbackSymbol] = new DeadMansSwitch(200, () =>
217
+ populateTabs.call(this),
218
+ );
219
+ });
220
+ this[resizeObserverSymbol].observe(this[navElementSymbol]);
134
221
  }
135
222
 
223
+ /**
224
+ * Detaches the ResizeObserver when the component is removed from the DOM.
225
+ * @private
226
+ * @this {SiteNavigation}
227
+ * @returns {void}
228
+ */
136
229
  function detachResizeObserver() {
137
- if (this[resizeObserverSymbol] instanceof ResizeObserver) {
138
- this[resizeObserverSymbol].disconnect();
139
- delete this[resizeObserverSymbol];
140
- }
230
+ if (this[resizeObserverSymbol] instanceof ResizeObserver) {
231
+ this[resizeObserverSymbol].disconnect();
232
+ delete this[resizeObserverSymbol];
233
+ }
141
234
  }
142
235
 
143
236
  /**
144
- * --- NEW: Function to set up a submenu with Floating UI ---
145
- * Handles intelligent hover behavior.
237
+ * Sets up a submenu based on its context (visible nav or hidden hamburger menu).
238
+ * @private
239
+ * @this {SiteNavigation}
146
240
  * @param {HTMLElement} parentLi The list item that contains the submenu.
241
+ * @param {'visible' | 'hidden'} context The context in which the submenu appears.
242
+ * @returns {void}
147
243
  */
148
- function setupSubmenu(parentLi) {
149
- const submenu = parentLi.querySelector("ul");
150
- if (!submenu) return; // No submenu to set up
151
-
152
- submenu.setAttribute("part", "submenu");
153
-
154
- let cleanup;
155
- let hideTimeout;
156
-
157
- const show = () => {
158
- clearTimeout(hideTimeout);
159
- submenu.style.display = "block";
160
- // autoUpdate handles positioning on scroll/resize
161
- cleanup = autoUpdate(parentLi, submenu, () => {
162
- computePosition(parentLi, submenu, {
163
- placement: "bottom-start",
164
- middleware: [offset(8), flip(), shift({ padding: 8 })],
165
- }).then(({ x, y }) => {
166
- Object.assign(submenu.style, {
167
- left: `${x}px`,
168
- top: `${y}px`,
169
- });
170
- });
171
- });
172
- };
173
-
174
- const hide = () => {
175
- // Use a timeout to create a "grace period", allowing diagonal mouse movement.
176
- hideTimeout = setTimeout(() => {
177
- submenu.style.display = "none";
178
- if (cleanup) {
179
- cleanup(); // Stop the autoUpdate listeners
180
- }
181
- }, 200); // 200ms delay
182
- };
183
-
184
- // Show on entering the parent, hide on leaving.
185
- parentLi.addEventListener("mouseenter", show);
186
- parentLi.addEventListener("mouseleave", hide);
187
-
188
- // If the mouse enters the submenu itself, cancel the pending hide command.
189
- submenu.addEventListener("mouseenter", () => clearTimeout(hideTimeout));
190
- submenu.addEventListener("mouseleave", hide);
244
+ function setupSubmenu(parentLi, context = "visible") {
245
+ const submenu = parentLi.querySelector("ul");
246
+ if (!submenu) return;
247
+
248
+ submenu.setAttribute("part", "submenu");
249
+
250
+ if (context === "visible") {
251
+ const component = this;
252
+ let cleanup;
253
+ let hideTimeout;
254
+
255
+ const immediateHide = () => {
256
+ submenu.style.display = "none";
257
+ if (cleanup) {
258
+ cleanup();
259
+ cleanup = null;
260
+ }
261
+ if (component[activeSubmenuHiderSymbol] === immediateHide) {
262
+ component[activeSubmenuHiderSymbol] = null;
263
+ }
264
+ };
265
+
266
+ const show = () => {
267
+ clearTimeout(hideTimeout);
268
+ if (
269
+ component[activeSubmenuHiderSymbol] &&
270
+ component[activeSubmenuHiderSymbol] !== immediateHide
271
+ ) {
272
+ component[activeSubmenuHiderSymbol]();
273
+ }
274
+ submenu.style.display = "block";
275
+ if (!cleanup) {
276
+ cleanup = autoUpdate(parentLi, submenu, () => {
277
+ computePosition(parentLi, submenu, {
278
+ placement: "bottom-start",
279
+ middleware: [offset(8), flip(), shift({ padding: 8 })],
280
+ }).then(({ x, y }) => {
281
+ Object.assign(submenu.style, { left: `${x}px`, top: `${y}px` });
282
+ });
283
+ });
284
+ }
285
+ component[activeSubmenuHiderSymbol] = immediateHide;
286
+ };
287
+
288
+ const hideWithDelay = () => {
289
+ hideTimeout = setTimeout(immediateHide, 200);
290
+ };
291
+
292
+ parentLi.addEventListener("mouseenter", show);
293
+ parentLi.addEventListener("mouseleave", hideWithDelay);
294
+ submenu.addEventListener("mouseenter", () => clearTimeout(hideTimeout));
295
+ submenu.addEventListener("mouseleave", hideWithDelay);
296
+ } else {
297
+ submenu.style.display = "none";
298
+ const anchor = parentLi.querySelector("a");
299
+ if (anchor) {
300
+ anchor.addEventListener("click", (event) => {
301
+ event.preventDefault();
302
+ event.stopPropagation();
303
+ const isVisible = submenu.style.display === "block";
304
+ submenu.style.display = isVisible ? "none" : "block";
305
+ });
306
+ }
307
+ }
191
308
  }
192
309
 
310
+ /**
311
+ * Calculates which navigation items fit in the visible area and moves the rest
312
+ * to a hidden "hamburger" menu.
313
+ * @private
314
+ * @this {SiteNavigation}
315
+ * @returns {void}
316
+ */
193
317
  function populateTabs() {
194
- const visibleList = this[visibleElementsSymbol];
195
- const hiddenList = this[hiddenElementsSymbol];
196
- const hamburgerNav = this[hamburgerNavSymbol];
197
-
198
- const sourceItems = Array.from(
199
- getSlottedElements.call(this, "ul > li"),
200
- ).filter((item) => item instanceof HTMLElement);
201
-
202
- // 1. PREPARATION
203
- visibleList.style.visibility = "hidden";
204
- hamburgerNav.style.display = "none";
205
- visibleList.innerHTML = "";
206
- hiddenList.innerHTML = "";
207
-
208
- const maxWidth = this[navElementSymbol].clientWidth;
209
- if (maxWidth === 0) {
210
- visibleList.style.visibility = "visible";
211
- return;
212
- }
213
-
214
- // 2. MEASUREMENT
215
- const measurementList = visibleList.cloneNode(true);
216
- Object.assign(measurementList.style, {
217
- position: "absolute",
218
- left: "0",
219
- top: "0",
220
- width: "auto",
221
- visibility: "hidden",
222
- });
223
- this.shadowRoot.appendChild(measurementList);
224
-
225
- const itemsToMove = [];
226
- for (const item of sourceItems) {
227
- const itemClone = item.cloneNode(true);
228
- // Important: For measurement, hide submenus so they don't affect width.
229
- const submenu = itemClone.querySelector("ul");
230
- if (submenu) submenu.style.display = "none";
231
-
232
- measurementList.appendChild(itemClone);
233
-
234
- if (measurementList.scrollWidth > maxWidth) {
235
- break;
236
- } else {
237
- itemsToMove.push(item);
238
- }
239
- }
240
-
241
- this.shadowRoot.removeChild(measurementList);
242
-
243
- // 3. DOM MANIPULATION
244
- const visibleItems = itemsToMove;
245
- const hiddenItems = sourceItems.slice(visibleItems.length);
246
-
247
- // Populate visible list and set up submenus
248
- if (visibleItems.length > 0) {
249
- visibleList.append(...visibleItems.map((item) => item.cloneNode(true)));
250
- // After appending, initialize submenus for visible items
251
- visibleList.querySelectorAll("li").forEach(setupSubmenu);
252
- }
253
-
254
- // Populate hidden list and set up submenus
255
- if (hiddenItems.length > 0) {
256
- hiddenList.append(...hiddenItems.map((item) => item.cloneNode(true)));
257
- hamburgerNav.style.display = "flex";
258
- // After appending, initialize submenus for hidden items as well
259
- hiddenList.querySelectorAll("li").forEach(setupSubmenu);
260
- }
261
-
262
- visibleList.style.visibility = "visible";
318
+ const visibleList = this[visibleElementsSymbol];
319
+ const hiddenList = this[hiddenElementsSymbol];
320
+ const hamburgerButton = this[hamburgerButtonSymbol];
321
+ const hamburgerNav = this[hamburgerNavSymbol];
322
+
323
+ const topLevelUl = [...getSlottedElements.call(this, "ul")].find(
324
+ (ul) => ul.parentElement === this,
325
+ );
326
+
327
+ if (!topLevelUl) {
328
+ visibleList.style.visibility = "visible";
329
+ hamburgerButton.style.display = "none";
330
+ return;
331
+ }
332
+
333
+ const sourceItems = Array.from(topLevelUl.children).filter(
334
+ (item) => item.tagName === "LI",
335
+ );
336
+
337
+ visibleList.style.visibility = "hidden";
338
+ hamburgerButton.style.display = "none";
339
+ hamburgerNav.style.display = "none";
340
+ visibleList.innerHTML = "";
341
+ hiddenList.innerHTML = "";
342
+
343
+ const originalDisplay = hamburgerButton.style.display;
344
+ hamburgerButton.style.visibility = "hidden";
345
+ hamburgerButton.style.display = "flex";
346
+ const hamburgerWidth = hamburgerButton.offsetWidth;
347
+ hamburgerButton.style.display = originalDisplay;
348
+ hamburgerButton.style.visibility = "visible";
349
+
350
+ const navWidth = this[navElementSymbol].clientWidth;
351
+ if (navWidth === 0) {
352
+ visibleList.style.visibility = "visible";
353
+ return;
354
+ }
355
+
356
+ const measurementList = visibleList.cloneNode(true);
357
+ Object.assign(measurementList.style, {
358
+ position: "absolute",
359
+ left: "0",
360
+ top: "0",
361
+ width: "auto",
362
+ visibility: "hidden",
363
+ });
364
+ this.shadowRoot.appendChild(measurementList);
365
+
366
+ const itemsToMove = [];
367
+ const availableWidthForTabs = navWidth - hamburgerWidth;
368
+
369
+ for (let i = 0; i < sourceItems.length; i++) {
370
+ const item = sourceItems[i];
371
+ const itemClone = item.cloneNode(true);
372
+ const submenu = itemClone.querySelector("ul");
373
+ if (submenu) submenu.style.display = "none";
374
+
375
+ measurementList.appendChild(itemClone);
376
+
377
+ const isLastItem = i === sourceItems.length - 1;
378
+ const effectiveMaxWidth = isLastItem ? navWidth : availableWidthForTabs;
379
+
380
+ if (measurementList.scrollWidth > effectiveMaxWidth) {
381
+ break;
382
+ } else {
383
+ itemsToMove.push(item);
384
+ }
385
+ }
386
+ this.shadowRoot.removeChild(measurementList);
387
+
388
+ const visibleItems = itemsToMove;
389
+ const hiddenItems = sourceItems.slice(visibleItems.length);
390
+
391
+ if (visibleItems.length > 0) {
392
+ const clonedVisibleItems = visibleItems.map((item) => {
393
+ const liClone = item.cloneNode(true);
394
+ const aClone = liClone.querySelector("a");
395
+
396
+ liClone.setAttribute("part", "nav-item");
397
+ if (aClone) aClone.setAttribute("part", "nav-link");
398
+
399
+ if (item.classList.contains("active")) {
400
+ liClone.setAttribute("part", "nav-item nav-item-active");
401
+ if (aClone) aClone.setAttribute("part", "nav-link nav-link-active");
402
+ }
403
+ return liClone;
404
+ });
405
+ visibleList.append(...clonedVisibleItems);
406
+ visibleList
407
+ .querySelectorAll("li")
408
+ .forEach((li) => setupSubmenu.call(this, li, "visible"));
409
+ }
410
+
411
+ if (hiddenItems.length > 0) {
412
+ const clonedHiddenItems = hiddenItems.map((item) => {
413
+ const liClone = item.cloneNode(true);
414
+ const aClone = liClone.querySelector("a");
415
+
416
+ liClone.setAttribute("part", "nav-item");
417
+ if (aClone) aClone.setAttribute("part", "nav-link");
418
+ if (item.classList.contains("active")) {
419
+ liClone.setAttribute("part", "nav-item nav-item-active");
420
+ if (aClone) aClone.setAttribute("part", "nav-link nav-link-active");
421
+ }
422
+ return liClone;
423
+ });
424
+ hiddenList.append(...clonedHiddenItems);
425
+ hamburgerButton.style.display = "flex";
426
+ hiddenList
427
+ .querySelectorAll("li")
428
+ .forEach((li) => setupSubmenu.call(this, li, "hidden"));
429
+ }
430
+
431
+ visibleList.style.visibility = "visible";
263
432
  }
264
433
 
434
+ /**
435
+ * Returns the HTML template for the component's shadow DOM.
436
+ * @private
437
+ * @returns {string}
438
+ */
265
439
  function getTemplate() {
266
- // language=HTML
267
- return `
440
+ return `
268
441
  <div data-monster-role="control" part="control">
269
442
  <nav data-monster-role="navigation" role="navigation" part="nav">
270
443
  <ul id="visible-elements" part="visible-list"></ul>