@ecl/mega-menu 5.0.0-alpha.21 → 5.0.0-alpha.22.1

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
@@ -33,6 +33,7 @@ npm install --save @ecl/mega-menu
33
33
  "container": (string) Empty container to be filled in with content
34
34
  "info" (object) (default: {}) Info column
35
35
  "title" (string) Title of the info panel
36
+ "one_level_only" (boolean) (default: false)
36
37
  "content" (string) Content of the info panel
37
38
  "link" (object) Structure for the "discover more" link, following ECL Link
38
39
  "featured" (object) (optional) {
@@ -6,6 +6,7 @@
6
6
  - "item" (object)
7
7
  - "label" (string) Label of the menu link
8
8
  - "external" (boolean) External link
9
+ - "one_level_only" (boolean) (default: false)
9
10
  - "promotional" (boolean) (default: false) Promotional menu item, styles can be custommized defining:
10
11
  --ecl-mega-menu-item-promotional-bg
11
12
  --ecl-mega-menu-item-promotional-hover-bg
@@ -62,6 +63,7 @@
62
63
  {% set _menu_list_item_class = 'ecl-mega-menu__item' %}
63
64
  {% set _featured = _item.featured|default({}) %}
64
65
  {% set _info = _item.info|default({}) %}
66
+ {% set _one_level_only = _item.one_level_only|default(false) %}
65
67
  {% set _promotional = _item.promotional|default(false) %}
66
68
  {% set _see_all = see_all|default(false) %}
67
69
  {% set _sublist_class = 'ecl-mega-menu__sublist' %}
@@ -84,10 +86,18 @@
84
86
  {% set _menu_list_item_class = _menu_list_item_class ~ ' ecl-mega-menu__item--has-children' %}
85
87
  {% endif %}
86
88
 
89
+ {% if _one_level_only %}
90
+ {% set _menu_list_item_class = _menu_list_item_class ~ ' ecl-mega-menu__item--one-level-only' %}
91
+ {% endif %}
92
+
87
93
  {% if _item.level|default(0) < 2 and _featured is not empty %}
88
94
  {% set _mega_class = _mega_class ~ ' ecl-mega-menu__mega--has-featured' %}
89
95
  {% endif %}
90
96
 
97
+ {% if _info is empty %}
98
+ {% set _mega_class = _mega_class ~ ' ecl-mega-menu__mega--no-info' %}
99
+ {% endif %}
100
+
91
101
  {% if _item.level == 2 %}
92
102
  {% set _mega_class = _mega_class ~ ' ecl-mega-menu__mega--level-2' %}
93
103
  {% if _item.children is empty %}
@@ -350,9 +360,12 @@
350
360
  {%- endif -%}
351
361
  {%- if _featured.items is not empty and _featured.items is iterable -%}
352
362
  {% set sublink_id = sublink_id ? sublink_id : _id %}
363
+ {% set labelled_by = _featured.title is not empty ? 'ecl-mega-menu-featured-title-' ~ sublink_id ~ ' ' ~ sublink_id : sublink_id %}
353
364
  <ul
354
365
  class="ecl-mega-menu__featured-list"
355
- aria-labelledby="{{ 'ecl-mega-menu-featured-title-' ~ sublink_id ~ ' ' ~ sublink_id }}"
366
+ {% if labelled_by is not empty %}
367
+ aria-labelledby="{{ labelled_by }}"
368
+ {% endif %}
356
369
  >
357
370
  {% for item in _featured.items %}
358
371
  {% include '@ecl/mega-menu/mega-menu-featured-item.html.twig' with item only %}
@@ -17,6 +17,7 @@
17
17
  "path": (string) (default: '')
18
18
  "external": (boolean) (optional),
19
19
  "sr_external" (string) (default: '') Additional label for the external icon
20
+ "one_level_only" (boolean) (default: false)
20
21
  "extra_attributes" (optional) (array) (default: []) Extra attributes for link,
21
22
  - "name" (string) Attribute name, eg. 'data-test'
22
23
  - "value" (optional) (string) Attribute value, eg: 'data-test-1'
package/mega-menu.js CHANGED
@@ -136,7 +136,8 @@ export class MegaMenu {
136
136
  this.menuOverlay = null;
137
137
  this.currentItem = null;
138
138
  this.totalItemsWidth = 0;
139
- this.breakpointL = 1140;
139
+ this.breakpointTablet = 768;
140
+ this.breakpointDesktop = 1140;
140
141
  this.openPanel = { num: 0, item: {} };
141
142
  this.infoLinks = null;
142
143
  this.seeAllLinks = null;
@@ -461,7 +462,7 @@ export class MegaMenu {
461
462
  const isTablet = browser.getPlatformType() === 'tablet';
462
463
 
463
464
  // Detect mobile devices
464
- if (isMobile) {
465
+ if (isMobile && window.innerWidth < this.breakpointTablet) {
465
466
  return false;
466
467
  }
467
468
 
@@ -471,8 +472,8 @@ export class MegaMenu {
471
472
  return false;
472
473
  }
473
474
 
474
- // After all that, check if the hamburger button is displayed
475
- if (window.innerWidth < this.breakpointL) {
475
+ // After all that, check the screen width
476
+ if (window.innerWidth < this.breakpointDesktop) {
476
477
  return false;
477
478
  }
478
479
 
@@ -627,16 +628,16 @@ export class MegaMenu {
627
628
  this.resizeTimer = setTimeout(() => {
628
629
  const screenWidth = window.innerWidth;
629
630
  if (this.prevScreenWidth !== undefined) {
630
- // Check if the transition involves crossing the L breakpoint
631
+ // Check if the transition involves crossing the desktop breakpoint
631
632
  const isTransition =
632
- (this.prevScreenWidth <= this.breakpointL &&
633
- screenWidth > this.breakpointL) ||
634
- (this.prevScreenWidth > this.breakpointL &&
635
- screenWidth <= this.breakpointL);
636
- // If we are moving in or out the L breakpoint, reset the styles
633
+ (this.prevScreenWidth <= this.breakpointDesktop &&
634
+ screenWidth > this.breakpointDesktop) ||
635
+ (this.prevScreenWidth > this.breakpointDesktop &&
636
+ screenWidth <= this.breakpointDesktop);
637
+ // If we are moving in or out the desktop breakpoint, reset the styles
637
638
  if (isTransition) {
638
639
  this.resetStyles(
639
- screenWidth > this.breakpointL ? 'desktop' : 'mobile',
640
+ screenWidth > this.breakpointDesktop ? 'desktop' : 'mobile',
640
641
  );
641
642
  }
642
643
  if (this.prevScreenWidth >= 1368 && screenWidth >= 1140) {
@@ -709,15 +710,14 @@ export class MegaMenu {
709
710
  }
710
711
  if (infoPanel && this.isLarge) {
711
712
  heights.push(infoPanelHeight);
712
- } else if (infoPanel && this.isDesktop) {
713
- itemsHeight = infoPanelHeight;
714
- subItemsHeight = infoPanelHeight;
715
- featuredHeight = infoPanelHeight;
716
- featuredFirstHeight = infoPanelHeight;
717
713
  }
718
714
 
719
715
  if (mainPanel) {
720
716
  mainPanel.style.height = '';
717
+ const seeAll = queryOne('.ecl-mega-menu__see-all', mainPanel);
718
+ if (seeAll) {
719
+ seeAll.style.top = 0;
720
+ }
721
721
  const mainTop = mainPanel.getBoundingClientRect().top;
722
722
  const list = queryOne('.ecl-mega-menu__sublist', mainPanel);
723
723
  if (!list) {
@@ -737,12 +737,23 @@ export class MegaMenu {
737
737
  }
738
738
  } else {
739
739
  const items = list.children;
740
- if (items.length > 0) {
741
- Array.from(items).forEach((item) => {
742
- itemsHeight += item.getBoundingClientRect().height;
743
- });
744
- heights.push(itemsHeight);
740
+ if (
741
+ !list
742
+ .closest('.ecl-mega-menu__item')
743
+ .classList.contains('ecl-mega-menu__item--one-level-only')
744
+ ) {
745
+ if (items.length > 0) {
746
+ Array.from(items).forEach((item) => {
747
+ itemsHeight += item.getBoundingClientRect().height;
748
+ });
749
+ }
750
+ } else {
751
+ if (items.length > 0) {
752
+ itemsHeight = list.offsetHeight;
753
+ }
745
754
  }
755
+
756
+ heights.push(itemsHeight);
746
757
  }
747
758
  featuredPanelFirst = queryOne(
748
759
  ':scope > .ecl-mega-menu__featured',
@@ -753,6 +764,7 @@ export class MegaMenu {
753
764
  Array.from(featuredPanelFirst.firstElementChild.children).forEach(
754
765
  (child) => {
755
766
  const elStyle = window.getComputedStyle(child);
767
+
756
768
  const marginHeight =
757
769
  parseFloat(elStyle.marginTop) +
758
770
  parseFloat(elStyle.marginBottom);
@@ -795,62 +807,64 @@ export class MegaMenu {
795
807
 
796
808
  const maxHeight = Math.max(...heights);
797
809
  const containerBounding = this.inner.getBoundingClientRect();
798
- const containerBottom = containerBounding.bottom;
810
+ let containerBottom = containerBounding.bottom;
811
+ if (mainPanel && infoPanel && this.isDesktop && !this.isLarge) {
812
+ containerBottom += infoPanelHeight;
813
+ }
814
+
815
+ const availableHeight = window.innerHeight - containerBottom;
799
816
  // By requirements, limit the height to the 70% of the available space.
800
- const availableHeight = (window.innerHeight - containerBottom) * 0.7;
801
- const minHeight =
802
- parseFloat(
803
- window.getComputedStyle(queryOne('.ecl-mega-menu__wrapper'))
804
- .minHeight,
805
- ) || 0;
817
+ const allowedHeight = availableHeight * 0.7;
818
+ const wrapper = queryOne('.ecl-mega-menu__wrapper', menuItem);
819
+ const wrapperTop =
820
+ parseFloat(getComputedStyle(wrapper).paddingTop) || 0;
806
821
 
807
822
  if (maxHeight > availableHeight) {
808
- height = availableHeight;
823
+ height = availableHeight - wrapperTop;
809
824
  } else {
810
- height = maxHeight;
811
- }
812
-
813
- if (height < minHeight) {
814
- height = minHeight;
825
+ height = maxHeight > allowedHeight ? allowedHeight : maxHeight;
815
826
  }
816
827
 
817
- const wrapper = queryOne('.ecl-mega-menu__wrapper', menuItem);
818
828
  if (wrapper) {
819
- wrapper.style.height = `${height}px`;
829
+ wrapper.style.height =
830
+ infoPanel && !this.isLarge
831
+ ? `${infoPanelHeight + height}px`
832
+ : `${height}px`;
820
833
  }
821
834
 
822
- if (mainPanel && this.isLarge) {
835
+ if (mainPanel) {
823
836
  mainPanel.style.height = `${height}px`;
824
- } else if (mainPanel && infoPanel && this.isDesktop) {
825
- mainPanel.style.height = `${height - infoPanelHeight}px`;
837
+ const seeAll = queryOne('.ecl-mega-menu__see-all', mainPanel);
838
+ const firstOnly = mainPanel
839
+ .closest('li')
840
+ .classList.contains('ecl-mega-menu__item--one-level-only');
841
+ if (seeAll && firstOnly) {
842
+ const remaining =
843
+ mainPanel.offsetHeight - (seeAll.offsetTop + seeAll.offsetHeight);
844
+ if (remaining > 0) {
845
+ seeAll.style.top = `${remaining}px`;
846
+ }
847
+ }
826
848
  }
827
849
  if (infoPanel && this.isLarge) {
828
850
  infoPanel.style.height = `${height}px`;
829
851
  }
830
- if (secondPanel && this.isLarge) {
852
+ if (secondPanel) {
831
853
  secondPanel.style.height = `${height}px`;
832
- } else if (secondPanel && this.isDesktop) {
833
- secondPanel.style.height = `${height - infoPanelHeight}px`;
854
+ secondPanel.style.opacity = 1;
834
855
  }
835
- if (featuredPanelFirst && this.isLarge) {
856
+ if (featuredPanelFirst) {
836
857
  featuredPanelFirst.style.height = `${height}px`;
837
- } else if (featuredPanelFirst && this.isDesktop) {
838
- featuredPanelFirst.style.height = `${height - infoPanelHeight}px`;
839
858
  }
840
- if (featuredPanel && this.isLarge) {
859
+ if (featuredPanel) {
841
860
  featuredPanel.style.height = `${height}px`;
842
- } else if (featuredPanel && this.isDesktop) {
843
- featuredPanel.style.height = `${height - infoPanelHeight}px`;
844
861
  }
845
- }
846
- if (mainPanel && this.isDesktop) {
847
- mainPanel.style.opacity = 1;
848
- }
849
- if (infoPanel && this.isDesktop) {
850
- infoPanel.style.opacity = 1;
851
- }
852
- if (secondPanel && this.isDesktop) {
853
- secondPanel.style.opacity = 1;
862
+ if (mainPanel) {
863
+ mainPanel.style.opacity = 1;
864
+ }
865
+ if (infoPanel) {
866
+ infoPanel.style.opacity = 1;
867
+ }
854
868
  }
855
869
  }, 100);
856
870
  }
package/mega-menu.scss CHANGED
@@ -12,6 +12,7 @@
12
12
  $theme: null !default;
13
13
  $mega-menu: null !default;
14
14
 
15
+ /* stylelint-disable scss/dollar-variable-no-missing-interpolation */
15
16
  :root {
16
17
  --ecl-mega-menu-item-promotional-bg: #{map.get(
17
18
  $mega-menu,
@@ -49,6 +50,7 @@ $mega-menu: null !default;
49
50
  'promotional-item-focus-text-color'
50
51
  )};
51
52
  }
53
+ /* stylelint-enable scss/dollar-variable-no-missing-interpolation */
52
54
 
53
55
  @mixin with-scrollbar {
54
56
  overflow-y: auto;
@@ -1116,7 +1118,6 @@ $mega-menu: null !default;
1116
1118
  ) {
1117
1119
  .ecl-mega-menu__wrapper {
1118
1120
  padding-top: var(--s-m);
1119
- min-height: 200px !important;
1120
1121
 
1121
1122
  &::before {
1122
1123
  background: var(--cm-border-neutral, '#e3e3e3');
@@ -1633,6 +1634,27 @@ $mega-menu: null !default;
1633
1634
  width: 96%;
1634
1635
  margin-inline-start: 2%;
1635
1636
  }
1637
+
1638
+ .ecl-mega-menu__item--one-level-only {
1639
+ .ecl-mega-menu__mega {
1640
+ width: calc(100% - var(--s-xl));
1641
+
1642
+ &.ecl-mega-menu__mega--has-featured {
1643
+ width: calc(100% - 17.785rem - var(--s-xl));
1644
+ }
1645
+
1646
+ .ecl-mega-menu__sublist {
1647
+ column-count: 3;
1648
+ column-gap: var(--s-2xl);
1649
+ column-rule: 1px solid var(--cm-border-low);
1650
+ display: block;
1651
+ }
1652
+
1653
+ > .ecl-mega-menu__featured {
1654
+ margin-inline-start: 0 !important;
1655
+ }
1656
+ }
1657
+ }
1636
1658
  }
1637
1659
  }
1638
1660
 
@@ -1666,8 +1688,60 @@ $mega-menu: null !default;
1666
1688
  .ecl-mega-menu__mega {
1667
1689
  left: 22rem;
1668
1690
  width: 20.93rem;
1691
+
1692
+ &.ecl-mega-menu__mega--no-info {
1693
+ left: 0;
1694
+ width: 39.805rem;
1695
+ }
1696
+ }
1697
+ }
1698
+ }
1699
+
1700
+ // First panel one level only
1701
+ .ecl-mega-menu__item.ecl-mega-menu__item--expanded.ecl-mega-menu__item--one-level-only
1702
+ > .ecl-mega-menu__wrapper
1703
+ > .ecl-container {
1704
+ > .ecl-mega-menu__mega {
1705
+ width: calc(100% - 22rem);
1706
+
1707
+ .ecl-mega-menu__sublist {
1708
+ column-count: 3;
1709
+ column-gap: var(--s-2xl);
1710
+ column-rule: 1px solid var(--cm-border-low);
1711
+ display: block;
1712
+ }
1713
+
1714
+ // Without info
1715
+ &.ecl-mega-menu__mega--no-info {
1716
+ width: 100%;
1717
+
1718
+ .ecl-mega-menu__sublist {
1719
+ column-count: 4;
1720
+ }
1721
+ }
1722
+
1723
+ // with featued panel
1724
+ &.ecl-mega-menu__mega--has-featured {
1725
+ width: calc(100% - 22rem - 18.875rem - calc(var(--s-3xl)));
1726
+
1727
+ .ecl-mega-menu__sublist {
1728
+ column-count: 2;
1729
+ }
1730
+
1731
+ // With featured & without info
1732
+ &.ecl-mega-menu__mega--no-info {
1733
+ width: calc(100% - 18.875rem - calc(var(--s-3xl)));
1734
+
1735
+ .ecl-mega-menu__sublist {
1736
+ column-count: 3;
1737
+ }
1738
+ }
1669
1739
  }
1670
1740
  }
1741
+
1742
+ .ecl-mega-menu__featured {
1743
+ margin-inline-start: 0 !important;
1744
+ }
1671
1745
  }
1672
1746
 
1673
1747
  &.ecl-mega-menu--rtl
@@ -1676,6 +1750,10 @@ $mega-menu: null !default;
1676
1750
  > .ecl-container
1677
1751
  > .ecl-mega-menu__mega {
1678
1752
  right: 20.93rem;
1753
+
1754
+ &.ecl-mega-menu__mega--no-info {
1755
+ right: 0;
1756
+ }
1679
1757
  }
1680
1758
  }
1681
1759
  }
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.21",
5
+ "version": "5.0.0-alpha.22.1",
6
6
  "description": "ECL Mega Menu",
7
7
  "publishConfig": {
8
8
  "access": "public"
@@ -11,13 +11,13 @@
11
11
  "module": "mega-menu.js",
12
12
  "style": "mega-menu.scss",
13
13
  "dependencies": {
14
- "@ecl/button": "5.0.0-alpha.21",
15
- "@ecl/dom-utils": "5.0.0-alpha.21",
16
- "@ecl/event-manager": "5.0.0-alpha.21",
17
- "@ecl/link": "5.0.0-alpha.21",
18
- "@ecl/picture": "5.0.0-alpha.21",
19
- "bowser": "2.12.1",
20
- "focus-trap": "7.6.5"
14
+ "@ecl/button": "5.0.0-alpha.22.1",
15
+ "@ecl/dom-utils": "5.0.0-alpha.22.1",
16
+ "@ecl/event-manager": "5.0.0-alpha.22.1",
17
+ "@ecl/link": "5.0.0-alpha.22.1",
18
+ "@ecl/picture": "5.0.0-alpha.22.1",
19
+ "bowser": "2.13.1",
20
+ "focus-trap": "7.6.6"
21
21
  },
22
22
  "repository": {
23
23
  "type": "git",
@@ -33,5 +33,5 @@
33
33
  "design-system",
34
34
  "twig"
35
35
  ],
36
- "gitHead": "e3828f07421db8fa2a610b445bc178ff26903c95"
36
+ "gitHead": "014bab7282bbab90d4f7fd268d891fdc975d0e2f"
37
37
  }