@madj2k/fe-frontend-kit 2.0.38 → 2.0.40

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.
@@ -0,0 +1,129 @@
1
+ /* ==================================================
2
+ * Slide Navigation
3
+ * ================================================== */
4
+
5
+ $slide-nav-zindex: 890;
6
+ $slide-nav-card-zindex: 666;
7
+ $slide-nav-card-zindex-active: 9999;
8
+
9
+ .slide-nav {
10
+ position: absolute;
11
+ left: 0;
12
+ top: -100vh;
13
+
14
+ width: 100vw;
15
+ height: 100vh;
16
+
17
+ overflow: hidden;
18
+ z-index: $slide-nav-zindex;
19
+ display: none;
20
+
21
+ /* prevent pointer events on inner spans */
22
+ a span,
23
+ button span {
24
+ pointer-events: none;
25
+ }
26
+
27
+ /* --------------------------------------------------
28
+ * Open state
29
+ * -------------------------------------------------- */
30
+ &.open {
31
+ display: block;
32
+ }
33
+
34
+ /* ==================================================
35
+ * Menu container
36
+ * (position animated via JS: top)
37
+ * ================================================== */
38
+ .slide-nav-container {
39
+ position: absolute;
40
+ top: -100%;
41
+ left: 0;
42
+
43
+ width: 100%;
44
+ height: 100vh;
45
+ }
46
+
47
+ /* ==================================================
48
+ * Cards
49
+ * (position animated via JS: left)
50
+ * ================================================== */
51
+ .slide-nav-card {
52
+ position: absolute;
53
+ top: 0;
54
+ left: 100%;
55
+
56
+ width: 100%;
57
+ height: 100%;
58
+
59
+ background-color: #fff;
60
+ z-index: $slide-nav-card-zindex;
61
+ transition: none;
62
+
63
+ /* active / visible card */
64
+ &.show {
65
+ left: 0;
66
+ z-index: $slide-nav-card-zindex-active;
67
+ }
68
+
69
+ /* animation lifecycle hooks */
70
+ &.opening,
71
+ &.closing {
72
+ box-shadow:
73
+ rgba(0, 0, 0, 0.25) 0px 14px 28px,
74
+ rgba(0, 0, 0, 0.22) 0px 20px 20px;
75
+ }
76
+ }
77
+
78
+ /* ==================================================
79
+ * Card inner layout
80
+ * ================================================== */
81
+
82
+ .slide-nav-inner {
83
+ display: flex;
84
+ flex-direction: column;
85
+
86
+ width: 100%;
87
+ height: 100%;
88
+
89
+ overflow-y: auto;
90
+ margin: 0;
91
+ }
92
+
93
+ /* ==================================================
94
+ * Lists & items
95
+ * ================================================== */
96
+ .slide-nav-list {
97
+ display: flex;
98
+ flex-direction: column;
99
+
100
+ list-style: none;
101
+ margin: 0;
102
+ padding: 0;
103
+
104
+ height: 100%;
105
+ }
106
+
107
+ .slide-nav-item {
108
+ width: 100%;
109
+ display: flex;
110
+ justify-content: space-between;
111
+ align-items: center;
112
+ }
113
+
114
+ .slide-nav-item-back {
115
+ margin-bottom: 1rem;
116
+ }
117
+
118
+ /* ==================================================
119
+ * Links & buttons
120
+ * ================================================== */
121
+ .slide-nav-link,
122
+ .slide-nav-back,
123
+ .slide-nav-next {
124
+ background: none;
125
+ border: none;
126
+ padding: 0;
127
+ margin: 0;
128
+ }
129
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madj2k/fe-frontend-kit",
3
- "version": "2.0.38",
3
+ "version": "2.0.40",
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
@@ -1,7 +1,7 @@
1
1
  # @madj2k/fe-frontend-kit
2
2
  Reusable frontend toolkit including SCSS mixins and menu components (JS/SCSS).
3
3
 
4
- # # Installation
4
+ ## Installation
5
5
  ```
6
6
  npm install @madj2k/fe-frontend-kit
7
7
  ```
@@ -71,7 +71,7 @@ CSS:
71
71
  id="nav-mobile"
72
72
  data-position-ref="siteheader">
73
73
  <div class="flyout-container js-flyout-container">
74
- <div class="nav-mobile-inner js-flyout-inner">
74
+ <div class="flyout-inner js-flyout-inner">
75
75
  CONTENT HERE
76
76
  </div>
77
77
  </div>
@@ -118,25 +118,27 @@ Otherwise in the opened menu the scrolling won't work.
118
118
 
119
119
  ### Height & Size Behavior
120
120
 
121
- | Option | Type | Default | Description |
122
- |--------|------|---------|-------------|
123
- | heightMode | 'full' \| 'maxContent' | 'full' | Determines height behavior of the flyout. |
124
- | animationDuration | number | 500 | Animation duration in milliseconds. |
121
+ | Option | Type | Default | Description |
122
+ |--------|------|---------|---------------------------------------------------------------------------|
123
+ | animationDuration | number | 500 | Animation duration in milliseconds. |
124
+ | heightMode | 'full' \| 'maxContent' | 'full' | Determines height behavior of the flyout. |
125
+ | heightModeClassPrefix | string | 'height-mode' | Prefix of class that is added to the DOM to indicate the used heightMode. |
125
126
 
126
127
  ### Padding & Layout Behavior
127
128
 
128
- | Option | Type | Default | Description |
129
- |--------|------|---------|-------------|
130
- | paddingBehavior | number | 0 | Controls dynamic horizontal padding. |
131
- | paddingViewPortMinWidth | number | 0 | Minimum viewport width required before padding applies. |
132
- | scrollHelper | boolean | true | Creates additional wrapper structure to enable scroll-locking. |
133
-
129
+ | Option | Type | Default | Description |
130
+ |-------------------------|----------------------|---------------|---------------------------------------------------------------------------|
131
+ | paddingBehavior | number | 0 | Controls dynamic horizontal padding. |
132
+ | paddingViewPortMinWidth | number | 0 | Minimum viewport width required before padding applies. |
133
+ | scrollHelper | boolean | true | Creates additional wrapper structure to enable scroll-locking. |
134
+ | scrollMode | 'default' \| 'inner' | 'default' | If set to 'inner' the inner-DIV of the flyout is scrollable. |
135
+ | scrollModeClassPrefix | string | 'scroll-mode' | Prefix of class that is added to the DOM to indicate the used ccrollMode. |
134
136
 
135
137
  ### Event Handling
136
138
 
137
- | Option | Type | Default | Description |
138
- |--------|------|-------------|
139
- | `eventMode` | `string` | `'click'` | Default event used for toggling the menu. Can be set to `click` or `mouseover`. |
139
+ | Option | Type | Default | Description |
140
+ |-----------------------|------|---------|-------------|
141
+ | eventMode | string | 'click'`| Default event used for toggling the menu. Can be set to `click` or `mouseover`. |
140
142
 
141
143
 
142
144
  ## Special: blur/gray effect for background
@@ -280,6 +282,301 @@ These are automatically detected:
280
282
  | **toggleElement** | The trigger element passed to the constructor. |
281
283
 
282
284
 
285
+ # Slide-Navigation
286
+
287
+ A card-based, multi-level slide menu for mobile and off-canvas navigation.
288
+ The menu is generated dynamically from a JSON structure and HTML templates.
289
+
290
+ Features:
291
+ - Unlimited menu depth
292
+ - Card-based sliding navigation
293
+ - Keyboard navigation & full accessibility (WAI-ARIA)
294
+ - Focus trapping and scroll locking
295
+ - No jQuery required (Vanilla JS)
296
+ - CMS-friendly (TYPO3 / dynamic content)
297
+
298
+ ## Usage
299
+ Integrate the CSS- and JS-file into your project.
300
+ Then initialize the menu on a toggle element:
301
+
302
+ ```js
303
+ import { Madj2kSlideMenu } from '@madj2k/fe-frontend-kit/menus/slide-menu';
304
+
305
+ document.querySelectorAll('.js-slide-nav-toggle').forEach((el) => {
306
+ new Madj2kSlideMenu(el, {
307
+ menuItemsJson: slideNavItems
308
+ });
309
+ });
310
+ ```
311
+
312
+ Optional: automatically close the slide menu on resize:
313
+
314
+ ```js
315
+ import { Madj2kBetterResizeEvent } from '@madj2k/fe-frontend-kit/tools/better-resize-event';
316
+
317
+ document.addEventListener('madj2k-better-resize-event', () => {
318
+ document.dispatchEvent(new CustomEvent('madj2k-slidemenu-close'));
319
+ });
320
+ ```
321
+
322
+ CSS:
323
+ ```scss
324
+ @use '@madj2k/fe-frontend-kit/menus/slide-menu' as *;
325
+ ```
326
+
327
+ ## Basic HTML
328
+
329
+ ### Toggle element
330
+ The toggle element opens and closes the slide menu.
331
+ It MUST define an aria-controls attribute pointing to the menu container.
332
+
333
+ ```html
334
+ <button class="nav-iconlink js-slide-nav-toggle"
335
+ aria-label="Open Menu"
336
+ aria-haspopup="true"
337
+ aria-expanded="false"
338
+ aria-controls="slide-nav">
339
+ <span>Open Menu</span>
340
+ </button>
341
+ ```
342
+
343
+ ### Menu container
344
+ The menu container is initially empty and will be filled dynamically.
345
+
346
+ ```html
347
+ <nav class="slide-nav"
348
+ id="slide-nav"
349
+ data-position-ref="navbar-wrap"></nav>
350
+ ```
351
+ **Note:**
352
+ If data-position-ref is set, the menu will be positioned below that element (referenced by id).
353
+ Otherwise, it is positioned relative to the toggle.
354
+
355
+ ### Content wrapper
356
+ To prevent background scrolling while the menu is open, the main content
357
+ should be wrapped in an element with the configured contentSectionClass
358
+ (default: js-main-content).
359
+
360
+ ```html
361
+ <div class="page-main js-main-content">
362
+ ...
363
+ </div>
364
+ ```
365
+
366
+
367
+ ## HTML Templates
368
+ The slide menu is rendered from <template> elements that must exist in the DOM.
369
+ These templates are not rendered by default and therefore do not duplicate
370
+ navigation markup for search engines.
371
+
372
+ **Note: There are example files for a TYPO3 CMS extension available.**
373
+
374
+ ### menuWrap
375
+ ```html
376
+ <template class="js-slide-nav-tmpl" data-type="menuWrap">
377
+ <div class="slide-nav-container js-slide-nav-container">
378
+ <div class="slide-nav-card js-slide-nav-card %levelClass%" id="slide-card-%uid%">
379
+ <div class="slide-nav-inner">
380
+ <ul class="slide-nav-list">
381
+ %menuItems%
382
+ </ul>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ </template>
387
+ ```
388
+
389
+ ### menuItem
390
+ ```html
391
+ <template class="js-slide-nav-tmpl" data-type="menuItem">
392
+ <li class="slide-nav-item %activeClass% %hasChildrenClass%">
393
+
394
+ <!-- normal link that opens the menu-item -->
395
+ %ifHasNoChildrenStart%
396
+ <a href="%link%"
397
+ title="%titleRaw%"
398
+ role="menuitem"
399
+ class="slide-nav-link arrow-listing-link %activeClass% %hasChildrenClass%"
400
+ target="%target%"
401
+ aria-current="%ariaCurrent%">
402
+ <span>%title%</span>
403
+ </a>
404
+ %ifHasNoChildrenEnd%
405
+
406
+ <!-- link that opens next card -->
407
+ %ifHasChildrenStart%
408
+ <a class="slide-nav-link slide-nav-next arrow-listing-link js-slide-nav-next animation-hover %activeClass% %hasChildrenClass%"
409
+ href="#"
410
+ role="button"
411
+ title="Open Submenu"
412
+ aria-label="Open Submenu"
413
+ aria-haspopup="true"
414
+ aria-expanded="%ariaExpanded%"
415
+ aria-controls="slide-card-%uid%">
416
+ <span>%title%</span><span class="icon-arrow-right icon"></span>
417
+ </a>
418
+ %ifHasChildrenEnd%
419
+ %submenu%
420
+ </li>
421
+ </template>
422
+ ```
423
+
424
+ ### subMenuWrap
425
+
426
+ ```html
427
+ <template class="js-slide-nav-tmpl" data-type="subMenuWrap">
428
+ <a class="slide-nav-next js-slide-nav-next"
429
+ href="#"
430
+ role="button"
431
+ title="Open Submenu"
432
+ aria-label="Open Submenu"
433
+ aria-haspopup="true"
434
+ aria-expanded="%ariaExpanded%"
435
+ aria-controls="slide-card-%uid%">&gt;</a>
436
+
437
+ <div class="slide-nav-card js-slide-nav-card %activeClass% %levelClass%"
438
+ id="slide-card-%uid%">
439
+ <div class="slide-nav-inner">
440
+ <ul class="slide-nav-list">
441
+ <li class="slide-nav-item-back" role="none">>
442
+ <button class="slide-nav-back js-slide-nav-back"
443
+ aria-label="One Level Up"
444
+ aria-controls="slide-card-%uid%"
445
+ data-parent-card="slide-card-%parentUid%">
446
+ &lt;<span class="slide-nav-back-label">Back</span>
447
+ </button>
448
+ </li>
449
+
450
+ <li class="slide-nav-headline %levelClass%" role="none">
451
+
452
+ <!-- normal parent -->
453
+ %ifIsNotLinkedStart%
454
+ <span class="slide-nav-headline-text %currentClass% %isLinkedClass%">%title%</span>
455
+ %ifIsNotLinkedEnd%
456
+
457
+ <!-- linked parent -->
458
+ %ifIsLinkedStart%
459
+ <a href="%link%"
460
+ title="%titleRaw%"
461
+ role="menuitem"
462
+ class="slide-nav-headline-link %currentClass% %hasChildrenClass% %isLinkedClass%"
463
+ target="%target%"
464
+ aria-current="%ariaCurrent%">
465
+ <span>%title%</span>
466
+ </a>
467
+ %ifIsLinkedEnd%
468
+ </li>
469
+
470
+ %menuItems%
471
+ </ul>
472
+ </div>
473
+ </div>
474
+ </template>
475
+ ```
476
+ ## Menu Data (menuItemsJson)
477
+
478
+ The menu structure is defined as a hierarchical JSON array.
479
+
480
+ ### Example
481
+ ```js
482
+ const slideNavItems = [
483
+ {
484
+ data: { uid: 2, pid: 1 },
485
+ title: 'Main Item',
486
+ link: '/main',
487
+ target: '_self',
488
+ active: 1,
489
+ current: 0,
490
+ hasSubpages: 1,
491
+ children: [
492
+ {
493
+ data: { uid: 3, pid: 2 },
494
+ title: 'Sub Item',
495
+ link: '/main/sub',
496
+ target: '_self',
497
+ active: 0,
498
+ current: 0,
499
+ hasSubpages: 0,
500
+ children: []
501
+ }
502
+ ]
503
+ },
504
+ {
505
+ data: { uid: 4, pid: 1 },
506
+ title: 'Second Item',
507
+ link: '/second',
508
+ target: '_self',
509
+ active: 0,
510
+ current: 0,
511
+ hasSubpages: 0,
512
+ children: []
513
+ }
514
+ ];
515
+ ```
516
+
517
+ ### Important fields
518
+
519
+ | Property | Description |
520
+ |--------|-------------|
521
+ | data.uid | Unique identifier of the menu item |
522
+ | data.pid | Parent identifier |
523
+ | title | Display title |
524
+ | link | URL |
525
+ | target | Link target |
526
+ | active | Marks active navigation path |
527
+ | current | Marks current page |
528
+ | hasSubpages | Indicates submenu existence |
529
+ | children | Array of child items |
530
+
531
+ ---
532
+
533
+ ## Options Reference
534
+
535
+ ### State & Animation Classes
536
+
537
+ | Option | Type | Default | Description |
538
+ |------|------|---------|-------------|
539
+ | openStatusClass | string | 'open' | Applied to toggle and menu when open |
540
+ | openCardStatusClass | string | 'show' | Marks the visible card |
541
+ | activeStatusClass | string | 'active' | Marks active navigation path |
542
+ | currentStatusClass | string | 'current' | Marks current page |
543
+ | animationOpenStatusClass | string | 'opening' | Applied during opening animation |
544
+ | animationCloseStatusClass | string | 'closing' | Applied during closing animation |
545
+
546
+ ### Structural Classes
547
+
548
+ | Option | Type | Default | Description |
549
+ |------|------|---------|-------------|
550
+ | menuToggleClass | string | 'js-slide-nav-toggle' | Toggle element |
551
+ | menuWrapClass | string | 'js-slide-nav-container' | Menu container |
552
+ | menuCardClass | string | 'js-slide-nav-card' | Card element |
553
+ | nextCardToggleClass | string | 'js-slide-nav-next' | Submenu toggle |
554
+ | lastCardToggleClass | string | 'js-slide-nav-back' | Back button |
555
+ | contentSectionClass | string | 'js-main-content' | Scroll-lock wrapper |
556
+
557
+ ### Behavior
558
+
559
+ | Option | Type | Default | Description |
560
+ |------|------|---------|-------------|
561
+ | animationDuration | number | 500 | Animation duration in ms |
562
+ | loadOnOpen | boolean | true | Build menu on first open |
563
+ | startOnHome | boolean | false | Always start on first level |
564
+ | scrollHelper | boolean | true | Creates additional wrapper structure to enable scroll-locking. |
565
+
566
+ ---
567
+
568
+ ## Events
569
+
570
+ The component dispatches the following custom events on `document`:
571
+
572
+ - madj2k-slidemenu-opening
573
+ - madj2k-slidemenu-opened
574
+ - madj2k-slidemenu-closing
575
+ - madj2k-slidemenu-closed
576
+ - madj2k-slidemenu-next-opened
577
+ - madj2k-slidemenu-previous-opened
578
+
579
+
283
580
  # JS: Banner
284
581
  A lightweight class to show a full-page overlay (banner, popup, hint or cookie layer),
285
582
  with opening and closing animation and optional cookie persistence.
@@ -10,15 +10,16 @@
10
10
  /// @param {Map} $map - A Sass map of color names and values (e.g. `("primary": #005fcc, "secondary": #999)`). Defaults to `$color-map`.
11
11
  ///
12
12
  /// @example scss
13
- /// @include background-color-classes((
14
- /// "primary": #005fcc,
15
- /// "secondary": #999,
16
- /// "light": #f5f5f5
17
- /// ));
13
+ /// .bg-color {
14
+ /// @include background-color-classes((
15
+ /// "primary": #005fcc,
16
+ /// "secondary": #999,
17
+ /// ));
18
+ /// }
18
19
  ///
19
20
  /// @example css
20
- /// .bg-primary { background-color: #005fcc; }
21
- /// .bg-secondary { background-color: #999; }
21
+ /// .bg-color-primary { background-color: #005fcc; }
22
+ /// .bg-color-secondary { background-color: #999; }
22
23
  ///
23
24
  /// @author Steffen Kroggel <developer@steffenkroggel>
24
25
  /// @license GNU General Public License v3.0 https://www.gnu.org/licenses/gpl-3.0.en.html
@@ -43,6 +44,46 @@
43
44
  }
44
45
  }
45
46
 
47
+ /// Generates utility classes
48
+ /// that set the CSS variable `--background-color` from a color map.
49
+ ///
50
+ /// @group Utilities
51
+ ///
52
+ /// @param {Map} $map - Sass map of color names and values.
53
+ ///
54
+ /// @example scss
55
+ /// .bg-color {
56
+ /// @include background-color-variable-classes(
57
+ /// "primary": #005fcc,
58
+ /// "secondary": #999,
59
+ /// ));
60
+ /// }
61
+ ///
62
+ /// @example css
63
+ /// .bg-color-primary { --background-color: #005fcc; }
64
+ /// .bg-color-secondary { --background-color: #999; }
65
+ ///
66
+ ///
67
+ @mixin background-color-variable-classes($map) {
68
+ @each $key, $value in $map {
69
+ &-#{$key} {
70
+ --background-color: #{$value};
71
+ }
72
+
73
+ @each $breakpoint, $size in $grid-breakpoints {
74
+ @media (min-width: $size) {
75
+ &-#{$breakpoint}-#{$key} {
76
+ --background-color: #{$value};
77
+ }
78
+
79
+ &-#{$breakpoint}-none {
80
+ --background-color: transparent;
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+
46
87
  /// Generates utility classes for text color based on a Sass map.
47
88
  ///
48
89
  /// For each key–value pair in the provided map, a class with a suffix of `-<key>`
@@ -55,14 +96,16 @@
55
96
  /// @param {Map} $map - A Sass map of color names and values. Defaults to `$color-map`.
56
97
  ///
57
98
  /// @example scss
58
- /// @include font-color-classes((
59
- /// "danger": #e00,
60
- /// "success": #0a0
61
- /// ));
99
+ /// .font-color {
100
+ /// @include font-color-classes((
101
+ /// "primary": #005fcc,
102
+ /// "secondary": #999,
103
+ /// ));
104
+ /// }
62
105
  ///
63
106
  /// @example css
64
- /// .text-danger { color: #e00 !important; }
65
- /// .text-danger > * { color: #e00 !important; }
107
+ /// .font-color-primary { color: #005fcc !important; }
108
+ /// .font-color-secondary > * { color: #999 !important;}
66
109
  ///
67
110
  /// @author Steffen Kroggel <developer@steffenkroggel>
68
111
  /// @license GNU General Public License v3.0 https://www.gnu.org/licenses/gpl-3.0.en.html
@@ -97,3 +140,54 @@
97
140
  }
98
141
  }
99
142
  }
143
+
144
+ /// Generates utility classes
145
+ /// that set the CSS variable `--font-color` from a color map.
146
+ ///
147
+ /// @group Utilities
148
+ ///
149
+ /// @param {Map} $map - Sass map of color names and values.
150
+ ///
151
+ /// @example scss
152
+ /// .font-color {
153
+ /// @include font-color-variable-classes((
154
+ /// "primary": #005fcc,
155
+ /// "secondary": #999,
156
+ /// ));
157
+ /// }
158
+ ///
159
+ /// @example css
160
+ /// .font-color-primary { --color: #005fcc }
161
+ /// .font-color-secondary > * { --color: #999 }
162
+ ///
163
+ ///
164
+ @mixin font-color-variable-classes($map) {
165
+ @each $key, $value in $map {
166
+ &-#{$key} {
167
+ --color: #{$value};
168
+
169
+ & > * {
170
+ --color: #{$value};
171
+ }
172
+ }
173
+ @each $breakpoint, $size in $grid-breakpoints {
174
+ @media (min-width: $size) {
175
+ &-#{$breakpoint}-#{$key} {
176
+ --color: #{$value};
177
+
178
+ & > * {
179
+ --color: #{$value};
180
+ }
181
+ }
182
+
183
+ &-#{$breakpoint}-none {
184
+ --color: inherit;
185
+
186
+ & > * {
187
+ --color: inherit;
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+ }
@@ -45,10 +45,6 @@
45
45
  align-items: center;
46
46
  text-decoration: none;
47
47
 
48
- &:hover {
49
- text-decoration: none;
50
- }
51
-
52
48
  span.icon:first-child:not(span.icon:last-child) {
53
49
  margin-right: rem-calc($margin);
54
50
  }