@madj2k/fe-frontend-kit 2.0.23 → 2.0.25
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.
|
@@ -49,6 +49,7 @@ class Madj2kFlyoutMenu {
|
|
|
49
49
|
menuCloseClass: "js-flyout-close",
|
|
50
50
|
menuContainerClass: "js-flyout-container",
|
|
51
51
|
menuInnerClass: "js-flyout-inner",
|
|
52
|
+
heightCalculationClass: 'calculate',
|
|
52
53
|
heightMode: 'full',
|
|
53
54
|
paddingBehavior: 0,
|
|
54
55
|
paddingViewPortMinWidth: 0,
|
|
@@ -230,10 +231,13 @@ class Madj2kFlyoutMenu {
|
|
|
230
231
|
* Opens the flyout menu
|
|
231
232
|
*/
|
|
232
233
|
open() {
|
|
233
|
-
const {$menu, $element, animationOpenStatusClass, openStatusClass} = this.settings;
|
|
234
|
+
const {$menu, $element, animationOpenStatusClass, openStatusClass, openStatusBodyClass, animationBodyClassPrefix} = this.settings;
|
|
235
|
+
const $body = document.body;
|
|
236
|
+
|
|
234
237
|
if (!$menu.classList.contains(openStatusClass) && !$menu.classList.contains(animationOpenStatusClass)) {
|
|
235
238
|
document.dispatchEvent(new CustomEvent('madj2k-slidemenu-close'));
|
|
236
239
|
document.dispatchEvent(new CustomEvent('madj2k-pulldownmenu-close'));
|
|
240
|
+
document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-close'));
|
|
237
241
|
document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-opening'));
|
|
238
242
|
|
|
239
243
|
this.toggleNoScroll();
|
|
@@ -243,7 +247,8 @@ class Madj2kFlyoutMenu {
|
|
|
243
247
|
$menu.classList.add(openStatusClass, animationOpenStatusClass);
|
|
244
248
|
$element.classList.add(openStatusClass, animationOpenStatusClass);
|
|
245
249
|
$element.setAttribute('aria-expanded', true);
|
|
246
|
-
|
|
250
|
+
$body.classList.add(openStatusBodyClass);
|
|
251
|
+
$body.classList.add(`${animationBodyClassPrefix}-${animationOpenStatusClass}`);
|
|
247
252
|
|
|
248
253
|
this.settings.$menuContainer.style.transition = `top ${this.settings.animationDuration}ms`;
|
|
249
254
|
this.settings.$menuContainer.style.top = '0';
|
|
@@ -251,7 +256,7 @@ class Madj2kFlyoutMenu {
|
|
|
251
256
|
setTimeout(() => {
|
|
252
257
|
$menu.classList.remove(animationOpenStatusClass);
|
|
253
258
|
$element.classList.remove(animationOpenStatusClass);
|
|
254
|
-
|
|
259
|
+
$body.classList.remove(`${animationBodyClassPrefix}-${animationOpenStatusClass}`);
|
|
255
260
|
document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-opened'));
|
|
256
261
|
}, this.settings.animationDuration);
|
|
257
262
|
}
|
|
@@ -283,17 +288,20 @@ class Madj2kFlyoutMenu {
|
|
|
283
288
|
* Closes the flyout menu
|
|
284
289
|
*/
|
|
285
290
|
close() {
|
|
286
|
-
const {$menu, $element, animationCloseStatusClass, openStatusClass} = this.settings;
|
|
291
|
+
const {$menu, $element, animationCloseStatusClass, openStatusClass, openStatusBodyClass, animationBodyClassPrefix} = this.settings;
|
|
292
|
+
const $body = document.body;
|
|
293
|
+
|
|
287
294
|
if ($menu.classList.contains(openStatusClass) && !$menu.classList.contains(animationCloseStatusClass)) {
|
|
288
295
|
document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-closing'));
|
|
289
296
|
|
|
297
|
+
this.toggleNoScroll();
|
|
298
|
+
|
|
290
299
|
$menu.classList.add(animationCloseStatusClass);
|
|
291
300
|
$element.classList.add(animationCloseStatusClass);
|
|
292
|
-
document.body.classList.add(`${this.settings.animationBodyClassPrefix}-${animationCloseStatusClass}`);
|
|
293
301
|
$element.classList.remove(openStatusClass);
|
|
294
302
|
$element.setAttribute('aria-expanded', false);
|
|
295
|
-
|
|
296
|
-
|
|
303
|
+
$body.classList.add(`${animationBodyClassPrefix}-${animationCloseStatusClass}`);
|
|
304
|
+
$body.classList.remove(openStatusBodyClass);
|
|
297
305
|
|
|
298
306
|
this.settings.$menuContainer.style.transition = `top ${this.settings.animationDuration}ms`;
|
|
299
307
|
this.settings.$menuContainer.style.top = '-100%';
|
|
@@ -301,7 +309,7 @@ class Madj2kFlyoutMenu {
|
|
|
301
309
|
setTimeout(() => {
|
|
302
310
|
$menu.classList.remove(openStatusClass, animationCloseStatusClass);
|
|
303
311
|
$element.classList.remove(animationCloseStatusClass);
|
|
304
|
-
|
|
312
|
+
$body.classList.remove(`${animationBodyClassPrefix}-${animationCloseStatusClass}`);
|
|
305
313
|
document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-closed'));
|
|
306
314
|
}, this.settings.animationDuration);
|
|
307
315
|
}
|
|
@@ -333,29 +341,41 @@ class Madj2kFlyoutMenu {
|
|
|
333
341
|
console.warn('Option "fullHeight" is deprecated. Please use "heightMode" instead.');
|
|
334
342
|
}
|
|
335
343
|
|
|
336
|
-
|
|
344
|
+
// remove max-height for correct calculation
|
|
345
|
+
this.settings.$menu.classList.add(this.settings.heightCalculationClass);
|
|
346
|
+
|
|
347
|
+
const innerHeight = this.settings.$menuInner.offsetHeight || this.settings.$menu.offsetHeight;
|
|
337
348
|
const refObj = this.settings.$positionReference || this.$element;
|
|
338
349
|
const refPos = refObj.getBoundingClientRect();
|
|
339
|
-
const
|
|
350
|
+
const refHeight = refObj.offsetHeight;
|
|
351
|
+
const flyoutTop = refPos.top + refHeight;
|
|
352
|
+
let newHeight = '';
|
|
340
353
|
|
|
341
354
|
// heightMode "full" with deprecated fullHeight-setting as fallback
|
|
342
355
|
if (this.settings.heightMode === 'full' || this.settings.fullHeight === true) {
|
|
356
|
+
|
|
357
|
+
// we use the viewport height because it may be the case that accordions are used here
|
|
343
358
|
const viewPortHeight = window.innerHeight;
|
|
344
|
-
if (
|
|
345
|
-
|
|
359
|
+
if (innerHeight < (viewPortHeight - flyoutTop)) {
|
|
360
|
+
newHeight = `calc(100vh - ${flyoutTop}px)`;
|
|
346
361
|
} else {
|
|
347
|
-
|
|
362
|
+
newHeight = `${innerHeight}px`;
|
|
348
363
|
}
|
|
349
364
|
|
|
350
365
|
} else if (this.settings.heightMode === 'maxContent') {
|
|
351
|
-
|
|
366
|
+
newHeight = `max-content`;
|
|
352
367
|
console.warn('heightMode: maxContent is not working on Apple Safari. Please use heightMode: full instead.');
|
|
353
368
|
|
|
354
369
|
} else {
|
|
355
|
-
|
|
370
|
+
newHeight = `${innerHeight}px`;
|
|
356
371
|
}
|
|
372
|
+
|
|
373
|
+
// set max-height again so that longer flyouts do not lead to scrolling on smaller ones
|
|
374
|
+
this.settings.$menu.classList.remove(this.settings.heightCalculationClass);
|
|
375
|
+
this.settings.$menu.style.height = newHeight;
|
|
357
376
|
}
|
|
358
377
|
|
|
378
|
+
|
|
359
379
|
/**
|
|
360
380
|
* Positions the menu based on the reference element
|
|
361
381
|
*/
|
|
@@ -405,28 +425,33 @@ class Madj2kFlyoutMenu {
|
|
|
405
425
|
* Toggles scroll behavior of the page
|
|
406
426
|
*/
|
|
407
427
|
toggleNoScroll() {
|
|
408
|
-
const body = document.body;
|
|
409
|
-
const helper = body.querySelector('.no-scroll-helper');
|
|
410
|
-
const inner = body.querySelector('.no-scroll-helper-inner');
|
|
411
|
-
let noScrollClass = this.settings.openStatusBodyClass;
|
|
412
428
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
429
|
+
// heightMode "full" with deprecated fullHeight-setting as fallback
|
|
430
|
+
if (this.settings.heightMode === 'full' || this.settings.fullHeight === true) {
|
|
431
|
+
const body = document.body;
|
|
432
|
+
const helper = body.querySelector('.no-scroll-helper');
|
|
433
|
+
const inner = body.querySelector('.no-scroll-helper-inner');
|
|
434
|
+
let noScrollClass ='';
|
|
435
|
+
|
|
436
|
+
if (document.documentElement.scrollHeight > window.innerHeight) {
|
|
437
|
+
noScrollClass = this.settings.openStatusBodyClassOverflow;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (!body.classList.contains(this.settings.openStatusBodyClass)) {
|
|
441
|
+
const scrollTop = -document.documentElement.scrollTop;
|
|
442
|
+
helper.setAttribute('data-scroll-top', scrollTop);
|
|
443
|
+
helper.style.cssText = 'position:relative;overflow:hidden;height:100vh;width:100%';
|
|
444
|
+
inner.style.cssText = `position:absolute;top:${scrollTop}px;height:100%;width:100%`;
|
|
445
|
+
body.classList.add(noScrollClass);
|
|
446
|
+
window.scrollTo({top: 0, behavior: 'instant'});
|
|
447
|
+
} else {
|
|
448
|
+
const scrollTop = parseInt(helper.getAttribute('data-scroll-top') || '0') * -1;
|
|
449
|
+
helper.removeAttribute('style');
|
|
450
|
+
inner.removeAttribute('style');
|
|
451
|
+
body.classList.remove(this.settings.openStatusBodyClassOverflow);
|
|
452
|
+
window.scrollTo({top: scrollTop, behavior: 'instant'});
|
|
453
|
+
}
|
|
416
454
|
|
|
417
|
-
if (!body.classList.contains(this.settings.openStatusBodyClass)) {
|
|
418
|
-
const scrollTop = -document.documentElement.scrollTop;
|
|
419
|
-
helper.setAttribute('data-scroll-top', scrollTop);
|
|
420
|
-
helper.style.cssText = 'position:relative;overflow:hidden;height:100vh;width:100%';
|
|
421
|
-
inner.style.cssText = `position:absolute;top:${scrollTop}px;height:100%;width:100%`;
|
|
422
|
-
body.classList.add(...noScrollClass.split(' '));
|
|
423
|
-
window.scrollTo({top: 0, behavior: 'instant'});
|
|
424
|
-
} else {
|
|
425
|
-
const scrollTop = parseInt(helper.getAttribute('data-scroll-top') || '0') * -1;
|
|
426
|
-
helper.removeAttribute('style');
|
|
427
|
-
inner.removeAttribute('style');
|
|
428
|
-
body.classList.remove(this.settings.openStatusBodyClass, this.settings.openStatusBodyClassOverflow);
|
|
429
|
-
window.scrollTo({top: scrollTop, behavior: 'instant'});
|
|
430
455
|
}
|
|
431
456
|
}
|
|
432
457
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
html, body {
|
|
2
|
+
height: 100.1%; // enforce scrollbar
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
.flyout {
|
|
2
6
|
position: absolute;
|
|
3
7
|
left: 0;
|
|
@@ -5,12 +9,18 @@
|
|
|
5
9
|
|
|
6
10
|
width: 100%;
|
|
7
11
|
z-index: -1;
|
|
8
|
-
overflow:hidden;
|
|
12
|
+
overflow: hidden;
|
|
9
13
|
visibility: hidden;
|
|
14
|
+
max-height: 0;
|
|
15
|
+
|
|
16
|
+
&.calculate {
|
|
17
|
+
max-height: none;
|
|
18
|
+
}
|
|
10
19
|
|
|
11
20
|
&.open {
|
|
12
21
|
z-index: 890;
|
|
13
22
|
visibility: visible;
|
|
23
|
+
max-height: none;
|
|
14
24
|
|
|
15
25
|
.flyout-container {
|
|
16
26
|
pointer-events: auto;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -293,13 +293,6 @@ document.querySelector('.js-background-blur').addEventListener('click', function
|
|
|
293
293
|
```
|
|
294
294
|
* And we need this additional CSS:
|
|
295
295
|
```
|
|
296
|
-
/**
|
|
297
|
-
* Prevent jumping because of scrollbar
|
|
298
|
-
*/
|
|
299
|
-
html,body {
|
|
300
|
-
min-height: 100.1%;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
296
|
/**
|
|
304
297
|
* background-blur for opened flyout
|
|
305
298
|
*/
|
|
@@ -268,11 +268,24 @@
|
|
|
268
268
|
/// @param {Color} $icon-color - Icon color (e.g., fill or text color). Defaults to `$color-primary`.
|
|
269
269
|
/// @param {Map} $icon-mappings - Map of icon toggle states (e.g., hamburger → close). Defaults to a predefined map.
|
|
270
270
|
///
|
|
271
|
-
/// @example html
|
|
271
|
+
/// @example html with icon font
|
|
272
|
+
/// <button class="nav-toggle" aria-expanded="false">
|
|
273
|
+
/// <i class="nav-toggle-icon icon-hamburger icon"></i>
|
|
274
|
+
/// </button>
|
|
275
|
+
///
|
|
276
|
+
/// @example html with icon sprite
|
|
272
277
|
/// <button class="nav-toggle" aria-expanded="false">
|
|
273
|
-
/// <i class="nav-toggle-icon
|
|
278
|
+
/// <i class="nav-toggle-icon">
|
|
279
|
+
/// <svg class="nav-toggle-icon-opened" aria-hidden="true" focusable="false">
|
|
280
|
+
/// <use href="sprite.svg#search"></use>
|
|
281
|
+
/// </svg>
|
|
282
|
+
/// <svg class="nav-toggle-icon-closed" aria-hidden="true" focusable="false">
|
|
283
|
+
/// <use href="sprite.svg#close"></use>
|
|
284
|
+
/// </svg>
|
|
285
|
+
/// </i>
|
|
274
286
|
/// </button>
|
|
275
287
|
///
|
|
288
|
+
///
|
|
276
289
|
/// @example scss
|
|
277
290
|
/// .nav-toggle {
|
|
278
291
|
/// @include nav-toggle(
|
|
@@ -305,6 +318,7 @@
|
|
|
305
318
|
display: flex;
|
|
306
319
|
align-items: center;
|
|
307
320
|
|
|
321
|
+
// variant with icons as font
|
|
308
322
|
&[aria-expanded="true"] {
|
|
309
323
|
@each $icon-class, $content in $icon-mappings {
|
|
310
324
|
.#{$icon-class} {
|
|
@@ -314,11 +328,30 @@
|
|
|
314
328
|
}
|
|
315
329
|
}
|
|
316
330
|
}
|
|
331
|
+
|
|
332
|
+
// variant with icons in a sprite
|
|
333
|
+
.nav-toggle-icon-opened {
|
|
334
|
+
display: none;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
&[aria-expanded="true"] {
|
|
338
|
+
.nav-toggle-icon-opened {
|
|
339
|
+
display: inline-block;
|
|
340
|
+
}
|
|
341
|
+
.nav-toggle-icon-closed {
|
|
342
|
+
display: none;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
317
345
|
}
|
|
318
346
|
|
|
319
|
-
&-icon
|
|
347
|
+
&-icon:not(:has(svg)),
|
|
348
|
+
&-icon svg {
|
|
320
349
|
font-size: rem-calc($icon-size);
|
|
321
350
|
width: rem-calc($icon-size);
|
|
322
351
|
color: $icon-color;
|
|
323
352
|
}
|
|
353
|
+
|
|
354
|
+
&-icon svg {
|
|
355
|
+
height: 100%;
|
|
356
|
+
}
|
|
324
357
|
}
|