@schukai/monster 4.45.5 → 4.46.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/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/source/components/accessibility/locale-select.mjs +200 -200
- package/source/components/datatable/datatable.mjs +1283 -1283
- package/source/components/form/login.mjs +117 -20
- package/source/components/form/select.mjs +3012 -3012
- package/source/components/form/style/login.pcss +16 -1
- package/source/components/form/stylesheet/login.mjs +1 -1
- package/source/components/layout/slider.mjs +686 -686
- package/source/components/navigation/site-navigation.mjs +578 -578
- package/source/components/navigation/stylesheet/site-navigation.mjs +13 -6
- package/source/components/navigation/wizard-navigation.mjs +391 -391
- package/source/monster.mjs +1 -1
|
@@ -13,20 +13,20 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
CustomElement,
|
|
17
|
+
getSlottedElements,
|
|
18
|
+
registerCustomElement,
|
|
19
|
+
assembleMethodSymbol,
|
|
20
20
|
} from "../../dom/customelement.mjs";
|
|
21
21
|
import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
|
|
22
22
|
import { SiteNavigationStyleSheet } from "./stylesheet/site-navigation.mjs";
|
|
23
23
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
computePosition,
|
|
25
|
+
autoUpdate,
|
|
26
|
+
flip,
|
|
27
|
+
shift,
|
|
28
|
+
offset,
|
|
29
|
+
size,
|
|
30
30
|
} from "@floating-ui/dom";
|
|
31
31
|
import { fireCustomEvent } from "../../dom/events.mjs";
|
|
32
32
|
|
|
@@ -64,59 +64,59 @@ const hamburgerCloseButtonSymbol = Symbol("hamburgerCloseButton");
|
|
|
64
64
|
* @fires monster-submenu-hide - Fired when a submenu is hidden. The event detail contains `{context, trigger, submenu, level}`.
|
|
65
65
|
*/
|
|
66
66
|
class SiteNavigation extends CustomElement {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
67
|
+
static get [instanceSymbol]() {
|
|
68
|
+
return Symbol.for("@schukai/monster/components/navigation/site@@instance");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Configuration options for the SiteNavigation component.
|
|
73
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
|
74
|
+
*
|
|
75
|
+
* To set these options via an HTML tag, use the `data-monster-options` attribute.
|
|
76
|
+
* The individual configuration values are detailed in the table below.
|
|
77
|
+
*
|
|
78
|
+
* @property {Object} templates - Template definitions.
|
|
79
|
+
* @property {string} templates.main - The main HTML template for the component.
|
|
80
|
+
* @property {string} interactionModel="auto" - Defines the interaction with submenus. Possible values: `auto`, `click`, `hover`. With `auto`, `hover` is used on desktop and `click` is used in the hamburger menu.
|
|
81
|
+
* @property {Object} features - Container for additional feature flags.
|
|
82
|
+
* @property {boolean} features.resetOnClose=true - If `true`, all open submenus within the hamburger menu will be reset when it is closed.
|
|
83
|
+
*/
|
|
84
|
+
get defaults() {
|
|
85
|
+
return Object.assign({}, super.defaults, {
|
|
86
|
+
templates: { main: getTemplate() },
|
|
87
|
+
interactionModel: "auto", // 'auto', 'click', 'hover'
|
|
88
|
+
features: {
|
|
89
|
+
resetOnClose: true,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
[assembleMethodSymbol]() {
|
|
95
|
+
super[assembleMethodSymbol]();
|
|
96
|
+
initControlReferences.call(this);
|
|
97
|
+
initEventHandler.call(this);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static getCSSStyleSheet() {
|
|
101
|
+
return [SiteNavigationStyleSheet];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static getTag() {
|
|
105
|
+
return "monster-site-navigation";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
connectedCallback() {
|
|
109
|
+
super.connectedCallback();
|
|
110
|
+
attachResizeObserver.call(this);
|
|
111
|
+
requestAnimationFrame(() => {
|
|
112
|
+
populateTabs.call(this);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
disconnectedCallback() {
|
|
117
|
+
super.disconnectedCallback();
|
|
118
|
+
detachResizeObserver.call(this);
|
|
119
|
+
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/**
|
|
@@ -125,22 +125,22 @@ class SiteNavigation extends CustomElement {
|
|
|
125
125
|
* @this {SiteNavigation}
|
|
126
126
|
*/
|
|
127
127
|
function initControlReferences() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
128
|
+
if (!this.shadowRoot) throw new Error("Component requires a shadowRoot.");
|
|
129
|
+
this[navElementSymbol] = this.shadowRoot.querySelector(
|
|
130
|
+
'[data-monster-role="navigation"]',
|
|
131
|
+
);
|
|
132
|
+
this[visibleElementsSymbol] =
|
|
133
|
+
this.shadowRoot.querySelector("#visible-elements");
|
|
134
|
+
this[hiddenElementsSymbol] =
|
|
135
|
+
this.shadowRoot.querySelector("#hidden-elements");
|
|
136
|
+
this[hamburgerButtonSymbol] =
|
|
137
|
+
this.shadowRoot.querySelector("#hamburger-button");
|
|
138
|
+
this[hamburgerNavSymbol] = this.shadowRoot.querySelector(
|
|
139
|
+
'[data-monster-role="hamburger-nav"]',
|
|
140
|
+
);
|
|
141
|
+
this[hamburgerCloseButtonSymbol] = this.shadowRoot.querySelector(
|
|
142
|
+
'[part="hamburger-close-button"]',
|
|
143
|
+
);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
/**
|
|
@@ -149,122 +149,122 @@ function initControlReferences() {
|
|
|
149
149
|
* @this {SiteNavigation}
|
|
150
150
|
*/
|
|
151
151
|
function initEventHandler() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
152
|
+
if (!this.shadowRoot) throw new Error("Component requires a shadowRoot.");
|
|
153
|
+
|
|
154
|
+
const hamburgerButton = this[hamburgerButtonSymbol];
|
|
155
|
+
const hamburgerNav = this[hamburgerNavSymbol];
|
|
156
|
+
const hamburgerCloseButton = this[hamburgerCloseButtonSymbol];
|
|
157
|
+
let cleanup;
|
|
158
|
+
|
|
159
|
+
if (!hamburgerButton || !hamburgerNav || !hamburgerCloseButton) return;
|
|
160
|
+
|
|
161
|
+
const getBestPositionStrategy = (element) => {
|
|
162
|
+
let parent = element.parentElement;
|
|
163
|
+
while (parent) {
|
|
164
|
+
const parentPosition = window.getComputedStyle(parent).position;
|
|
165
|
+
if (["fixed", "sticky"].includes(parentPosition)) {
|
|
166
|
+
return "fixed";
|
|
167
|
+
}
|
|
168
|
+
parent = parent.parentElement;
|
|
169
|
+
}
|
|
170
|
+
return "absolute";
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const handleOutsideClick = (event) => {
|
|
174
|
+
if (
|
|
175
|
+
!hamburgerButton.contains(event.target) &&
|
|
176
|
+
!hamburgerNav.contains(event.target)
|
|
177
|
+
) {
|
|
178
|
+
hideMenu();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const hideMenu = () => {
|
|
183
|
+
hamburgerNav.style.display = "none";
|
|
184
|
+
document.body.classList.remove("monster-navigation-open");
|
|
185
|
+
|
|
186
|
+
fireCustomEvent(this, "monster-hamburger-hide", {
|
|
187
|
+
button: hamburgerButton,
|
|
188
|
+
menu: hamburgerNav,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
if (this.getOption("features.resetOnClose") === true) {
|
|
192
|
+
this[hiddenElementsSymbol]
|
|
193
|
+
.querySelectorAll(".is-open")
|
|
194
|
+
.forEach((submenu) => submenu.classList.remove("is-open"));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (cleanup) {
|
|
198
|
+
cleanup();
|
|
199
|
+
cleanup = undefined;
|
|
200
|
+
}
|
|
201
|
+
document.removeEventListener("click", handleOutsideClick);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
this[hideHamburgerMenuSymbol] = hideMenu;
|
|
205
|
+
|
|
206
|
+
const showMenu = () => {
|
|
207
|
+
this[activeSubmenuHiderSymbol]?.();
|
|
208
|
+
hamburgerNav.style.display = "block";
|
|
209
|
+
document.body.classList.add("monster-navigation-open");
|
|
210
|
+
|
|
211
|
+
fireCustomEvent(this, "monster-hamburger-show", {
|
|
212
|
+
button: hamburgerButton,
|
|
213
|
+
menu: hamburgerNav,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
hamburgerNav.scrollIntoView({ block: "start", behavior: "smooth" });
|
|
217
|
+
|
|
218
|
+
cleanup = autoUpdate(hamburgerButton, hamburgerNav, () => {
|
|
219
|
+
if (window.innerWidth > 768) {
|
|
220
|
+
const strategy = getBestPositionStrategy(this);
|
|
221
|
+
|
|
222
|
+
computePosition(hamburgerButton, hamburgerNav, {
|
|
223
|
+
placement: "bottom-end",
|
|
224
|
+
strategy: strategy,
|
|
225
|
+
middleware: [
|
|
226
|
+
offset(8),
|
|
227
|
+
flip(),
|
|
228
|
+
shift({ padding: 8 }),
|
|
229
|
+
size({
|
|
230
|
+
apply: ({ availableHeight, elements }) => {
|
|
231
|
+
Object.assign(elements.floating.style, {
|
|
232
|
+
maxHeight: `${availableHeight}px`,
|
|
233
|
+
overflowY: "auto",
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
padding: 8,
|
|
237
|
+
}),
|
|
238
|
+
],
|
|
239
|
+
}).then(({ x, y, strategy }) => {
|
|
240
|
+
Object.assign(hamburgerNav.style, {
|
|
241
|
+
position: strategy,
|
|
242
|
+
left: `${x}px`,
|
|
243
|
+
top: `${y}px`,
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
} else {
|
|
247
|
+
// Mobile view (fullscreen overlay), position is handled by CSS
|
|
248
|
+
Object.assign(hamburgerNav.style, { position: "", left: "", top: "" });
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
setTimeout(() => document.addEventListener("click", handleOutsideClick), 0);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
hamburgerButton.addEventListener("click", (event) => {
|
|
255
|
+
event.stopPropagation();
|
|
256
|
+
const isVisible = hamburgerNav.style.display === "block";
|
|
257
|
+
if (isVisible) {
|
|
258
|
+
hideMenu();
|
|
259
|
+
} else {
|
|
260
|
+
showMenu();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
hamburgerCloseButton.addEventListener("click", (event) => {
|
|
265
|
+
event.stopPropagation();
|
|
266
|
+
hideMenu();
|
|
267
|
+
});
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
/**
|
|
@@ -274,22 +274,22 @@ function initEventHandler() {
|
|
|
274
274
|
* @this {SiteNavigation}
|
|
275
275
|
*/
|
|
276
276
|
function attachResizeObserver() {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
277
|
+
this[resizeObserverSymbol] = new ResizeObserver(() => {
|
|
278
|
+
if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
|
|
279
|
+
try {
|
|
280
|
+
this[timerCallbackSymbol].touch();
|
|
281
|
+
return;
|
|
282
|
+
} catch (e) {
|
|
283
|
+
delete this[timerCallbackSymbol];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
|
|
287
|
+
requestAnimationFrame(() => {
|
|
288
|
+
populateTabs.call(this);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
this[resizeObserverSymbol].observe(this);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
/**
|
|
@@ -298,10 +298,10 @@ function attachResizeObserver() {
|
|
|
298
298
|
* @this {SiteNavigation}
|
|
299
299
|
*/
|
|
300
300
|
function detachResizeObserver() {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
301
|
+
if (this[resizeObserverSymbol] instanceof ResizeObserver) {
|
|
302
|
+
this[resizeObserverSymbol].disconnect();
|
|
303
|
+
delete this[resizeObserverSymbol];
|
|
304
|
+
}
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
/**
|
|
@@ -314,240 +314,240 @@ function detachResizeObserver() {
|
|
|
314
314
|
* @param {number} level The nesting level of the submenu (starts at 1).
|
|
315
315
|
*/
|
|
316
316
|
function setupSubmenu(parentLi, context = "visible", level = 1) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
317
|
+
const submenu = parentLi.querySelector(
|
|
318
|
+
":scope > ul, :scope > div[part='mega-menu']",
|
|
319
|
+
);
|
|
320
|
+
if (!submenu) return;
|
|
321
|
+
|
|
322
|
+
if (submenu.tagName === "UL") {
|
|
323
|
+
submenu.setAttribute("part", "submenu");
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const interaction = this.getOption("interactionModel", "auto");
|
|
327
|
+
const isTouchDevice =
|
|
328
|
+
"ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
329
|
+
|
|
330
|
+
const effectiveInteraction =
|
|
331
|
+
interaction === "auto"
|
|
332
|
+
? context === "visible"
|
|
333
|
+
? "hover"
|
|
334
|
+
: "click"
|
|
335
|
+
: interaction;
|
|
336
|
+
|
|
337
|
+
const component = this;
|
|
338
|
+
let cleanup;
|
|
339
|
+
|
|
340
|
+
const immediateHide = () => {
|
|
341
|
+
submenu.style.display = "none";
|
|
342
|
+
Object.assign(submenu.style, {
|
|
343
|
+
maxHeight: "",
|
|
344
|
+
overflowY: "",
|
|
345
|
+
});
|
|
346
|
+
submenu
|
|
347
|
+
.querySelectorAll(
|
|
348
|
+
"ul[style*='display: block'], div[part='mega-menu'][style*='display: block']",
|
|
349
|
+
)
|
|
350
|
+
.forEach((sub) => {
|
|
351
|
+
sub.style.display = "none";
|
|
352
|
+
});
|
|
353
|
+
fireCustomEvent(this, "monster-submenu-hide", {
|
|
354
|
+
context,
|
|
355
|
+
trigger: parentLi,
|
|
356
|
+
submenu,
|
|
357
|
+
level,
|
|
358
|
+
});
|
|
359
|
+
if (cleanup) {
|
|
360
|
+
cleanup();
|
|
361
|
+
cleanup = null;
|
|
362
|
+
}
|
|
363
|
+
if (level === 1 && component[activeSubmenuHiderSymbol] === immediateHide) {
|
|
364
|
+
component[activeSubmenuHiderSymbol] = null;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const show = () => {
|
|
369
|
+
component[hideHamburgerMenuSymbol]?.();
|
|
370
|
+
if (level === 1) {
|
|
371
|
+
if (
|
|
372
|
+
component[activeSubmenuHiderSymbol] &&
|
|
373
|
+
component[activeSubmenuHiderSymbol] !== immediateHide
|
|
374
|
+
) {
|
|
375
|
+
component[activeSubmenuHiderSymbol]();
|
|
376
|
+
}
|
|
377
|
+
component[activeSubmenuHiderSymbol] = immediateHide;
|
|
378
|
+
} else {
|
|
379
|
+
[...parentLi.parentElement.children]
|
|
380
|
+
.filter((li) => li !== parentLi)
|
|
381
|
+
.forEach((sibling) => {
|
|
382
|
+
const siblingSubmenu = sibling.querySelector(
|
|
383
|
+
":scope > ul, :scope > div[part='mega-menu']",
|
|
384
|
+
);
|
|
385
|
+
if (siblingSubmenu) {
|
|
386
|
+
siblingSubmenu.style.display = "none";
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
submenu.style.display = "block";
|
|
391
|
+
fireCustomEvent(this, "monster-submenu-show", {
|
|
392
|
+
context,
|
|
393
|
+
trigger: parentLi,
|
|
394
|
+
submenu,
|
|
395
|
+
level,
|
|
396
|
+
});
|
|
397
|
+
if (!cleanup) {
|
|
398
|
+
cleanup = autoUpdate(parentLi, submenu, () => {
|
|
399
|
+
const middleware = [offset(8), flip(), shift({ padding: 8 })];
|
|
400
|
+
const containsSubmenus = submenu.querySelector(
|
|
401
|
+
"ul, div[part='mega-menu']",
|
|
402
|
+
);
|
|
403
|
+
if (!containsSubmenus) {
|
|
404
|
+
middleware.push(
|
|
405
|
+
size({
|
|
406
|
+
apply: ({ availableHeight, elements }) => {
|
|
407
|
+
Object.assign(elements.floating.style, {
|
|
408
|
+
maxHeight: `${availableHeight}px`,
|
|
409
|
+
overflowY: "auto",
|
|
410
|
+
});
|
|
411
|
+
},
|
|
412
|
+
padding: 8,
|
|
413
|
+
}),
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
computePosition(parentLi, submenu, {
|
|
417
|
+
placement: level === 1 ? "bottom-start" : "right-start",
|
|
418
|
+
middleware: middleware,
|
|
419
|
+
}).then(({ x, y, strategy }) => {
|
|
420
|
+
Object.assign(submenu.style, {
|
|
421
|
+
position: strategy,
|
|
422
|
+
left: `${x}px`,
|
|
423
|
+
top: `${y}px`,
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
if (effectiveInteraction === "hover" && isTouchDevice) {
|
|
431
|
+
let lastTap = 0;
|
|
432
|
+
const DOUBLE_TAP_DELAY = 300;
|
|
433
|
+
const anchor = parentLi.querySelector(":scope > a");
|
|
434
|
+
|
|
435
|
+
if (!anchor) return;
|
|
436
|
+
|
|
437
|
+
const handleOutsideClickForSubmenu = (event) => {
|
|
438
|
+
if (
|
|
439
|
+
submenu.style.display === "block" &&
|
|
440
|
+
!parentLi.contains(event.target)
|
|
441
|
+
) {
|
|
442
|
+
immediateHide();
|
|
443
|
+
document.removeEventListener(
|
|
444
|
+
"click",
|
|
445
|
+
handleOutsideClickForSubmenu,
|
|
446
|
+
true,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
anchor.addEventListener("click", (event) => {
|
|
452
|
+
const now = Date.now();
|
|
453
|
+
const timeSinceLastTap = now - lastTap;
|
|
454
|
+
lastTap = now;
|
|
455
|
+
|
|
456
|
+
if (timeSinceLastTap < DOUBLE_TAP_DELAY && timeSinceLastTap > 0) {
|
|
457
|
+
lastTap = 0;
|
|
458
|
+
document.removeEventListener(
|
|
459
|
+
"click",
|
|
460
|
+
handleOutsideClickForSubmenu,
|
|
461
|
+
true,
|
|
462
|
+
);
|
|
463
|
+
immediateHide();
|
|
464
|
+
} else {
|
|
465
|
+
event.preventDefault();
|
|
466
|
+
event.stopPropagation();
|
|
467
|
+
|
|
468
|
+
const isMenuOpen = submenu.style.display === "block";
|
|
469
|
+
|
|
470
|
+
if (isMenuOpen) {
|
|
471
|
+
document.removeEventListener(
|
|
472
|
+
"click",
|
|
473
|
+
handleOutsideClickForSubmenu,
|
|
474
|
+
true,
|
|
475
|
+
);
|
|
476
|
+
immediateHide();
|
|
477
|
+
} else {
|
|
478
|
+
show();
|
|
479
|
+
setTimeout(() => {
|
|
480
|
+
document.addEventListener(
|
|
481
|
+
"click",
|
|
482
|
+
handleOutsideClickForSubmenu,
|
|
483
|
+
true,
|
|
484
|
+
);
|
|
485
|
+
}, 0);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
} else if (effectiveInteraction === "hover" && !isTouchDevice) {
|
|
490
|
+
let hideTimeout;
|
|
491
|
+
let isHovering = false;
|
|
492
|
+
|
|
493
|
+
const handleMouseEnter = () => {
|
|
494
|
+
isHovering = true;
|
|
495
|
+
clearTimeout(hideTimeout);
|
|
496
|
+
if (submenu.style.display !== "block") {
|
|
497
|
+
show();
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
const handleMouseLeave = () => {
|
|
502
|
+
isHovering = false;
|
|
503
|
+
hideTimeout = setTimeout(() => {
|
|
504
|
+
if (!isHovering) {
|
|
505
|
+
immediateHide();
|
|
506
|
+
}
|
|
507
|
+
}, 250);
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
parentLi.addEventListener("mouseenter", handleMouseEnter);
|
|
511
|
+
parentLi.addEventListener("mouseleave", handleMouseLeave);
|
|
512
|
+
submenu.addEventListener("mouseenter", handleMouseEnter);
|
|
513
|
+
submenu.addEventListener("mouseleave", handleMouseLeave);
|
|
514
|
+
} else {
|
|
515
|
+
const anchor = parentLi.querySelector(":scope > a");
|
|
516
|
+
if (anchor) {
|
|
517
|
+
anchor.addEventListener("click", (event) => {
|
|
518
|
+
event.preventDefault();
|
|
519
|
+
event.stopPropagation();
|
|
520
|
+
if (!submenu.classList.contains("is-open")) {
|
|
521
|
+
[...parentLi.parentElement.children]
|
|
522
|
+
.filter((li) => li !== parentLi)
|
|
523
|
+
.forEach((sibling) => {
|
|
524
|
+
const siblingSubmenu = sibling.querySelector(
|
|
525
|
+
":scope > ul, :scope > div[part='mega-menu']",
|
|
526
|
+
);
|
|
527
|
+
if (siblingSubmenu) {
|
|
528
|
+
siblingSubmenu.classList.remove("is-open");
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
const isOpen = submenu.classList.toggle("is-open");
|
|
533
|
+
const eventName = isOpen
|
|
534
|
+
? "monster-submenu-show"
|
|
535
|
+
: "monster-submenu-hide";
|
|
536
|
+
fireCustomEvent(this, eventName, {
|
|
537
|
+
context,
|
|
538
|
+
trigger: parentLi,
|
|
539
|
+
submenu,
|
|
540
|
+
level,
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (submenu.tagName === "UL") {
|
|
547
|
+
submenu
|
|
548
|
+
.querySelectorAll(":scope > li")
|
|
549
|
+
.forEach((li) => setupSubmenu.call(this, li, context, level + 1));
|
|
550
|
+
}
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
/**
|
|
@@ -558,20 +558,20 @@ function setupSubmenu(parentLi, context = "visible", level = 1) {
|
|
|
558
558
|
* @returns {HTMLLIElement} The cloned and configured list item.
|
|
559
559
|
*/
|
|
560
560
|
function cloneNavItem(item) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
561
|
+
const liClone = item.cloneNode(true);
|
|
562
|
+
const aClone = liClone.querySelector("a");
|
|
563
|
+
let navItemPart = "nav-item";
|
|
564
|
+
let navLinkPart = "nav-link";
|
|
565
565
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
566
|
+
if (item.classList.contains("active")) {
|
|
567
|
+
navItemPart += " nav-item-active";
|
|
568
|
+
if (aClone) navLinkPart += " nav-link-active";
|
|
569
|
+
}
|
|
570
570
|
|
|
571
|
-
|
|
572
|
-
|
|
571
|
+
liClone.setAttribute("part", navItemPart);
|
|
572
|
+
if (aClone) aClone.setAttribute("part", navLinkPart);
|
|
573
573
|
|
|
574
|
-
|
|
574
|
+
return liClone;
|
|
575
575
|
}
|
|
576
576
|
|
|
577
577
|
/**
|
|
@@ -588,122 +588,122 @@ function cloneNavItem(item) {
|
|
|
588
588
|
* @this {SiteNavigation}
|
|
589
589
|
*/
|
|
590
590
|
function populateTabs() {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
591
|
+
const visibleList = this[visibleElementsSymbol];
|
|
592
|
+
const hiddenList = this[hiddenElementsSymbol];
|
|
593
|
+
const hamburgerButton = this[hamburgerButtonSymbol];
|
|
594
|
+
const navEl = this[navElementSymbol];
|
|
595
|
+
|
|
596
|
+
const topLevelUl = [...getSlottedElements.call(this, "ul")].find(
|
|
597
|
+
(ul) => ul.parentElement === this,
|
|
598
|
+
);
|
|
599
|
+
|
|
600
|
+
visibleList.innerHTML = "";
|
|
601
|
+
hiddenList.innerHTML = "";
|
|
602
|
+
hamburgerButton.style.display = "none";
|
|
603
|
+
this.style.visibility = "hidden";
|
|
604
|
+
|
|
605
|
+
if (!topLevelUl) {
|
|
606
|
+
this.style.visibility = "visible";
|
|
607
|
+
return; // Nichts zu tun
|
|
608
|
+
}
|
|
609
|
+
const sourceItems = Array.from(topLevelUl.children).filter(
|
|
610
|
+
(n) => n.tagName === "LI",
|
|
611
|
+
);
|
|
612
|
+
if (sourceItems.length === 0) {
|
|
613
|
+
this.style.visibility = "visible";
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const navWidth = navEl.clientWidth;
|
|
618
|
+
|
|
619
|
+
const originalDisplay = hamburgerButton.style.display;
|
|
620
|
+
hamburgerButton.style.visibility = "hidden";
|
|
621
|
+
hamburgerButton.style.display = "flex";
|
|
622
|
+
const hamburgerWidth =
|
|
623
|
+
Math.ceil(hamburgerButton.getBoundingClientRect().width) || 0;
|
|
624
|
+
hamburgerButton.style.display = originalDisplay;
|
|
625
|
+
hamburgerButton.style.visibility = "visible";
|
|
626
|
+
|
|
627
|
+
navEl.style.overflow = "hidden";
|
|
628
|
+
visibleList.style.flexWrap = "nowrap";
|
|
629
|
+
visibleList.style.visibility = "hidden"; // Inhalt der Liste während Manipulation ausblenden
|
|
630
|
+
|
|
631
|
+
const fit = [];
|
|
632
|
+
const rest = [];
|
|
633
|
+
let hasOverflow = false;
|
|
634
|
+
|
|
635
|
+
for (let i = 0; i < sourceItems.length; i++) {
|
|
636
|
+
const item = sourceItems[i];
|
|
637
|
+
|
|
638
|
+
if (hasOverflow) {
|
|
639
|
+
rest.push(item);
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const liClone = cloneNavItem(item);
|
|
644
|
+
visibleList.appendChild(liClone);
|
|
645
|
+
|
|
646
|
+
const requiredWidth = liClone.offsetLeft + liClone.offsetWidth;
|
|
647
|
+
const availableWidth = navWidth - hamburgerWidth;
|
|
648
|
+
const SAFETY_MARGIN = 1; // 1px Sicherheitsmarge für Subpixel-Rendering
|
|
649
|
+
|
|
650
|
+
if (requiredWidth > availableWidth + SAFETY_MARGIN) {
|
|
651
|
+
hasOverflow = true;
|
|
652
|
+
rest.push(item);
|
|
653
|
+
} else {
|
|
654
|
+
fit.push(item);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if (fit.length > 0 && rest.length > 0) {
|
|
659
|
+
const lastVisibleItem = visibleList.children[fit.length - 1];
|
|
660
|
+
const visibleItemsWidth =
|
|
661
|
+
lastVisibleItem.offsetLeft + lastVisibleItem.offsetWidth;
|
|
662
|
+
|
|
663
|
+
const firstHiddenItemClone = cloneNavItem(rest[0]);
|
|
664
|
+
const submenu = firstHiddenItemClone.querySelector(
|
|
665
|
+
"ul, div[part='mega-menu']",
|
|
666
|
+
);
|
|
667
|
+
if (submenu) submenu.style.display = "none";
|
|
668
|
+
|
|
669
|
+
visibleList.appendChild(firstHiddenItemClone);
|
|
670
|
+
const firstHiddenItemWidth =
|
|
671
|
+
firstHiddenItemClone.getBoundingClientRect().width;
|
|
672
|
+
visibleList.removeChild(firstHiddenItemClone);
|
|
673
|
+
|
|
674
|
+
const gap = parseFloat(getComputedStyle(visibleList).gap || "0") || 0;
|
|
675
|
+
if (visibleItemsWidth + gap + firstHiddenItemWidth <= navWidth) {
|
|
676
|
+
fit.push(rest.shift());
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
navEl.style.overflow = "";
|
|
681
|
+
visibleList.style.flexWrap = "";
|
|
682
|
+
visibleList.innerHTML = "";
|
|
683
|
+
|
|
684
|
+
if (fit.length) {
|
|
685
|
+
const clonedVisible = fit.map(cloneNavItem);
|
|
686
|
+
visibleList.append(...clonedVisible);
|
|
687
|
+
visibleList
|
|
688
|
+
.querySelectorAll(":scope > li")
|
|
689
|
+
.forEach((li) => setupSubmenu.call(this, li, "visible", 1));
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (rest.length) {
|
|
693
|
+
const clonedHidden = rest.map(cloneNavItem);
|
|
694
|
+
hiddenList.append(...clonedHidden);
|
|
695
|
+
hamburgerButton.style.display = "flex";
|
|
696
|
+
hiddenList
|
|
697
|
+
.querySelectorAll(":scope > li")
|
|
698
|
+
.forEach((li) => setupSubmenu.call(this, li, "hidden", 1));
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
visibleList.style.visibility = "visible";
|
|
702
|
+
this.style.visibility = "visible";
|
|
703
|
+
fireCustomEvent(this, "monster-layout-change", {
|
|
704
|
+
visibleItems: fit,
|
|
705
|
+
hiddenItems: rest,
|
|
706
|
+
});
|
|
707
707
|
}
|
|
708
708
|
|
|
709
709
|
/**
|
|
@@ -713,7 +713,7 @@ function populateTabs() {
|
|
|
713
713
|
* @returns {string} The combined string.
|
|
714
714
|
*/
|
|
715
715
|
function html(strings) {
|
|
716
|
-
|
|
716
|
+
return strings.join("");
|
|
717
717
|
}
|
|
718
718
|
|
|
719
719
|
/**
|
|
@@ -722,7 +722,7 @@ function html(strings) {
|
|
|
722
722
|
* @returns {string} The HTML template string.
|
|
723
723
|
*/
|
|
724
724
|
function getTemplate() {
|
|
725
|
-
|
|
725
|
+
return html`<div data-monster-role="control" part="control">
|
|
726
726
|
<nav data-monster-role="navigation" role="navigation" part="nav">
|
|
727
727
|
<ul id="visible-elements" part="visible-list"></ul>
|
|
728
728
|
</nav>
|