@mgdis/mg-components 5.5.0 → 5.6.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.
Files changed (142) hide show
  1. package/dist/cjs/{index-c3450336.js → index-4dcc1812.js} +11 -1
  2. package/dist/cjs/loader.cjs.js +3 -3
  3. package/dist/cjs/mg-badge_30.cjs.entry.js +742 -244
  4. package/dist/cjs/mg-components.cjs.js +3 -3
  5. package/dist/collection/collection-manifest.json +4 -4
  6. package/dist/collection/components/atoms/mg-badge/mg-badge.conf.js +1 -1
  7. package/dist/collection/components/atoms/mg-badge/mg-badge.css +13 -0
  8. package/dist/collection/components/atoms/mg-badge/mg-badge.js +3 -3
  9. package/dist/collection/components/atoms/mg-button/mg-button.css +2 -1
  10. package/dist/collection/components/atoms/mg-card/mg-card.css +13 -6
  11. package/dist/collection/components/atoms/mg-icon/mg-icon.conf.js +13 -3
  12. package/dist/collection/components/atoms/mg-tag/mg-tag.css +6 -6
  13. package/dist/collection/components/atoms/mg-tag/mg-tag.js +3 -3
  14. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.css +2 -0
  15. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.js +3 -3
  16. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.css +3 -3
  17. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +4 -1
  18. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.css +3 -3
  19. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.css +3 -3
  20. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.css +3 -3
  21. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +7 -3
  22. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.css +3 -3
  23. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.css +3 -3
  24. package/dist/collection/components/molecules/menu/mg-menu/doc/mg-menu.stories.js +43 -11
  25. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.conf.js +17 -0
  26. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.css +27 -0
  27. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.js +141 -18
  28. package/dist/collection/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.js +5 -10
  29. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.conf.js +0 -4
  30. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.css +47 -21
  31. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.js +118 -70
  32. package/dist/collection/components/molecules/mg-illustrated-message/mg-illustrated-message.js +4 -3
  33. package/dist/collection/components/molecules/mg-message/mg-message.css +7 -0
  34. package/dist/collection/components/molecules/mg-message/mg-message.js +53 -12
  35. package/dist/collection/components/molecules/mg-modal/mg-modal.css +8 -1
  36. package/dist/collection/components/molecules/mg-panel/mg-panel.css +7 -0
  37. package/dist/collection/components/molecules/mg-popover/mg-popover.css +72 -14
  38. package/dist/collection/components/molecules/mg-popover/mg-popover.js +48 -4
  39. package/dist/collection/components/molecules/mg-skip-links/doc/mg-skip-links.stories.js +1 -1
  40. package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.js +32 -1
  41. package/dist/collection/components/molecules/mg-tabs/doc/mg-tabs.stories.js +5 -3
  42. package/dist/collection/components/molecules/mg-tabs/mg-tabs.css +11 -7
  43. package/dist/collection/components/molecules/mg-tabs/mg-tabs.js +101 -54
  44. package/dist/collection/locales/en/messages.json +4 -0
  45. package/dist/collection/locales/fr/messages.json +4 -0
  46. package/dist/collection/locales/index.js +2 -25
  47. package/dist/collection/styles/a11y.scss +32 -0
  48. package/dist/collection/styles/components.scss +3 -0
  49. package/dist/collection/styles/fonts.scss +21 -0
  50. package/dist/collection/styles/form.scss +3 -0
  51. package/dist/collection/styles/global.scss +87 -0
  52. package/dist/collection/styles/layout.scss +29 -0
  53. package/dist/collection/styles/main.scss +23 -0
  54. package/dist/collection/styles/navigation-button.scss +76 -0
  55. package/dist/collection/styles/reset-mg-card-slotted-variables.scss +9 -0
  56. package/dist/collection/styles/typography.scss +75 -0
  57. package/dist/collection/styles/utilities.scss +21 -0
  58. package/dist/collection/utils/behaviors.utils.js +169 -0
  59. package/dist/collection/utils/components.utils.js +50 -0
  60. package/dist/collection/utils/locale.utils.js +22 -0
  61. package/dist/collection/utils/unit.test.utils.js +37 -32
  62. package/dist/collection/variables.css +9 -9
  63. package/dist/components/components.utils.js +51 -1
  64. package/dist/components/index2.js +65 -18
  65. package/dist/components/mg-badge2.js +4 -4
  66. package/dist/components/mg-button2.js +1 -1
  67. package/dist/components/mg-card2.js +1 -1
  68. package/dist/components/mg-icon2.js +13 -3
  69. package/dist/components/mg-illustrated-message.js +4 -3
  70. package/dist/components/mg-input-date.js +6 -4
  71. package/dist/components/mg-input-numeric.js +2 -3
  72. package/dist/components/mg-input-password.js +1 -1
  73. package/dist/components/mg-input-select2.js +8 -4
  74. package/dist/components/mg-input-text2.js +1 -1
  75. package/dist/components/mg-input-textarea.js +1 -1
  76. package/dist/components/mg-menu-item.js +1 -253
  77. package/dist/components/mg-menu-item2.js +517 -0
  78. package/dist/components/mg-menu.js +138 -21
  79. package/dist/components/mg-message.js +54 -13
  80. package/dist/components/mg-modal.js +1 -1
  81. package/dist/components/mg-panel.js +1 -1
  82. package/dist/components/mg-popover.js +1 -190
  83. package/dist/components/mg-popover2.js +212 -0
  84. package/dist/components/mg-skip-links.js +16 -2
  85. package/dist/components/mg-tabs.js +100 -52
  86. package/dist/components/mg-tag.js +4 -4
  87. package/dist/components/mg-tooltip2.js +4 -4
  88. package/dist/esm/{index-78edde1d.js → index-dc9a2348.js} +11 -1
  89. package/dist/esm/loader.js +3 -3
  90. package/dist/esm/mg-badge_30.entry.js +742 -244
  91. package/dist/esm/mg-components.js +3 -3
  92. package/dist/esm/polyfills/css-shim.js +1 -1
  93. package/dist/mg-components/locales/en/messages.json +4 -0
  94. package/dist/mg-components/locales/fr/messages.json +4 -0
  95. package/dist/mg-components/mg-components.css +1 -1
  96. package/dist/mg-components/mg-components.esm.js +1 -1
  97. package/dist/mg-components/{p-125c54ca.js → p-182bd802.js} +2 -2
  98. package/dist/mg-components/p-f7da9dd2.entry.js +1 -0
  99. package/dist/mg-components/styles/a11y.scss +32 -0
  100. package/dist/mg-components/styles/components.scss +3 -0
  101. package/dist/mg-components/styles/fonts.scss +21 -0
  102. package/dist/mg-components/styles/form.scss +3 -0
  103. package/dist/mg-components/styles/global.scss +87 -0
  104. package/dist/mg-components/styles/layout.scss +29 -0
  105. package/dist/mg-components/styles/main.scss +23 -0
  106. package/dist/mg-components/styles/navigation-button.scss +76 -0
  107. package/dist/mg-components/styles/reset-mg-card-slotted-variables.scss +9 -0
  108. package/dist/mg-components/styles/typography.scss +75 -0
  109. package/dist/mg-components/styles/utilities.scss +21 -0
  110. package/dist/mg-components/variables.css +9 -9
  111. package/dist/types/components/atoms/mg-badge/mg-badge.conf.d.ts +2 -2
  112. package/dist/types/components/atoms/mg-button/mg-button.conf.d.ts +2 -2
  113. package/dist/types/components/atoms/mg-icon/mg-icon.conf.d.ts +2 -2
  114. package/dist/types/components/atoms/mg-tag/mg-tag.conf.d.ts +1 -1
  115. package/dist/types/components/molecules/inputs/MgInput.conf.d.ts +2 -2
  116. package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.conf.d.ts +2 -2
  117. package/dist/types/components/molecules/inputs/mg-input-radio/mg-input-radio.conf.d.ts +1 -1
  118. package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.conf.d.ts +2 -2
  119. package/dist/types/components/molecules/inputs/mg-input-toggle/mg-input-toggle.conf.d.ts +1 -1
  120. package/dist/types/components/molecules/menu/mg-menu/doc/mg-menu.stories.d.ts +5 -0
  121. package/dist/types/components/molecules/menu/mg-menu/mg-menu.conf.d.ts +37 -0
  122. package/dist/types/components/molecules/menu/mg-menu/mg-menu.d.ts +51 -3
  123. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.conf.d.ts +0 -8
  124. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.d.ts +55 -15
  125. package/dist/types/components/molecules/mg-message/mg-message.d.ts +21 -4
  126. package/dist/types/components/molecules/mg-popover/mg-popover.d.ts +12 -0
  127. package/dist/types/components/molecules/mg-skip-links/mg-skip-links.conf.d.ts +1 -1
  128. package/dist/types/components/molecules/mg-skip-links/mg-skip-links.d.ts +15 -0
  129. package/dist/types/components/molecules/mg-tabs/mg-tabs.conf.d.ts +5 -3
  130. package/dist/types/components/molecules/mg-tabs/mg-tabs.d.ts +22 -12
  131. package/dist/types/components.d.ts +44 -12
  132. package/dist/types/locales/index.d.ts +10 -9
  133. package/dist/types/stencil-public-runtime.d.ts +39 -3
  134. package/dist/types/utils/behaviors.utils.d.ts +83 -0
  135. package/dist/types/utils/components.utils.d.ts +14 -0
  136. package/dist/types/utils/locale.utils.d.ts +13 -0
  137. package/dist/types/utils/unit.test.utils.d.ts +50 -14
  138. package/package.json +26 -26
  139. package/readme.md +22 -13
  140. package/dist/components/locale.utils.js +0 -40
  141. package/dist/components/mg-menu.conf.js +0 -10
  142. package/dist/mg-components/p-4961c96c.entry.js +0 -1
@@ -1,19 +1,27 @@
1
1
  import { h } from '@stencil/core';
2
2
  import { filterArgs } from '../../../../../../.storybook/utils';
3
- import { Status } from '../../mg-menu-item/mg-menu-item.conf';
4
3
  import { Direction } from '../mg-menu.conf';
4
+ import { Status } from '../../mg-menu-item/mg-menu-item.conf';
5
5
  export default {
6
6
  component: 'mg-menu',
7
- title: 'Beta/menus/mg-menu',
7
+ title: 'Beta/Menus/mg-menu',
8
8
  argTypes: {
9
9
  direction: {
10
10
  options: [undefined, Direction.HORIZONTAL, Direction.VERTICAL],
11
11
  control: { type: 'select' },
12
12
  },
13
+ moreitem: {
14
+ control: { type: 'object' },
15
+ },
13
16
  },
14
17
  };
15
- const getItemArgs = ({ size, label, direction, status, metadata, icon, badge, content, submenu }) => ({
16
- size: size !== undefined ? size : direction === Direction.VERTICAL ? 'medium' : undefined,
18
+ /**
19
+ * Format item args from given params
20
+ *
21
+ * @param {ItemArgType} itemArgs - item arguments
22
+ * @returns {ItemFormatedArgs} items formated args object
23
+ */
24
+ const getItemArgs = ({ label, status, metadata, icon, badge, content, submenu }) => ({
17
25
  status,
18
26
  slot: {
19
27
  label,
@@ -24,9 +32,32 @@ const getItemArgs = ({ size, label, direction, status, metadata, icon, badge, co
24
32
  submenu,
25
33
  },
26
34
  });
27
- const getMenuArgs = (direction, level = 0, isSubmenu = false) => ({
35
+ /**
36
+ * Render mg-menu-item
37
+ *
38
+ * @param {ItemFormatedArgs} args mg-menu-item args
39
+ * @returns {HTMLElement} rendered mg-menu-item
40
+ */
41
+ const menuItem = (args) => {
42
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
43
+ return (h("mg-menu-item", Object.assign({}, filterArgs(args)), ((_a = args.slot) === null || _a === void 0 ? void 0 : _a.label) && h("span", { slot: "label" }, (_b = args.slot) === null || _b === void 0 ? void 0 : _b.label), ((_c = args.slot) === null || _c === void 0 ? void 0 : _c.metadata) && h("span", { slot: "metadata" }, (_d = args.slot) === null || _d === void 0 ? void 0 : _d.metadata), ((_e = args.slot) === null || _e === void 0 ? void 0 : _e.icon) && h("mg-icon", { slot: "image", icon: "user" }), ((_f = args.slot) === null || _f === void 0 ? void 0 : _f.badge) && (h("mg-badge", { slot: "information", label: "information", value: "1" }, (_g = args.slot) === null || _g === void 0 ? void 0 : _g.icon)), ((_h = args.slot) === null || _h === void 0 ? void 0 : _h.content) && (h("div", null, h("h3", null, "Demo title"), h("p", null, "some content"))), ((_j = args.slot) === null || _j === void 0 ? void 0 : _j.submenu) && menu(getMenuArgs(Direction.VERTICAL, ((_k = args.slot) === null || _k === void 0 ? void 0 : _k.submenu) - 1, 'medium'))));
44
+ };
45
+ /***********
46
+ * mg-menu *
47
+ **********/
48
+ /**
49
+ * Format menu args from given params
50
+ *
51
+ * @param {Direction} direction menu direction
52
+ * @param {number} level menu level. Default: 0.
53
+ * @param {MenuSizeType} size menu size. Default: 'regular'
54
+ * @returns {MenuFormatedArgs} menu formated args object
55
+ */
56
+ const getMenuArgs = (direction, level = 0, size = 'regular') => ({
28
57
  label: 'Batman menu',
29
58
  direction,
59
+ size,
60
+ moreitem: undefined,
30
61
  slot: {
31
62
  items: [
32
63
  getItemArgs({
@@ -58,16 +89,17 @@ const getMenuArgs = (direction, level = 0, isSubmenu = false) => ({
58
89
  icon: true,
59
90
  metadata: 'my metadata',
60
91
  content: true,
61
- size: !isSubmenu && direction === Direction.HORIZONTAL ? 'regular' : undefined,
62
92
  }),
63
93
  ],
64
94
  },
65
95
  });
66
- const menu = args => h("mg-menu", Object.assign({}, filterArgs(args, { direction: Direction.HORIZONTAL })), args.slot.items.map(item => menuItem(item)));
67
- const menuItem = args => {
68
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
69
- return (h("mg-menu-item", Object.assign({}, filterArgs(args)), ((_a = args.slot) === null || _a === void 0 ? void 0 : _a.label) && h("span", { slot: "label" }, (_b = args.slot) === null || _b === void 0 ? void 0 : _b.label), ((_c = args.slot) === null || _c === void 0 ? void 0 : _c.metadata) && h("span", { slot: "metadata" }, (_d = args.slot) === null || _d === void 0 ? void 0 : _d.metadata), ((_e = args.slot) === null || _e === void 0 ? void 0 : _e.icon) && h("mg-icon", { slot: "illustration", icon: "user" }), ((_f = args.slot) === null || _f === void 0 ? void 0 : _f.badge) && (h("mg-badge", { slot: "information", label: "information", value: "1" }, (_g = args.slot) === null || _g === void 0 ? void 0 : _g.icon)), ((_h = args.slot) === null || _h === void 0 ? void 0 : _h.content) && (h("div", null, h("h3", null, "Demo title"), h("p", null, "some content"))), ((_j = args.slot) === null || _j === void 0 ? void 0 : _j.submenu) && menu(getMenuArgs(Direction.VERTICAL, ((_k = args.slot) === null || _k === void 0 ? void 0 : _k.submenu) - 1, true))));
70
- };
96
+ /**
97
+ * Render mg-menu
98
+ *
99
+ * @param {MenuFormatedArgs} args mg-menu args
100
+ * @returns {HTMLElement} rendered mg-menu
101
+ */
102
+ const menu = (args) => (h("mg-menu", Object.assign({}, filterArgs(args, { direction: Direction.HORIZONTAL })), args.slot.items.map(item => menuItem(item))));
71
103
  /**
72
104
  * Template
73
105
  *
@@ -6,3 +6,20 @@ export var Direction;
6
6
  Direction["VERTICAL"] = "vertical";
7
7
  Direction["HORIZONTAL"] = "horizontal";
8
8
  })(Direction || (Direction = {}));
9
+ /**
10
+ * More item type guard
11
+ *
12
+ * @param {unknown} element element to control
13
+ * @returns {boolean} truthy if element is more-item
14
+ */
15
+ export const isMoreItem = (element) => {
16
+ var _a, _b, _c;
17
+ const item = element;
18
+ return (item === undefined ||
19
+ (typeof item === 'object' &&
20
+ (typeof item.size === 'string' || typeof ((_a = item.mgIcon) === null || _a === void 0 ? void 0 : _a.icon) === 'string' || typeof ((_b = item.slotLabel) === null || _b === void 0 ? void 0 : _b.label) === 'string' || typeof ((_c = item.slotLabel) === null || _c === void 0 ? void 0 : _c.display) === 'boolean')));
21
+ };
22
+ /**
23
+ * List of all possibles sizes
24
+ */
25
+ export const sizes = ['regular', 'medium', 'large'];
@@ -1,3 +1,30 @@
1
+ /**
2
+ * A11Y
3
+ */
4
+ .sr-only {
5
+ border: 0 !important;
6
+ clip: rect(1px, 1px, 1px, 1px) !important;
7
+ -webkit-clip-path: inset(50%) !important;
8
+ clip-path: inset(50%) !important;
9
+ height: 1px !important;
10
+ margin: -1px !important;
11
+ overflow: hidden !important;
12
+ padding: 0 !important;
13
+ position: absolute !important;
14
+ width: 1px !important;
15
+ white-space: nowrap !important;
16
+ }
17
+
18
+ *:focus:not(:focus-visible) {
19
+ outline: none;
20
+ }
21
+
22
+ @media (prefers-reduced-motion) {
23
+ .mg-a11y-animation {
24
+ animation: none !important;
25
+ transition: none !important;
26
+ }
27
+ }
1
28
  :host {
2
29
  display: flex;
3
30
  background-color: hsl(var(--mg-menu-background-color-hsl, var(--color-light)));
@@ -1,16 +1,19 @@
1
1
  import { h, Host } from '@stencil/core';
2
- import { Direction } from './mg-menu.conf';
2
+ import { OverflowBehavior, OverflowBehaviorElements } from '../../../../utils/behaviors.utils';
3
+ import { Direction, isMoreItem, sizes } from './mg-menu.conf';
4
+ import { initLocales } from '../../../../locales';
3
5
  export class MgMenu {
4
6
  constructor() {
5
7
  /************
6
8
  * Internal *
7
9
  ************/
8
10
  this.name = 'mg-menu';
11
+ this.menuItems = [];
9
12
  this.focusedMenuItem = 0;
10
13
  /**
11
14
  * Close matching menu-item
12
15
  *
13
- * @param {HTMLMgMenuItemElement} item menu-item to close
16
+ * @param {HTMLElement} item menu-item to close
14
17
  * @param {boolean} condition addionnal condition
15
18
  * @returns {void}
16
19
  */
@@ -19,12 +22,15 @@ export class MgMenu {
19
22
  item.expanded = false;
20
23
  }
21
24
  };
25
+ /*************
26
+ * Methods *
27
+ *************/
22
28
  /**
23
29
  * Store menu-items on component init and add listeners
30
+ *
31
+ * @returns {void}
24
32
  */
25
- this.initMenuItems = () => {
26
- // store all menu-items
27
- this.menuItems = Array.from(this.element.children).filter(child => child.nodeName === 'MG-MENU-ITEM');
33
+ this.initMenuItemsListeners = () => {
28
34
  // add listeners on menu item and edit index
29
35
  this.menuItems.forEach((item, menuItemIndex) => {
30
36
  ['click', 'focus'].forEach(trigger => {
@@ -38,9 +44,47 @@ export class MgMenu {
38
44
  });
39
45
  });
40
46
  };
47
+ /**
48
+ * render mg-menu-more
49
+ *
50
+ * @returns {HTMLElement} formated mg-menu-item element
51
+ */
52
+ this.renderMgMenuMore = () => {
53
+ const moreElement = this.element.shadowRoot.querySelector(`[${OverflowBehaviorElements.MORE}]`);
54
+ this.menuItems.forEach((child) => {
55
+ const proxy = child.cloneNode(true);
56
+ moreElement.querySelector('mg-menu').appendChild(proxy);
57
+ });
58
+ const allMenuItem = Array.from(this.element.querySelectorAll('mg-menu-item:not([data-overflow-more])'));
59
+ Array.from(moreElement.querySelectorAll('mg-menu-item:not([data-overflow-more])')).forEach((proxy, index) => {
60
+ // manage click on proxy to mirror it on initial element
61
+ proxy.addEventListener('click', () => {
62
+ (allMenuItem[index].shadowRoot.querySelector('a') || allMenuItem[index].shadowRoot.querySelector('button')).dispatchEvent(new MouseEvent('click', { bubbles: true }));
63
+ });
64
+ // manage status change miror in proxy
65
+ allMenuItem[index].addEventListener('status-change', (event) => {
66
+ proxy.setAttribute('status', event.detail);
67
+ this.overflowBehavior.updateActiveStatus();
68
+ });
69
+ });
70
+ this.element.appendChild(moreElement);
71
+ return this.element.querySelector(`[${OverflowBehaviorElements.MORE}]`);
72
+ };
73
+ /**
74
+ * Render mg-menu-item more element for overflow behavior
75
+ *
76
+ * @returns {HTMLElement} rendered mg-menu-item more element
77
+ */
78
+ this.renderMgMenuItemMore = () => {
79
+ var _a, _b, _c, _d, _e, _f, _g;
80
+ return (h("mg-menu-item", { "data-overflow-more": true }, h("mg-icon", { icon: ((_b = (_a = this.moreitem) === null || _a === void 0 ? void 0 : _a.mgIcon) === null || _b === void 0 ? void 0 : _b.icon) || 'ellipsis-vertical', slot: "image" }), h("span", { class: { 'sr-only': !((_d = (_c = this.moreitem) === null || _c === void 0 ? void 0 : _c.slotLabel) === null || _d === void 0 ? void 0 : _d.display) }, slot: "label" }, ((_f = (_e = this.moreitem) === null || _e === void 0 ? void 0 : _e.slotLabel) === null || _f === void 0 ? void 0 : _f.label) || this.messages.moreLabel), h("mg-menu", { direction: Direction.VERTICAL, label: this.messages.moreLabel, size: (_g = this.moreitem) === null || _g === void 0 ? void 0 : _g.size })));
81
+ };
41
82
  this.label = undefined;
42
83
  this.direction = Direction.HORIZONTAL;
84
+ this.moreitem = undefined;
85
+ this.size = 'regular';
43
86
  this.isChildMenu = undefined;
87
+ this.hasOverflow = false;
44
88
  }
45
89
  validateLabel(newValue) {
46
90
  if (newValue === undefined) {
@@ -52,6 +96,19 @@ export class MgMenu {
52
96
  throw new Error(`<${this.name}> prop "direction" must be one of : ${Direction.HORIZONTAL}, ${Direction.VERTICAL}.`);
53
97
  }
54
98
  }
99
+ validateMoreItem(newValue) {
100
+ if (newValue !== undefined && this.direction !== Direction.HORIZONTAL) {
101
+ throw new Error(`<${this.name}> prop "moreitem" must be paired with direction ${Direction.HORIZONTAL}.`);
102
+ }
103
+ else if (newValue !== undefined && !isMoreItem(newValue)) {
104
+ throw new Error(`<${this.name}> prop "moreitem" must match MoreItemType.`);
105
+ }
106
+ }
107
+ validateSize(newValue) {
108
+ if (!sizes.includes(newValue)) {
109
+ throw new Error(`<${this.name}> prop "size" must be one of : ${sizes.join(', ')}.`);
110
+ }
111
+ }
55
112
  /*************
56
113
  * Lifecycle *
57
114
  *************/
@@ -61,8 +118,12 @@ export class MgMenu {
61
118
  * @returns {void}
62
119
  */
63
120
  componentWillLoad() {
121
+ this.messages = initLocales(this.element).messages.plusMenu;
122
+ // validation
64
123
  this.validateDirection(this.direction);
65
124
  this.validateLabel(this.label);
125
+ this.validateMoreItem(this.moreitem);
126
+ this.validateSize(this.size);
66
127
  }
67
128
  /**
68
129
  * Check if component slots configuration
@@ -74,27 +135,39 @@ export class MgMenu {
74
135
  // return a promise to process action only in the FIRST render().
75
136
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
76
137
  return setTimeout(() => {
77
- this.initMenuItems();
138
+ // store all menu-items
139
+ this.menuItems = Array.from(this.element.children).filter(child => child.nodeName === 'MG-MENU-ITEM');
78
140
  this.isChildMenu = this.element.closest('mg-menu-item') !== null;
79
- // click outside management for child vertical menu
80
- if (!this.isChildMenu && this.direction === Direction.HORIZONTAL) {
81
- document.addEventListener('click', (event) => {
82
- if (event.target.closest('mg-menu') === null) {
83
- this.menuItems.forEach(item => {
84
- this.closeMenuItem(item, this.direction === Direction.HORIZONTAL);
85
- });
86
- }
87
- });
88
- }
141
+ this.hasOverflow = this.direction === Direction.HORIZONTAL && !this.isChildMenu;
142
+ if (this.hasOverflow && isMoreItem(this.moreitem))
143
+ this.overflowBehavior = new OverflowBehavior(this.element, this.renderMgMenuMore);
89
144
  }, 0);
90
145
  }
146
+ /**
147
+ * Check add listeners to childs
148
+ *
149
+ * @returns {void}
150
+ */
151
+ componentDidRender() {
152
+ // add menu items listeners
153
+ this.initMenuItemsListeners();
154
+ }
155
+ /**
156
+ * Disconnect overflow ResizeObserver
157
+ *
158
+ * @returns {void} run overflow resize obeserver disconnexion
159
+ */
160
+ disconnectedCallback() {
161
+ if (this.hasOverflow)
162
+ this.overflowBehavior.disconnect();
163
+ }
91
164
  /**
92
165
  * Render
93
166
  *
94
167
  * @returns {HTMLElement} HTML Element
95
168
  */
96
169
  render() {
97
- return (h(Host, { role: this.isChildMenu ? 'menu' : 'menubar', "aria-label": this.label }, h("slot", null)));
170
+ return (h(Host, { role: this.isChildMenu ? 'menu' : 'menubar', "aria-label": this.label }, h("slot", null), this.hasOverflow && isMoreItem(this.moreitem) && this.renderMgMenuItemMore()));
98
171
  }
99
172
  static get is() { return "mg-menu"; }
100
173
  static get encapsulation() { return "shadow"; }
@@ -149,12 +222,56 @@ export class MgMenu {
149
222
  "attribute": "direction",
150
223
  "reflect": true,
151
224
  "defaultValue": "Direction.HORIZONTAL"
225
+ },
226
+ "moreitem": {
227
+ "type": "unknown",
228
+ "mutable": false,
229
+ "complexType": {
230
+ "original": "MoreItemType",
231
+ "resolved": "{ mgIcon?: { icon: string; }; slotLabel?: { label?: string; display?: boolean; }; size?: \"regular\" | \"large\" | \"medium\"; }",
232
+ "references": {
233
+ "MoreItemType": {
234
+ "location": "import",
235
+ "path": "./mg-menu.conf"
236
+ }
237
+ }
238
+ },
239
+ "required": false,
240
+ "optional": false,
241
+ "docs": {
242
+ "tags": [],
243
+ "text": "Customize mg-menu \"more element\"\nUsed with direction: 'vertical' to manage overflow"
244
+ }
245
+ },
246
+ "size": {
247
+ "type": "string",
248
+ "mutable": false,
249
+ "complexType": {
250
+ "original": "MenuSizeType",
251
+ "resolved": "\"large\" | \"medium\" | \"regular\"",
252
+ "references": {
253
+ "MenuSizeType": {
254
+ "location": "import",
255
+ "path": "./mg-menu.conf"
256
+ }
257
+ }
258
+ },
259
+ "required": false,
260
+ "optional": false,
261
+ "docs": {
262
+ "tags": [],
263
+ "text": "Define mg-menu size\nDefault: 'regular'"
264
+ },
265
+ "attribute": "size",
266
+ "reflect": false,
267
+ "defaultValue": "'regular'"
152
268
  }
153
269
  };
154
270
  }
155
271
  static get states() {
156
272
  return {
157
- "isChildMenu": {}
273
+ "isChildMenu": {},
274
+ "hasOverflow": {}
158
275
  };
159
276
  }
160
277
  static get elementRef() { return "element"; }
@@ -165,6 +282,12 @@ export class MgMenu {
165
282
  }, {
166
283
  "propName": "direction",
167
284
  "methodName": "validateDirection"
285
+ }, {
286
+ "propName": "moreitem",
287
+ "methodName": "validateMoreItem"
288
+ }, {
289
+ "propName": "size",
290
+ "methodName": "validateSize"
168
291
  }];
169
292
  }
170
293
  }
@@ -3,7 +3,7 @@ import { filterArgs } from '../../../../../../.storybook/utils';
3
3
  import { Direction } from '../../mg-menu/mg-menu.conf';
4
4
  export default {
5
5
  component: 'mg-menu-item',
6
- title: 'Beta/menus/mg-menu-item',
6
+ title: 'Beta/Menus/mg-menu-item',
7
7
  };
8
8
  /**
9
9
  * Template
@@ -15,25 +15,20 @@ export default {
15
15
  const Template = (args) => h("mg-menu-item", Object.assign({}, filterArgs(args)), args.slot);
16
16
  export const MgMenuItem = Template.bind({});
17
17
  MgMenuItem.args = {
18
- identifier: 'identifier',
19
18
  slot: h("span", { slot: "label" }, "My label"),
20
19
  };
21
20
  export const MgMenuItemAsLink = Template.bind({});
22
- MgMenuItemAsLink.args = {
23
- identifier: 'identifier',
24
- href: './',
25
- slot: h("span", { slot: "label" }, "My label"),
26
- };
21
+ MgMenuItemAsLink.args = Object.assign({ href: './' }, MgMenuItem.args);
27
22
  export const MgMenuItemWhitIcon = Template.bind({});
28
- MgMenuItemWhitIcon.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [h("span", { slot: "label" }, "My label"), h("mg-icon", { icon: "user", slot: "illustration" })] });
23
+ MgMenuItemWhitIcon.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [h("span", { slot: "label" }, "My label"), h("mg-icon", { icon: "user", slot: "image" })] });
29
24
  export const MgMenuItemWhitBadge = Template.bind({});
30
25
  MgMenuItemWhitBadge.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [h("span", { slot: "label" }, "My label"), h("mg-badge", { value: "2", label: "hello", slot: "information" })] });
31
26
  export const MgMenuItemWhitBadgeAndIcon = Template.bind({});
32
- MgMenuItemWhitBadgeAndIcon.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [h("span", { slot: "label" }, "My label"), h("mg-badge", { value: "2", label: "hello", slot: "information" }), h("mg-icon", { icon: "user", slot: "illustration" })] });
27
+ MgMenuItemWhitBadgeAndIcon.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [h("span", { slot: "label" }, "My label"), h("mg-badge", { value: "2", label: "hello", slot: "information" }), h("mg-icon", { icon: "user", slot: "image" })] });
33
28
  export const MgMenuItemWhitMetadata = Template.bind({});
34
29
  MgMenuItemWhitMetadata.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [h("span", { slot: "label" }, "My label"), h("span", { slot: "metadata" }, "My metadata")] });
35
30
  export const MgMenuItemWhithSubmenu = Template.bind({});
36
31
  MgMenuItemWhithSubmenu.args = Object.assign(Object.assign({}, MgMenuItem.args), { slot: [
37
32
  h("span", { slot: "label" }, "My label"),
38
- h("mg-menu", { direction: Direction.VERTICAL, label: "submenu" }, h("mg-menu-item", null, h("span", { slot: "label" }, "Subitem 1")), h("mg-menu-item", null, h("mg-icon", { icon: "user", slot: "illustration" }), h("span", { slot: "label" }, "Subitem 2")), h("mg-menu-item", null, h("span", { slot: "label" }, "Subitem 3"), h("mg-icon", { icon: "user", slot: "illustration" }), h("mg-badge", { value: "2", label: "hello", slot: "information" }))),
33
+ h("mg-menu", { direction: Direction.VERTICAL, label: "submenu" }, h("mg-menu-item", null, h("span", { slot: "label" }, "Subitem 1")), h("mg-menu-item", null, h("mg-icon", { icon: "user", slot: "image" }), h("span", { slot: "label" }, "Subitem 2")), h("mg-menu-item", null, h("span", { slot: "label" }, "Subitem 3"), h("mg-icon", { icon: "user", slot: "image" }), h("mg-badge", { value: "2", label: "hello", slot: "information" }))),
39
34
  ] });
@@ -16,7 +16,3 @@ export var Status;
16
16
  Status["DISABLED"] = "disabled";
17
17
  Status["ACTIVE"] = "active";
18
18
  })(Status || (Status = {}));
19
- /**
20
- * List of all possibles sizes
21
- */
22
- export const sizes = ['regular', 'medium', 'large'];
@@ -28,6 +28,7 @@
28
28
  .mg-menu-item.mg-menu-item--size-regular .mg-menu-item__navigation-button,
29
29
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-regular {
30
30
  padding: 1rem 2rem;
31
+ height: calc(3.8rem);
31
32
  }
32
33
  .mg-menu-item.mg-menu-item--size-regular .mg-menu-item__navigation-button,
33
34
  .mg-menu-item.mg-menu-item--size-regular .mg-menu-item__navigation-button ::slotted([slot=label]),
@@ -35,7 +36,7 @@
35
36
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-regular,
36
37
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-regular ::slotted([slot=label]),
37
38
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-regular ::slotted([slot=metadata]) {
38
- font-size: 1.3rem;
39
+ font-size: var(--font-size);
39
40
  }
40
41
  .mg-menu-item.mg-menu-item--size-regular .mg-menu-item__navigation-button.mg-menu-item__navigation-button--horizontal,
41
42
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-regular.mg-menu-item__navigation-button--horizontal {
@@ -48,7 +49,8 @@
48
49
 
49
50
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button,
50
51
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium {
51
- padding: 1.5rem 3rem;
52
+ padding: 1rem 3rem;
53
+ height: calc(5.1rem);
52
54
  }
53
55
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button,
54
56
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button ::slotted([slot=label]),
@@ -56,11 +58,11 @@
56
58
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium,
57
59
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium ::slotted([slot=label]),
58
60
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium ::slotted([slot=metadata]) {
59
- font-size: 1.5rem;
61
+ font-size: calc(var(--font-size) + 0.2rem);
60
62
  }
61
63
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button.mg-menu-item__navigation-button--horizontal,
62
64
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium.mg-menu-item__navigation-button--horizontal {
63
- padding-bottom: calc(1.5rem - 0.3rem);
65
+ padding-bottom: calc(1rem - 0.3rem);
64
66
  }
65
67
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button.mg-menu-item__navigation-button--vertical,
66
68
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium.mg-menu-item__navigation-button--vertical {
@@ -69,7 +71,8 @@
69
71
 
70
72
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button,
71
73
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large {
72
- padding: 2.5rem 4rem;
74
+ padding: 1rem 4rem;
75
+ height: calc(7.1rem);
73
76
  }
74
77
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button,
75
78
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button ::slotted([slot=label]),
@@ -77,11 +80,11 @@
77
80
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large,
78
81
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large ::slotted([slot=label]),
79
82
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large ::slotted([slot=metadata]) {
80
- font-size: 1.5rem;
83
+ font-size: calc(var(--font-size) + 0.2rem);
81
84
  }
82
85
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button.mg-menu-item__navigation-button--horizontal,
83
86
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large.mg-menu-item__navigation-button--horizontal {
84
- padding-bottom: calc(2.5rem - 0.3rem);
87
+ padding-bottom: calc(1rem - 0.3rem);
85
88
  }
86
89
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button.mg-menu-item__navigation-button--vertical,
87
90
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large.mg-menu-item__navigation-button--vertical {
@@ -91,28 +94,30 @@
91
94
  .mg-menu-item__navigation-button {
92
95
  display: flex;
93
96
  align-items: center;
94
- column-gap: 1rem;
97
+ column-gap: var(--mg-menu-item-navigation-button-column-gap, 1rem);
95
98
  background-color: unset;
96
99
  border: none;
97
100
  font-family: var(--font-family);
98
101
  color: hsl(var(--mg-menu-item-color-hsl, var(--color-dark)));
99
102
  line-height: var(--line-height);
100
103
  text-decoration: none;
104
+ white-space: nowrap;
105
+ box-sizing: border-box;
101
106
  cursor: pointer;
102
107
  }
103
108
  .mg-menu-item__navigation-button:disabled, .mg-menu-item__navigation-button--disabled {
104
109
  cursor: default;
105
- opacity: 30%;
110
+ opacity: 0.3;
106
111
  }
107
112
  .mg-menu-item__navigation-button:focus-visible {
108
113
  z-index: 10;
109
114
  }
110
- .mg-menu-item__navigation-button:hover:not(.mg-menu-item__navigation-button--disabled), .mg-menu-item__navigation-button:focus:not(.mg-menu-item__navigation-button--disabled) {
111
- background-color: hsla(var(--mg-menu-item-focused-background-color-hsl), 10%);
115
+ .mg-menu-item__navigation-button:hover:not(.mg-menu-item__navigation-button--disabled), .mg-menu-item__navigation-button:focus-visible:not(.mg-menu-item__navigation-button--disabled) {
116
+ background-color: hsl(var(--mg-menu-item-focused-background-color-hsl), 0.1);
112
117
  }
113
118
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--active {
114
119
  color: hsl(var(--mg-menu-item-color-active-hsl));
115
- font-weight: 700;
120
+ font-weight: 600;
116
121
  }
117
122
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--active.mg-menu-item__navigation-button--horizontal {
118
123
  border-bottom-color: hsl(var(--mg-menu-item-border-color-active-hsl));
@@ -277,16 +282,16 @@
277
282
  :host {
278
283
  position: relative;
279
284
  display: flex;
280
- }
281
-
282
- :host([data-style-position-last]) .mg-menu-item__collapse-container {
283
- left: unset;
284
- right: 0;
285
+ --mg-popover-padding-vertical: 0;
286
+ --mg-popover-padding-horizontal: 0;
285
287
  }
286
288
 
287
289
  :host([data-style-direction-vertical]) {
288
290
  flex-direction: column;
289
291
  }
292
+ :host([data-style-direction-vertical]) .mg-menu-item__navigation-button {
293
+ width: 100%;
294
+ }
290
295
  :host([data-style-direction-vertical]) .mg-menu-item__collapse-container {
291
296
  left: unset;
292
297
  top: unset;
@@ -298,20 +303,29 @@
298
303
  }
299
304
 
300
305
  :host([data-style-direction-horizontal]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level {
301
- box-shadow: var(--box-shadow);
302
306
  background-color: hsl(var(--color-light));
303
307
  }
304
308
  :host([data-style-direction-horizontal]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level ::slotted(mg-menu) {
305
309
  padding: 1rem 0;
306
310
  }
307
311
 
312
+ :host([data-overflow-more]) {
313
+ --mg-menu-item-navigation-button-column-gap: 0;
314
+ }
315
+ :host([data-overflow-more]) .mg-menu-item__navigation-button-chevron {
316
+ display: none;
317
+ }
318
+ :host([data-overflow-more]) .mg-menu-item__navigation-button-text-content ::slotted([slot=information]) {
319
+ margin-left: 0;
320
+ }
321
+ :host([data-overflow-more]) ::slotted(mg-menu) {
322
+ --mg-menu-item-navigation-button-column-gap: 1rem;
323
+ }
324
+
308
325
  .mg-menu-item {
309
326
  max-width: var(--mg-menu-item-navigation-button-max-width);
310
327
  }
311
328
  .mg-menu-item__collapse-container {
312
- position: absolute;
313
- top: 100%;
314
- left: 0;
315
329
  width: max-content;
316
330
  z-index: 10;
317
331
  }
@@ -321,9 +335,12 @@
321
335
  .mg-menu-item__navigation-button-text-content {
322
336
  width: 100%;
323
337
  display: flex;
338
+ align-items: center;
324
339
  }
340
+ .mg-menu-item__navigation-button-text-content-notification,
325
341
  .mg-menu-item__navigation-button-text-content ::slotted([slot=information]) {
326
342
  margin-left: 1rem;
343
+ font-size: var(--font-size);
327
344
  }
328
345
  .mg-menu-item__navigation-button-chevron {
329
346
  margin-left: auto;
@@ -342,6 +359,15 @@
342
359
  text-overflow: ellipsis;
343
360
  }
344
361
 
362
+ ::slotted(*) {
363
+ display: flex;
364
+ flex-direction: column;
365
+ }
366
+
345
367
  :host([status=disabled]) {
346
368
  pointer-events: none;
369
+ }
370
+
371
+ :host([hidden]) {
372
+ display: none;
347
373
  }