@ecl/mega-menu 5.0.0-alpha.1 → 5.0.0-alpha.10

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/README.md CHANGED
@@ -10,7 +10,6 @@ npm install --save @ecl/mega-menu
10
10
 
11
11
  - **"id"** (string) (default: random): Unique id
12
12
  - **"toggle"**: (associative array) (default: {}): Toggle (hamburger) button, using ECL button structure
13
- - **"title"** (string) (default: ''): Used as the inner container aria-label value
14
13
  - **"close"**: (associative array) (default: {}): Object, using ECL Button structure
15
14
  - **"aria_label"** (string): (default: ''): Main list aria label
16
15
  - **"second_level_aria_label"** (string): (default: ''): Second level list aria label
@@ -31,8 +30,8 @@ npm install --save @ecl/mega-menu
31
30
  "featured" (object) (optional) {
32
31
  "title": (string)
33
32
  "content": (string)
34
- "items": (associative array)
35
- }
33
+ "items": (associative array) Array of items with image and link
34
+ },
36
35
  "children": (associative array) (optional): [
37
36
  {
38
37
  "label": (string) (default: '')
@@ -56,7 +55,6 @@ npm install --save @ecl/mega-menu
56
55
  <!-- prettier-ignore -->
57
56
  ```twig
58
57
  {% include '@ecl/mega-menu/mega-menu.html.twig' with {
59
- title: 'Menu',
60
58
  toggle: {
61
59
  link: {
62
60
  label: 'Menu',
@@ -0,0 +1,102 @@
1
+ {% apply spaceless %}
2
+
3
+ {#
4
+ Parameters:
5
+ - "label" (string) Label of the textual link
6
+ - "path" (string) Path or Url for the href of the link
7
+ - "icon_path": Path to the icons sprite
8
+ - "picture" (associative array) ECL picture
9
+ - "img" (associative array) (default: {}):
10
+ - "src" (string) (default: ''): Path to the image
11
+ - "alt" (string) (default: ''): Alt text, required in case of a link with only an image
12
+ - "sources" (array) (default: []): format: [
13
+ {
14
+ "src" (string) (default: ''): Path to the source image
15
+ "media" (string) (default: ''): Media condition to use this source. Could be a breakpoint ('s', 'm', 'l', 'xl') or a free string.
16
+ "type" (string) (default: ''): Type of this source
17
+ },
18
+ ...
19
+ ]
20
+ - "extra_classes" (optional) (string) (default: '') Extra classes (space separated) for the nav element
21
+ - "extra_attributes" (optional) (array) (default: []) Extra attributes for the nav element
22
+ - "name" (string) Attribute name, eg. 'data-test'
23
+ - "value" (optional) (string) Attribute value, eg: 'data-test-1'
24
+ #}
25
+
26
+ {# Internal properties #}
27
+
28
+ {% set _item_css_class = 'ecl-mega-menu__featured-list__item' %}
29
+ {% set _css_class = 'ecl-mega-menu__featured-link' %}
30
+ {% set _label = label|default('') %}
31
+ {% set _path = path|default('') %}
32
+ {% set _picture = picture|default({}) %}
33
+ {% set _icon_path = icon_path|default('') %}
34
+ {% set _external = external|default(false) %}
35
+ {% set _sr_external = sr_external|default(false) %}
36
+ {% set _extra_attributes = 'data-ecl-mega-menu-featured-link' %}
37
+
38
+ {# Internal logic - Process properties #}
39
+
40
+ {% if extra_classes is defined and extra_classes is not empty %}
41
+ {% set _css_class = _css_class ~ ' ' ~ extra_classes %}
42
+ {% endif %}
43
+
44
+ {% if extra_attributes is defined and extra_attributes is not empty and extra_attributes is iterable %}
45
+ {% for attr in extra_attributes %}
46
+ {% if attr.value is defined %}
47
+ {% set _extra_attributes = _extra_attributes ~ ' ' ~ attr.name|e('html_attr') ~ '="' ~ attr.value|e('html_attr') ~ '"' %}
48
+ {% else %}
49
+ {% set _extra_attributes = _extra_attributes ~ ' ' ~ attr.name|e('html_attr') %}
50
+ {% endif %}
51
+ {% endfor %}
52
+ {% endif %}
53
+
54
+ {% set _picture_markup = '' %}
55
+ {% if _picture is not empty %}
56
+ {% set _picture_markup %}
57
+ {% include '@ecl/picture/picture.html.twig' with {
58
+ picture: _picture,
59
+ extra_classes: 'ecl-mega-menu__featured-picture',
60
+ extra_image_classes: 'ecl-mega-menu__featured-image',
61
+ } only %}
62
+ {% endset %}
63
+ {% endif %}
64
+
65
+ {% if _label is not empty and _picture_markup is not empty %}
66
+ {% set _item_css_class = _item_css_class ~ ' ecl-mega-menu__featured-list__item--combo' %}
67
+ {% endif %}
68
+ {% if _picture is not empty and _path is empty %}
69
+ {% set _item_css_class = _item_css_class ~ ' ecl-mega-menu__featured-list__item--image-only' %}
70
+ {% endif %}
71
+
72
+ <li class="{{ _item_css_class }}">
73
+ {# Link with image #}
74
+ {% if _path is not empty and _picture is not empty %}
75
+ <a
76
+ class="ecl-link ecl-link--standalone {{ _css_class }}"
77
+ href="{{ _path }}"
78
+ {{ _extra_attributes|raw }}
79
+ >
80
+ {{- _picture_markup -}}{{- _label -}}
81
+ </a>
82
+ {# simple image #}
83
+ {% elseif _picture is not empty %}
84
+ {{- _picture_markup -}}
85
+ {# textual link #}
86
+ {% elseif _path is not empty and _label is not empty %}
87
+ {% include '@ecl/link/link.html.twig' with {
88
+ link: {
89
+ path: _path,
90
+ type: 'standalone',
91
+ icon_path: _icon_path,
92
+ external: _external,
93
+ sr_external: _sr_external,
94
+ label: _label,
95
+ },
96
+ extra_attributes: extra_attributes|default([])|merge([{ name: 'data-ecl-mega-menu-featured-link' }]),
97
+ extra_classes: _css_class,
98
+ } only %}
99
+ {% endif %}
100
+ </li>
101
+
102
+ {% endapply %}
@@ -20,9 +20,11 @@
20
20
  - "title" (string) Title of the featured panel
21
21
  - "content" (string) Content of the featured panel
22
22
  - "items" (associative array) Array of items
23
+ - "picture": (object) (default: {}) Object of type Picture
23
24
  - "path" (string) Path or Url for the href
24
25
  - "label" (string) Label of the item
25
26
  - "external" (boolean) Whether the link is external
27
+ - "icon_path" (string) Path to the icons sprite
26
28
  - "sr_external" (string) (default: '') Additional label for the external icon
27
29
  - "extra_attributes" (array)
28
30
  - "name" (string) Attribute name, eg. 'data-test'
@@ -190,10 +192,10 @@
190
192
  size: 'xs',
191
193
  },
192
194
  extra_classes: _info.link.extra_classes|default('') ~ ' ecl-mega-menu__info-link',
193
- extra_attributes: [{
195
+ extra_attributes: _info.link.extra_attributes|default([])|merge([{
194
196
  name: 'aria-describedby',
195
197
  value: _info_title_id,
196
- }],
198
+ }]),
197
199
  }) only %}
198
200
  {%- endif -%}
199
201
  </div>
@@ -247,7 +249,7 @@
247
249
  {% endif %}
248
250
  <li
249
251
  class="{{ _subitem_class }}"
250
- {{- _subitem_attrs|raw -}}
252
+ {{ _subitem_attrs|raw }}
251
253
  >
252
254
  {%- if child.children is defined and child.children is not empty -%}
253
255
  {# Children, 2nd level #}
@@ -322,13 +324,6 @@
322
324
  data-ecl-mega-menu-featured
323
325
  >
324
326
  <div class="ecl-mega-menu__featured-scrollable">
325
- {% if _featured.picture is not empty %}
326
- {% include '@ecl/picture/picture.html.twig' with {
327
- picture: _featured.picture,
328
- extra_classes: 'ecl-mega-menu__featured-picture',
329
- extra_image_classes: 'ecl-mega-menu__featured-image',
330
- } only %}
331
- {% endif %}
332
327
  {% if _featured.title is not empty %}
333
328
  <span
334
329
  class="ecl-mega-menu__featured-title"
@@ -346,15 +341,7 @@
346
341
  aria-labelledby="{{ 'ecl-mega-menu-featured-title-' ~ sublink_id ~ ' ' ~ sublink_id }}"
347
342
  >
348
343
  {% for item in _featured.items %}
349
- <li class="ecl-mega-menu__featured-list__item">
350
- {% include '@ecl/link/link.html.twig' with {
351
- link: item|merge({ type: 'standalone', icon_path: _icon_path }),
352
- extra_attributes: [
353
- { name: 'data-ecl-mega-menu-featured-link' },
354
- ]|merge(item.extra_attributes|default([])),
355
- extra_classes: item.extra_classes|default(''),
356
- } only %}
357
- </li>
344
+ {% include '@ecl/mega-menu/mega-menu-featured-item.html.twig' with item|merge({ icon_path: _icon_path }) only %}
358
345
  {% endfor %}
359
346
  </ul>
360
347
  {%- endif -%}
@@ -9,6 +9,7 @@
9
9
  - "aria_label" (string) (default: '') Aria label for the main nav
10
10
  - "second_level_aria_label" (string) (default: '') Aria label for the sub-lists, second level
11
11
  - "third_level_aria_label" (string) (default: '') Aria label for the sub-lists, third level
12
+ - "see_all_label": (string) (default: ''): Label for the "view all" link
12
13
  - "icon_path": (string) (default: ''): Path to the icon sprite
13
14
  - "items": (array) (default: []): The menu items - format: [
14
15
  {
@@ -27,7 +28,7 @@
27
28
  "featured" (oject) (optional) {
28
29
  - "title": (string) Title of the featured panel
29
30
  - "content": (string) Top content of the featured panel
30
- - "items": (associative array) (optional) Object of type ECL link
31
+ - "items": (associative array) (optional) Array of items with image and link
31
32
  }
32
33
  "children": (associative array) (optional): [
33
34
  {
@@ -35,7 +36,7 @@
35
36
  "path": (string) (default: '')
36
37
  "external": (boolean),
37
38
  "sr_external" (string) (default: '') Additional label for the external icon
38
- "see_all" (boolean)
39
+ "see_all" (boolean) controls visibility of "View All" button
39
40
  "see_all_label" (string)
40
41
  "see_all_attributes" (optional) (array) (default: [])
41
42
  - "name" (string) Attribute name, eg. 'data-test'
@@ -47,7 +48,7 @@
47
48
  ]
48
49
  }
49
50
  ],
50
- - "extra_classes" (optional) (string) (default: '') Extra classes (space separated) for the nav element
51
+ - "extra_classes" (string) (default: '') Extra classes (space separated) for the nav element
51
52
  - "extra_attributes" (optional) (array) (default: []) Extra attributes for the nav element
52
53
  - "name" (string) Attribute name, eg. 'data-test'
53
54
  - "value" (optional) (string) Attribute value, eg: 'data-test-1'
@@ -63,6 +64,7 @@
63
64
  {% set _toggle = toggle|default({}) %}
64
65
  {% set _close = close|default({}) %}
65
66
  {% set _items = items|default([{}]) %}
67
+ {% set _see_all_label = see_all_label|default('') %}
66
68
  {% set _css_class = 'ecl-mega-menu' %}
67
69
  {% set _extra_attributes = '' %}
68
70
  {% set _icon_path = icon_path|default('') %}
@@ -93,7 +95,6 @@
93
95
  {%- if _close is not empty and _close.label is defined and _close.label is not empty -%}
94
96
  data-ecl-mega-menu-label-close="{{ _close.label }}"
95
97
  {%- endif -%}
96
- aria-expanded="false"
97
98
  role="navigation"
98
99
  id={{ _id }}
99
100
  {%- if _aria_label is not empty %}
package/mega-menu.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { queryOne, queryAll } from '@ecl/dom-utils';
4
4
  import EventManager from '@ecl/event-manager';
5
- import isMobile from 'mobile-device-detect';
6
5
  import { createFocusTrap } from 'focus-trap';
6
+ import Bowser from 'bowser';
7
7
 
8
8
  /**
9
9
  * @param {HTMLElement} element DOM element for component instantiation and scope
@@ -361,9 +361,7 @@ export class MegaMenu {
361
361
  this.back.removeEventListener('click', this.handleClickOnBack);
362
362
  }
363
363
 
364
- if (this.attachClickListener) {
365
- document.removeEventListener('click', this.handleClickGlobal);
366
- }
364
+ document.removeEventListener('click', this.handleClickGlobal);
367
365
  }
368
366
 
369
367
  if (this.links) {
@@ -460,13 +458,17 @@ export class MegaMenu {
460
458
  * - not having hamburger menu on screen
461
459
  */
462
460
  useDesktopDisplay() {
461
+ const browser = Bowser.getParser(window.navigator.userAgent);
462
+ const isMobile = browser.getPlatformType() === 'mobile';
463
+ const isTablet = browser.getPlatformType() === 'tablet';
464
+
463
465
  // Detect mobile devices
464
- if (isMobile.isMobileOnly) {
466
+ if (isMobile) {
465
467
  return false;
466
468
  }
467
469
 
468
470
  // Force mobile display on tablet
469
- if (isMobile.isTablet) {
471
+ if (isTablet) {
470
472
  this.element.classList.add('ecl-mega-menu--forced-mobile');
471
473
  return false;
472
474
  }
@@ -492,10 +494,15 @@ export class MegaMenu {
492
494
 
493
495
  // Remove display:none from the sublists
494
496
  if (subLists && viewport === 'mobile') {
495
- const megaMenus = queryAll(
496
- '.ecl-mega-menu__item > .ecl-mega-menu__wrapper > .ecl-container > [data-ecl-mega-menu-mega]',
497
+ const megaMenus = queryAll('[data-ecl-mega-menu-mega]', this.element);
498
+ const featuredPanels = queryAll(
499
+ '[data-ecl-mega-menu-featured]',
497
500
  this.element,
498
501
  );
502
+ if (featuredPanels.length) {
503
+ megaMenus.push(...featuredPanels);
504
+ }
505
+
499
506
  megaMenus.forEach((menu) => {
500
507
  menu.style.height = '';
501
508
  });
@@ -578,7 +585,6 @@ export class MegaMenu {
578
585
  this.checkDropdownHeight(current);
579
586
  });
580
587
  } else {
581
- this.element.setAttribute('aria-expanded', 'false');
582
588
  this.element.removeAttribute('data-expanded');
583
589
  this.open.setAttribute('aria-expanded', 'false');
584
590
  this.enableScroll();
@@ -663,6 +669,11 @@ export class MegaMenu {
663
669
  checkDropdownHeight(menuItem, hide = true) {
664
670
  const infoPanel = queryOne('.ecl-mega-menu__info', menuItem);
665
671
  const mainPanel = queryOne('.ecl-mega-menu__mega', menuItem);
672
+ const expanded = queryOne('.ecl-mega-menu__subitem--expanded', menuItem);
673
+ let secondPanel = null;
674
+ if (expanded) {
675
+ secondPanel = queryOne('.ecl-mega-menu__mega--level-2', expanded);
676
+ }
666
677
  // Hide the panels while calculating their heights
667
678
  if (mainPanel && this.isDesktop && hide) {
668
679
  mainPanel.style.opacity = 0;
@@ -670,6 +681,10 @@ export class MegaMenu {
670
681
  if (infoPanel && this.isDesktop && hide) {
671
682
  infoPanel.style.opacity = 0;
672
683
  }
684
+ // Second panel has already zero opacity in reality, this is for consistency
685
+ if (secondPanel && this.isDesktop && hide) {
686
+ secondPanel.opacity = 0;
687
+ }
673
688
  setTimeout(() => {
674
689
  const viewportHeight = window.innerHeight;
675
690
  let infoPanelHeight = 0;
@@ -677,7 +692,6 @@ export class MegaMenu {
677
692
  if (this.isDesktop) {
678
693
  const heights = [];
679
694
  let height = 0;
680
- let secondPanel = null;
681
695
  let featuredPanel = null;
682
696
  let itemsHeight = 0;
683
697
  let subItemsHeight = 0;
@@ -724,38 +738,32 @@ export class MegaMenu {
724
738
  }
725
739
  }
726
740
  }
727
- const expanded = queryOne(
728
- '.ecl-mega-menu__subitem--expanded',
729
- menuItem,
730
- );
731
-
732
- if (expanded) {
733
- secondPanel = queryOne('.ecl-mega-menu__mega--level-2', expanded);
734
- if (secondPanel) {
735
- secondPanel.style.height = '';
736
- const subItems = queryAll(`${this.subItemSelector}`, secondPanel);
737
- if (subItems.length > 0) {
738
- subItems.forEach((item) => {
739
- subItemsHeight += item.getBoundingClientRect().height;
740
- });
741
- }
742
- heights.push(subItemsHeight);
743
- // Featured panel calculations.
744
- featuredPanel = queryOne('.ecl-mega-menu__featured', expanded);
745
- if (featuredPanel) {
746
- // Get the elements inside the scrollable container and calculate their heights.
747
- Array.from(featuredPanel.firstElementChild.children).forEach(
748
- (child) => {
749
- const elStyle = window.getComputedStyle(child);
750
- const marginHeight =
751
- parseFloat(elStyle.marginTop) +
752
- parseFloat(elStyle.marginBottom);
753
- featuredHeight += child.offsetHeight + marginHeight;
754
- },
755
- );
756
741
 
757
- heights.push(featuredHeight);
758
- }
742
+ if (secondPanel) {
743
+ secondPanel.style.height = '';
744
+ const subItems = queryAll(`${this.subItemSelector}`, secondPanel);
745
+ if (subItems.length > 0) {
746
+ subItems.forEach((item) => {
747
+ subItemsHeight += item.getBoundingClientRect().height;
748
+ });
749
+ }
750
+ heights.push(subItemsHeight);
751
+ // Featured panel calculations.
752
+ featuredPanel = queryOne('.ecl-mega-menu__featured', expanded);
753
+ if (featuredPanel) {
754
+ // Get the elements inside the scrollable container and calculate their heights.
755
+ Array.from(featuredPanel.firstElementChild.children).forEach(
756
+ (child) => {
757
+ const elStyle = window.getComputedStyle(child);
758
+ const marginHeight =
759
+ parseFloat(elStyle.marginTop) +
760
+ parseFloat(elStyle.marginBottom);
761
+ featuredHeight += child.offsetHeight + marginHeight;
762
+ },
763
+ );
764
+ // Add 5px to the featured panel height to prevent scrollbar on hover
765
+ featuredHeight += 5;
766
+ heights.push(featuredHeight);
759
767
  }
760
768
  }
761
769
 
@@ -775,6 +783,7 @@ export class MegaMenu {
775
783
  if (wrapper) {
776
784
  wrapper.style.height = `${height}px`;
777
785
  }
786
+
778
787
  if (mainPanel && this.isLarge) {
779
788
  mainPanel.style.height = `${height}px`;
780
789
  } else if (mainPanel && infoPanel && this.isDesktop) {
@@ -800,6 +809,9 @@ export class MegaMenu {
800
809
  if (infoPanel && this.isDesktop) {
801
810
  infoPanel.style.opacity = 1;
802
811
  }
812
+ if (secondPanel && this.isDesktop) {
813
+ secondPanel.style.opacity = 1;
814
+ }
803
815
  }, 100);
804
816
  }
805
817
 
@@ -903,7 +915,7 @@ export class MegaMenu {
903
915
  handleKeyboard(e) {
904
916
  const element = e.target;
905
917
  const cList = element.classList;
906
- const menuExpanded = this.element.getAttribute('aria-expanded');
918
+ const menuExpanded = this.element.getAttribute('data-expanded');
907
919
 
908
920
  // Detect press on Escape
909
921
  if (e.key === 'Escape' || e.key === 'Esc') {
@@ -911,7 +923,7 @@ export class MegaMenu {
911
923
  element.blur();
912
924
  }
913
925
 
914
- if (menuExpanded === 'false') {
926
+ if (!menuExpanded) {
915
927
  this.closeOpenDropdown();
916
928
  }
917
929
  return;
@@ -1155,7 +1167,7 @@ export class MegaMenu {
1155
1167
  } else {
1156
1168
  e.preventDefault();
1157
1169
  this.disableScroll();
1158
- this.element.setAttribute('aria-expanded', 'true');
1170
+ this.element.setAttribute('data-expanded', true);
1159
1171
  this.element.classList.add('ecl-mega-menu--start-panel');
1160
1172
  this.element.classList.remove(
1161
1173
  'ecl-mega-menu--one-panel',
@@ -1197,7 +1209,7 @@ export class MegaMenu {
1197
1209
  * @fires Menu#onClose
1198
1210
  */
1199
1211
  handleClickOnClose(e) {
1200
- if (this.element.getAttribute('aria-expanded') === 'true') {
1212
+ if (this.element.getAttribute('data-expanded')) {
1201
1213
  this.focusTrap.deactivate();
1202
1214
  this.closeOpenDropdown();
1203
1215
  this.trigger('onClose', e);
@@ -1312,7 +1324,6 @@ export class MegaMenu {
1312
1324
  this.positionMenuOverlay();
1313
1325
  this.checkDropdownHeight(menuItem);
1314
1326
  this.element.setAttribute('data-expanded', true);
1315
- this.element.setAttribute('aria-expanded', 'true');
1316
1327
  this.element.classList.add('ecl-mega-menu--one-panel');
1317
1328
  this.element.classList.remove('ecl-mega-menu--start-panel');
1318
1329
  this.open.setAttribute('aria-expanded', 'true');
@@ -1360,19 +1371,6 @@ export class MegaMenu {
1360
1371
  };
1361
1372
  const details = { panel: 1, item: menuItem };
1362
1373
  this.trigger('OnOpenPanel', details);
1363
- if (this.isDesktop) {
1364
- const list = queryOne('.ecl-mega-menu__sublist', menuItem);
1365
- if (list) {
1366
- // Expand the item in the sublist if it contains children.
1367
- const firstExpandedChild = Array.from(list.children).find((child) =>
1368
- child.firstElementChild?.hasAttribute('aria-expanded'),
1369
- );
1370
-
1371
- if (firstExpandedChild) {
1372
- this.handleSecondPanel(firstExpandedChild, 'expand', true);
1373
- }
1374
- }
1375
- }
1376
1374
  break;
1377
1375
  }
1378
1376
 
@@ -1392,7 +1390,7 @@ export class MegaMenu {
1392
1390
  *
1393
1391
  * @fires MegaMenu#onOpenPanel
1394
1392
  */
1395
- handleSecondPanel(menuItem, op, noCheck = false) {
1393
+ handleSecondPanel(menuItem, op) {
1396
1394
  const infoPanel = queryOne(
1397
1395
  '.ecl-mega-menu__info',
1398
1396
  menuItem.closest('.ecl-container'),
@@ -1410,13 +1408,16 @@ export class MegaMenu {
1410
1408
  if (item === menuItem) {
1411
1409
  if (itemLink && itemLink.hasAttribute('aria-expanded')) {
1412
1410
  itemLink.setAttribute('aria-expanded', 'true');
1413
-
1411
+ const mega = queryOne('.ecl-mega-menu__mega', item);
1414
1412
  if (!this.isDesktop) {
1415
1413
  // We use this class mainly to recover the default behavior of the link.
1416
1414
  itemLink.classList.add('ecl-mega-menu__parent-link');
1417
1415
  if (this.back) {
1418
1416
  this.back.focus();
1419
1417
  }
1418
+ } else {
1419
+ // Hide the panel since it will be resized later.
1420
+ mega.style.opacity = 0;
1420
1421
  }
1421
1422
  item.classList.add('ecl-mega-menu__subitem--expanded');
1422
1423
  }
@@ -1450,12 +1451,11 @@ export class MegaMenu {
1450
1451
  });
1451
1452
  }
1452
1453
  this.positionMenuOverlay();
1453
- if (!noCheck) {
1454
- this.checkDropdownHeight(
1455
- menuItem.closest('.ecl-mega-menu__item'),
1456
- false,
1457
- );
1458
- }
1454
+ this.checkDropdownHeight(
1455
+ menuItem.closest('.ecl-mega-menu__item'),
1456
+ false,
1457
+ );
1458
+
1459
1459
  const details = { panel: 2, item: menuItem };
1460
1460
  this.trigger('OnOpenPanel', details);
1461
1461
  break;
@@ -1573,7 +1573,6 @@ export class MegaMenu {
1573
1573
  }
1574
1574
  }
1575
1575
  this.enableScroll();
1576
- this.element.setAttribute('aria-expanded', 'false');
1577
1576
  this.element.removeAttribute('data-expanded');
1578
1577
  this.element.classList.remove(
1579
1578
  'ecl-mega-menu--start-panel',
@@ -1660,11 +1659,11 @@ export class MegaMenu {
1660
1659
  */
1661
1660
  handleFocusOut(e) {
1662
1661
  const element = e.target;
1663
- const menuExpanded = this.element.getAttribute('aria-expanded');
1662
+ const menuExpanded = this.element.getAttribute('data-expanded');
1664
1663
 
1665
1664
  // Specific focus action for mobile menu
1666
1665
  // Loop through the items and go back to close button
1667
- if (menuExpanded === 'true' && !this.isDesktop) {
1666
+ if (menuExpanded && !this.isDesktop) {
1668
1667
  const nextItem = element.parentElement.nextSibling;
1669
1668
 
1670
1669
  if (!nextItem) {
package/mega-menu.scss CHANGED
@@ -14,7 +14,8 @@ $mega-menu: null !default;
14
14
 
15
15
  @mixin with-scrollbar {
16
16
  overflow-y: auto;
17
- scrollbar-color: var(--c-n) rgba(0, 0, 0, 0);
17
+ scrollbar-color: var(--cm-on-surface-neutral-medium, var(--c-n))
18
+ rgba(0, 0, 0, 0);
18
19
  scrollbar-width: thin;
19
20
  }
20
21
 
@@ -68,6 +69,7 @@ $mega-menu: null !default;
68
69
  }
69
70
 
70
71
  &:hover {
72
+ background-color: map.get($mega-menu, 'mobile', 'open-background-hover');
71
73
  text-decoration: underline;
72
74
  }
73
75
 
@@ -80,9 +82,13 @@ $mega-menu: null !default;
80
82
  }
81
83
  }
82
84
 
83
- .ecl-mega-menu[aria-expanded='true'] .ecl-mega-menu__open {
85
+ .ecl-mega-menu[data-expanded] .ecl-mega-menu__open {
84
86
  background-color: map.get($mega-menu, 'mobile', 'open-background-active');
85
87
 
88
+ &:hover {
89
+ background-color: map.get($mega-menu, 'mobile', 'open-background-hover');
90
+ }
91
+
86
92
  .ecl-icon:first-of-type {
87
93
  display: none;
88
94
  }
@@ -114,7 +120,7 @@ $mega-menu: null !default;
114
120
  padding-top: 0;
115
121
 
116
122
  .ecl-container {
117
- padding: 0 var(--s-m);
123
+ padding: 0 map.get($mega-menu, 'desktop', 'container-padding-horizontal');
118
124
  }
119
125
 
120
126
  .ecl-mega-menu__container {
@@ -164,7 +170,7 @@ $mega-menu: null !default;
164
170
  }
165
171
 
166
172
  // Expanded
167
- .ecl-mega-menu[aria-expanded='true'] .ecl-mega-menu__inner {
173
+ .ecl-mega-menu[data-expanded] .ecl-mega-menu__inner {
168
174
  display: block;
169
175
  right: 0;
170
176
  }
@@ -275,8 +281,7 @@ $mega-menu: null !default;
275
281
  z-index: -1;
276
282
  }
277
283
 
278
- .ecl-mega-menu[aria-expanded='true'],
279
- .ecl-mega-menu[data-expanded='true'] {
284
+ .ecl-mega-menu[data-expanded] {
280
285
  .ecl-mega-menu__overlay {
281
286
  display: block;
282
287
  }
@@ -316,8 +321,9 @@ $mega-menu: null !default;
316
321
  }
317
322
 
318
323
  .ecl-mega-menu__wrapper {
319
- background: map.get($theme, 'color', 'white');
324
+ background: #fff;
320
325
  display: none;
326
+ font: map.get($mega-menu, 'global', 'font');
321
327
  position: absolute;
322
328
  height: 100%;
323
329
  left: 0;
@@ -358,12 +364,14 @@ $mega-menu: null !default;
358
364
  .ecl-mega-menu__featured-list__item .ecl-link {
359
365
  align-items: center;
360
366
  background: transparent;
367
+ /* stylelint-disable-next-line declaration-property-value-no-unknown */
361
368
  border-bottom: 1px solid
362
369
  map.get($mega-menu, 'desktop', 'sublink-current-background');
363
370
  border-radius: 0;
364
371
  box-sizing: border-box;
365
372
  color: map.get($mega-menu, 'mobile', 'item-color');
366
373
  display: inline-flex;
374
+ font: map.get($mega-menu, 'global', 'font');
367
375
  line-height: map.get($theme, 'line-height-ui', 'xs');
368
376
  padding: map.get($mega-menu, 'mobile', 'item-padding');
369
377
  position: relative;
@@ -392,8 +400,8 @@ $mega-menu: null !default;
392
400
  background: transparent;
393
401
  border-color: transparent;
394
402
  border-radius: 0px;
395
- color: var(--c-d);
396
- outline-color: var(--c-p);
403
+ color: var(--cm-on-surface-brand, var(--c-d));
404
+ outline-color: var(--cm-border-primary, var(--c-p));
397
405
  outline-offset: -2px;
398
406
  outline-width: 2px;
399
407
  }
@@ -413,11 +421,23 @@ $mega-menu: null !default;
413
421
  }
414
422
  }
415
423
 
416
- .ecl-mega-menu__featured-list__item .ecl-link {
417
- border-bottom: 1px solid map.get($mega-menu, 'mobile', 'featured-link-border');
424
+ .ecl-mega-menu__featured-list__item {
425
+ .ecl-link {
426
+ /* stylelint-disable-next-line declaration-property-value-no-unknown */
427
+ border-bottom: 1px solid
428
+ map.get($mega-menu, 'mobile', 'featured-link-border');
418
429
 
419
- &:hover {
420
- border-color: map.get($mega-menu, 'mobile', 'featured-link-border');
430
+ .ecl-picture {
431
+ margin-inline: calc(-1 * var(--s-s)) calc(-1 * var(--s-2xl));
432
+ }
433
+
434
+ &:hover {
435
+ border-color: map.get($mega-menu, 'mobile', 'featured-link-border');
436
+ }
437
+ }
438
+
439
+ &--combo .ecl-mega-menu__featured-image {
440
+ margin-block-end: var(--s-xs);
421
441
  }
422
442
  }
423
443
 
@@ -438,7 +458,7 @@ $mega-menu: null !default;
438
458
  outline: none;
439
459
 
440
460
  .ecl-button__label {
441
- outline: 2px solid var(--c-p);
461
+ outline: 2px solid var(--cm-border-primary, var(--c-p));
442
462
  outline-offset: 4px;
443
463
  }
444
464
  }
@@ -468,7 +488,6 @@ $mega-menu: null !default;
468
488
  }
469
489
 
470
490
  .ecl-mega-menu__info-content {
471
- font: var(--f-m);
472
491
  max-width: var(--max-w);
473
492
  }
474
493
  }
@@ -494,11 +513,11 @@ $mega-menu: null !default;
494
513
  .ecl-mega-menu__subitem {
495
514
  .ecl-mega-menu__sublink--level-2 {
496
515
  background: transparent;
497
- color: var(--c-p);
516
+ color: var(--cm-on-surface-primary, var(--c-p));
498
517
 
499
518
  &:hover {
500
519
  box-shadow: none;
501
- color: var(--c-p-140);
520
+ color: var(--cm-on-surface-primary-highest, var(--c-p-140));
502
521
  }
503
522
  }
504
523
  }
@@ -553,7 +572,6 @@ $mega-menu: null !default;
553
572
  border-radius: 0;
554
573
  color: map.get($mega-menu, 'desktop', 'item-color');
555
574
  display: inline-flex;
556
- font: var(--f-m);
557
575
  height: 100%;
558
576
  line-height: map.get($mega-menu, 'desktop', 'link-line-height');
559
577
  padding: map.get($mega-menu, 'desktop', 'link-padding');
@@ -561,7 +579,7 @@ $mega-menu: null !default;
561
579
  z-index: 0;
562
580
 
563
581
  &:active {
564
- color: map.get($theme, 'color', 'white');
582
+ color: #fff;
565
583
  }
566
584
 
567
585
  &:hover {
@@ -579,7 +597,7 @@ $mega-menu: null !default;
579
597
  );
580
598
  border-radius: 0;
581
599
  color: map.get($mega-menu, 'desktop', 'item-color-focus');
582
- outline-color: map.get($theme, 'color', 'white');
600
+ outline-color: #fff;
583
601
  outline-offset: -8px;
584
602
  outline-width: map.get($mega-menu, 'desktop', 'outline-width');
585
603
  }
@@ -635,7 +653,7 @@ $mega-menu: null !default;
635
653
  }
636
654
 
637
655
  .ecl-mega-menu__link:focus-visible {
638
- outline-color: var(--c-p);
656
+ outline-color: var(--cm-border-primary, var(--c-p));
639
657
  }
640
658
  }
641
659
  }
@@ -651,8 +669,8 @@ $mega-menu: null !default;
651
669
 
652
670
  &.ecl-mega-menu__item--expanded {
653
671
  .ecl-mega-menu__link {
654
- background-color: map.get($theme, 'color', 'white');
655
- color: var(--c-d);
672
+ background-color: #fff;
673
+ color: var(--cm-on-surface-brand, var(--c-d));
656
674
  z-index: map.get($theme, 'z-index', 'dropdown') + 1;
657
675
  }
658
676
  }
@@ -686,8 +704,6 @@ $mega-menu: null !default;
686
704
  background-color: map.get($mega-menu, 'global', 'greysh-background');
687
705
  box-shadow: none;
688
706
  display: none;
689
- font: map.get($mega-menu, 'mobile', 'subtitle-font');
690
- font-weight: map.get($mega-menu, 'mobile', 'subtitle-font-weight');
691
707
  }
692
708
  }
693
709
 
@@ -770,8 +786,7 @@ $mega-menu: null !default;
770
786
  .ecl-link {
771
787
  border-radius: 0;
772
788
  box-sizing: border-box;
773
- color: var(--c-d);
774
- font: var(--f-m);
789
+ color: var(--cm-on-surface-brand, var(--c-d));
775
790
  margin: 0 var(--s-l);
776
791
  padding: var(--s-xs) 0;
777
792
 
@@ -798,10 +813,12 @@ $mega-menu: null !default;
798
813
  .ecl-mega-menu__sublink {
799
814
  background: transparent;
800
815
  box-sizing: border-box;
816
+ /* stylelint-disable-next-line declaration-property-value-no-unknown */
801
817
  border-bottom: 1.5px solid
802
818
  map.get($mega-menu, 'desktop', 'sublink-current-background');
803
819
  border-radius: 0;
804
820
  color: map.get($mega-menu, 'mobile', 'item-color');
821
+ font: map.get($mega-menu, 'global', 'font');
805
822
  padding: map.get($mega-menu, 'mobile', 'subitem-padding');
806
823
  position: relative;
807
824
  line-height: map.get($theme, 'line-height-ui', 'xs');
@@ -835,15 +852,15 @@ $mega-menu: null !default;
835
852
  }
836
853
 
837
854
  &--current {
838
- background-color: var(--c-n-80);
839
- box-shadow: inset 4px 0 0 0 var(--c-p);
855
+ background-color: var(--cm-surface-neutral-lowest, var(--c-n-80));
856
+ box-shadow: inset 4px 0 0 0 var(--cm-border-primary, var(--c-p));
840
857
  }
841
858
 
842
859
  &:focus-visible {
843
860
  background: transparent;
844
861
  border-color: transparent;
845
- color: var(--c-d);
846
- outline-color: var(--c-p);
862
+ color: var(--cm-on-surface-brand, var(--c-d));
863
+ outline-color: var(--cm-border-primary, var(--c-p));
847
864
  outline-offset: -2px;
848
865
  outline-width: 2px;
849
866
  }
@@ -871,14 +888,14 @@ $mega-menu: null !default;
871
888
  }
872
889
 
873
890
  .ecl-mega-menu__sublink {
874
- color: var(--c-p);
891
+ color: var(--cm-on-surface-primary, var(--c-p));
875
892
 
876
893
  &:hover {
877
894
  text-decoration: underline;
878
895
  }
879
896
 
880
897
  &:focus-visible {
881
- color: var(--c-p) !important;
898
+ color: var(--cm-on-surface-primary, var(--c-p)) !important;
882
899
  }
883
900
 
884
901
  &.ecl-mega-menu__sublink--last {
@@ -897,27 +914,36 @@ $mega-menu: null !default;
897
914
 
898
915
  .ecl-mega-menu__featured {
899
916
  background-color: map.get($mega-menu, 'mobile', 'featured-background');
900
- border-color: var(--c-n);
917
+ border-color: var(--cm-border-neutral, var(--c-n));
901
918
  border-width: 0.5px;
902
919
  flex-direction: column;
903
920
  padding: 0 var(--s-xs);
904
921
 
922
+ .ecl-mega-menu__featured-scrollable {
923
+ background-color: map.get($mega-menu, 'mobile', 'featured-background');
924
+ }
925
+
905
926
  .ecl-mega-menu__featured-picture {
906
927
  display: block;
907
928
 
908
929
  .ecl-mega-menu__featured-image {
909
- aspect-ratio: 21/9;
930
+ aspect-ratio: 16/9;
910
931
  display: block;
911
932
  margin-inline-start: var(--s-l);
933
+ margin-block-start: var(--s-m);
912
934
  max-width: 15.25rem;
913
935
  }
914
936
  }
915
937
 
938
+ .ecl-link .ecl-mega-menu__featured-picture .ecl-mega-menu__featured-image {
939
+ margin-inline-start: var(--s-s);
940
+ }
941
+
916
942
  .ecl-mega-menu__featured-title {
917
943
  display: block;
918
944
  margin: calc(var(--s-xs) + 2px) var(--s-m) calc(var(--s-xs) + 2px)
919
945
  var(--s-l);
920
- font: var(--f-l);
946
+ font: var(--f-m);
921
947
  }
922
948
 
923
949
  .ecl-mega-menu__featured-content {
@@ -932,16 +958,20 @@ $mega-menu: null !default;
932
958
  .ecl-link {
933
959
  border-radius: 0;
934
960
  box-sizing: border-box;
935
- color: var(--c-p);
961
+ color: var(--cm-on-surface-primary, var(--c-p));
936
962
  display: block;
937
963
  outline-offset: -2px;
938
964
  padding: var(--s-m) var(--s-l);
939
965
  width: 100%;
940
966
 
941
967
  &:hover {
942
- color: var(--c-p);
968
+ color: var(--cm-on-surface-primary, var(--c-p));
943
969
  }
944
970
  }
971
+
972
+ &--image-only {
973
+ margin-block-end: var(--s-xs);
974
+ }
945
975
  }
946
976
  }
947
977
  }
@@ -968,7 +998,7 @@ $mega-menu: null !default;
968
998
  width: 100vw;
969
999
 
970
1000
  &::before {
971
- background: #e3e3e3;
1001
+ background: var(--cm-border-neutral, '#e3e3e3');
972
1002
  content: ' ';
973
1003
  display: block;
974
1004
  height: 1px;
@@ -998,7 +1028,7 @@ $mega-menu: null !default;
998
1028
  > .ecl-mega-menu__wrapper
999
1029
  > .ecl-container
1000
1030
  > .ecl-mega-menu__info {
1001
- background-color: map.get($theme, 'color', 'white');
1031
+ background-color: #fff;
1002
1032
  border: map.get($mega-menu, 'desktop', 'mega-border');
1003
1033
  border-radius: 0 0 map.get($mega-menu, 'global', 'border-radius')
1004
1034
  map.get($mega-menu, 'global', 'border-radius');
@@ -1048,7 +1078,7 @@ $mega-menu: null !default;
1048
1078
  }
1049
1079
 
1050
1080
  .ecl-mega-menu__item > .ecl-mega-menu__mega-container {
1051
- background-color: map.get($theme, 'color', 'white');
1081
+ background-color: #fff;
1052
1082
  top: 100%;
1053
1083
  width: 100%;
1054
1084
 
@@ -1101,7 +1131,7 @@ $mega-menu: null !default;
1101
1131
  }
1102
1132
 
1103
1133
  .ecl-mega-menu__subitem--expanded .ecl-mega-menu__featured {
1104
- background: map.get($theme, 'color', 'white');
1134
+ background: #fff;
1105
1135
  display: flex;
1106
1136
  margin-bottom: 0;
1107
1137
 
@@ -1121,7 +1151,7 @@ $mega-menu: null !default;
1121
1151
  }
1122
1152
 
1123
1153
  .ecl-mega-menu__sublist {
1124
- border-color: map.get($theme, 'color', 'white');
1154
+ border-color: #fff;
1125
1155
  border-width: 2px;
1126
1156
  display: flex;
1127
1157
  flex-direction: column;
@@ -1210,7 +1240,7 @@ $mega-menu: null !default;
1210
1240
  }
1211
1241
 
1212
1242
  &:focus-visible {
1213
- outline-color: var(--c-p);
1243
+ outline-color: var(--cm-border-primary, var(--c-p));
1214
1244
  }
1215
1245
  }
1216
1246
  }
@@ -1252,14 +1282,14 @@ $mega-menu: null !default;
1252
1282
 
1253
1283
  &:focus-visible {
1254
1284
  border-color: transparent;
1255
- color: var(--c-d);
1256
- outline-color: var(--c-p);
1285
+ color: var(--cm-on-surface-brand, var(--c-d));
1286
+ outline-color: var(--cm-border-primary, var(--c-p));
1257
1287
  outline-width: 2px;
1258
1288
  }
1259
1289
  }
1260
1290
 
1261
1291
  .ecl-mega-menu__subitem[aria-expanded] > .ecl-mega-menu__sublink:hover {
1262
- background-color: var(--c-n-40);
1292
+ background-color: var(--cm-surface-neutral-lowest, var(--c-n-40));
1263
1293
  box-shadow: none;
1264
1294
  text-decoration: none;
1265
1295
  }
@@ -1273,7 +1303,7 @@ $mega-menu: null !default;
1273
1303
  'desktop',
1274
1304
  'sublink-current-background'
1275
1305
  );
1276
- border-color: var(--c-p);
1306
+ border-color: var(--cm-border-primary, var(--c-p));
1277
1307
  }
1278
1308
  }
1279
1309
  }
@@ -1291,6 +1321,9 @@ $mega-menu: null !default;
1291
1321
  top: 0;
1292
1322
 
1293
1323
  .ecl-mega-menu__featured-scrollable {
1324
+ background-color: transparent;
1325
+ height: 100%;
1326
+
1294
1327
  @include with-scrollbar;
1295
1328
  }
1296
1329
 
@@ -1298,8 +1331,9 @@ $mega-menu: null !default;
1298
1331
  display: block;
1299
1332
 
1300
1333
  .ecl-mega-menu__featured-image {
1301
- aspect-ratio: 21/9;
1334
+ aspect-ratio: 16/9;
1302
1335
  display: block;
1336
+ margin-block-start: 0;
1303
1337
  margin-inline-start: var(--s-s);
1304
1338
  max-width: calc(100% - var(--s-s));
1305
1339
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@ecl/mega-menu",
3
3
  "author": "European Commission",
4
4
  "license": "EUPL-1.2",
5
- "version": "5.0.0-alpha.1",
5
+ "version": "5.0.0-alpha.10",
6
6
  "description": "ECL Mega Menu",
7
7
  "publishConfig": {
8
8
  "access": "public"
@@ -11,12 +11,13 @@
11
11
  "module": "mega-menu.js",
12
12
  "style": "mega-menu.scss",
13
13
  "dependencies": {
14
- "@ecl/button": "5.0.0-alpha.1",
15
- "@ecl/dom-utils": "5.0.0-alpha.1",
16
- "@ecl/event-manager": "5.0.0-alpha.1",
17
- "@ecl/link": "5.0.0-alpha.1",
18
- "focus-trap": "7.6.4",
19
- "mobile-device-detect": "0.4.3"
14
+ "@ecl/button": "5.0.0-alpha.10",
15
+ "@ecl/dom-utils": "5.0.0-alpha.10",
16
+ "@ecl/event-manager": "5.0.0-alpha.10",
17
+ "@ecl/link": "5.0.0-alpha.10",
18
+ "@ecl/picture": "5.0.0-alpha.10",
19
+ "bowser": "2.11.0",
20
+ "focus-trap": "7.6.4"
20
21
  },
21
22
  "repository": {
22
23
  "type": "git",
@@ -32,5 +33,5 @@
32
33
  "design-system",
33
34
  "twig"
34
35
  ],
35
- "gitHead": "f800b6d2de209fcfe182aadca5f7e45ad497b23a"
36
+ "gitHead": "8f085d9bbc9ebe568932bc297fdcf7f7a47da47b"
36
37
  }