@mgdis/mg-components 5.6.0 → 5.8.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 (203) hide show
  1. package/dist/cjs/{index-4dcc1812.js → index-5e7ede97.js} +109 -3
  2. package/dist/cjs/loader.cjs.js +4 -3
  3. package/dist/cjs/{mg-badge_30.cjs.entry.js → mg-action-more_31.cjs.entry.js} +490 -661
  4. package/dist/cjs/mg-components.cjs.js +7 -3
  5. package/dist/cjs/mg-item-more.cjs.entry.js +273 -0
  6. package/dist/cjs/mg-menu.conf-9afe6571.js +242 -0
  7. package/dist/collection/collection-manifest.json +7 -5
  8. package/dist/collection/components/atoms/mg-badge/mg-badge.js +1 -1
  9. package/dist/collection/components/atoms/mg-button/mg-button.css +7 -21
  10. package/dist/collection/components/atoms/mg-button/mg-button.js +25 -1
  11. package/dist/collection/components/atoms/mg-icon/mg-icon.conf.js +35 -27
  12. package/dist/collection/components/atoms/mg-icon/mg-icon.js +3 -3
  13. package/dist/collection/components/atoms/mg-tag/mg-tag.js +1 -1
  14. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.js +18 -17
  15. package/dist/collection/components/molecules/inputs/MgInput.js +6 -1
  16. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.css +4 -3
  17. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +3 -2
  18. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.css +4 -0
  19. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +1 -1
  20. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.css +4 -0
  21. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.js +1 -1
  22. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.css +4 -0
  23. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.css +4 -3
  24. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.js +2 -1
  25. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.css +4 -0
  26. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +1 -1
  27. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.css +4 -0
  28. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.css +4 -0
  29. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.js +1 -1
  30. package/dist/collection/components/molecules/inputs/mg-input-toggle/mg-input-toggle.css +4 -4
  31. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.conf.js +0 -13
  32. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.js +41 -70
  33. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.css +5 -4
  34. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.js +160 -61
  35. package/dist/collection/components/molecules/mg-action-more/mg-action-more.conf.js +1 -0
  36. package/dist/collection/components/molecules/mg-action-more/mg-action-more.css +38 -0
  37. package/dist/collection/components/molecules/mg-action-more/mg-action-more.js +252 -0
  38. package/dist/collection/components/molecules/mg-form/mg-form.js +2 -2
  39. package/dist/collection/components/molecules/mg-item-more/mg-item-more.conf.js +1 -0
  40. package/dist/collection/components/molecules/mg-item-more/mg-item-more.css +30 -0
  41. package/dist/collection/components/molecules/mg-item-more/mg-item-more.js +200 -0
  42. package/dist/collection/components/molecules/mg-message/mg-message.js +1 -1
  43. package/dist/collection/components/molecules/mg-pagination/mg-pagination.js +19 -1
  44. package/dist/collection/components/molecules/mg-panel/mg-panel.js +2 -2
  45. package/dist/collection/components/molecules/mg-popover/mg-popover.css +0 -1
  46. package/dist/collection/components/molecules/mg-popover/mg-popover.js +17 -4
  47. package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.js +2 -1
  48. package/dist/collection/components/molecules/mg-tabs/mg-tabs.css +2 -3
  49. package/dist/collection/components/molecules/mg-tabs/mg-tabs.js +9 -8
  50. package/dist/collection/locales/en/messages.json +6 -1
  51. package/dist/collection/locales/fr/messages.json +6 -1
  52. package/dist/collection/locales/index.js +1 -1
  53. package/dist/collection/styles/mg-icon-animation.scss +6 -0
  54. package/dist/collection/styles/navigation-button.scss +3 -2
  55. package/dist/collection/utils/behaviors.utils.js +38 -52
  56. package/dist/collection/utils/components.utils.js +3 -1
  57. package/dist/collection/utils/locale.utils.js +9 -9
  58. package/dist/collection/utils/unit.test.utils.js +32 -4
  59. package/dist/collection/variables.css +2 -1
  60. package/dist/components/MgInput.js +6 -1
  61. package/dist/components/components.utils.js +3 -1
  62. package/dist/components/index.d.ts +11 -0
  63. package/dist/components/index.js +3 -1
  64. package/dist/components/index2.js +26 -14
  65. package/dist/components/mg-action-more.d.ts +11 -0
  66. package/dist/components/mg-action-more.js +216 -0
  67. package/dist/components/mg-badge2.js +1 -1
  68. package/dist/components/mg-button2.js +6 -3
  69. package/dist/components/mg-form.js +2 -2
  70. package/dist/components/mg-icon2.js +38 -30
  71. package/dist/components/mg-input-checkbox.js +3 -3
  72. package/dist/components/mg-input-date.js +2 -2
  73. package/dist/components/mg-input-numeric.js +2 -2
  74. package/dist/components/mg-input-password.js +1 -1
  75. package/dist/components/mg-input-radio.js +2 -2
  76. package/dist/components/mg-input-select2.js +2 -2
  77. package/dist/components/mg-input-text2.js +1 -1
  78. package/dist/components/mg-input-textarea.js +2 -2
  79. package/dist/components/mg-input-toggle.js +1 -1
  80. package/dist/components/mg-item-more.d.ts +11 -0
  81. package/dist/components/mg-item-more.js +336 -0
  82. package/dist/components/mg-menu-item2.js +137 -250
  83. package/dist/components/mg-menu.conf.js +14 -0
  84. package/dist/components/mg-menu.js +1 -246
  85. package/dist/components/mg-menu2.js +180 -0
  86. package/dist/components/mg-message.js +1 -1
  87. package/dist/components/mg-pagination.js +3 -1
  88. package/dist/components/mg-panel.js +2 -2
  89. package/dist/components/mg-popover2.js +17 -3
  90. package/dist/components/mg-skip-links.js +1 -1
  91. package/dist/components/mg-tabs.js +10 -9
  92. package/dist/components/mg-tag.js +1 -1
  93. package/dist/components/mg-tooltip2.js +18 -17
  94. package/dist/esm/{index-dc9a2348.js → index-03cceb11.js} +109 -4
  95. package/dist/esm/loader.js +4 -3
  96. package/dist/esm/{mg-badge_30.entry.js → mg-action-more_31.entry.js} +464 -636
  97. package/dist/esm/mg-components.js +4 -3
  98. package/dist/esm/mg-item-more.entry.js +269 -0
  99. package/dist/esm/mg-menu.conf-881fbd82.js +235 -0
  100. package/dist/mg-components/locales/en/messages.json +6 -1
  101. package/dist/mg-components/locales/fr/messages.json +6 -1
  102. package/dist/mg-components/mg-components.css +1 -1
  103. package/dist/mg-components/mg-components.esm.js +1 -1
  104. package/dist/mg-components/p-1221773c.entry.js +1 -0
  105. package/dist/mg-components/p-367f92d2.js +1 -0
  106. package/dist/mg-components/p-6aeded97.entry.js +1 -0
  107. package/dist/mg-components/p-e126dd84.js +2 -0
  108. package/dist/mg-components/styles/mg-icon-animation.scss +6 -0
  109. package/dist/mg-components/styles/navigation-button.scss +3 -2
  110. package/dist/mg-components/variables.css +2 -1
  111. package/dist/types/components/atoms/mg-button/mg-button.d.ts +5 -0
  112. package/dist/types/components/molecules/inputs/mg-input-textarea/mg-input-textarea.d.ts +1 -1
  113. package/dist/types/components/molecules/menu/mg-menu/mg-menu.conf.d.ts +3 -27
  114. package/dist/types/components/molecules/menu/mg-menu/mg-menu.d.ts +9 -27
  115. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.conf.d.ts +5 -0
  116. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.d.ts +66 -11
  117. package/dist/types/components/molecules/mg-action-more/mg-action-more.conf.d.ts +42 -0
  118. package/dist/types/components/molecules/mg-action-more/mg-action-more.d.ts +81 -0
  119. package/dist/types/components/molecules/mg-item-more/mg-item-more.conf.d.ts +26 -0
  120. package/dist/types/components/molecules/mg-item-more/mg-item-more.d.ts +74 -0
  121. package/dist/types/components/molecules/mg-pagination/mg-pagination.d.ts +4 -0
  122. package/dist/types/components/molecules/mg-popover/mg-popover.d.ts +2 -1
  123. package/dist/types/components.d.ts +120 -12
  124. package/dist/types/locales/index.d.ts +12 -2
  125. package/dist/types/stencil-public-runtime.d.ts +9 -0
  126. package/dist/types/utils/behaviors.utils.d.ts +12 -11
  127. package/dist/types/utils/locale.utils.d.ts +5 -5
  128. package/dist/types/utils/unit.test.utils.d.ts +20 -2
  129. package/loader/index.d.ts +9 -0
  130. package/package.json +17 -16
  131. package/readme.md +0 -18
  132. package/dist/.storybook/utils.js +0 -24
  133. package/dist/collection/components/atoms/mg-badge/doc/mg-badge.stories.js +0 -27
  134. package/dist/collection/components/atoms/mg-button/doc/mg-button.stories.js +0 -38
  135. package/dist/collection/components/atoms/mg-card/doc/mg-card.stories.js +0 -18
  136. package/dist/collection/components/atoms/mg-character-left/doc/mg-character-left.stories.js +0 -20
  137. package/dist/collection/components/atoms/mg-divider/doc/mg-divider.stories.js +0 -18
  138. package/dist/collection/components/atoms/mg-icon/doc/mg-icon.stories.js +0 -41
  139. package/dist/collection/components/atoms/mg-input-title/doc/mg-input-title.stories.js +0 -21
  140. package/dist/collection/components/atoms/mg-tag/doc/mg-tag.stories.js +0 -22
  141. package/dist/collection/components/atoms/mg-tooltip/doc/mg-tooltip.stories.js +0 -50
  142. package/dist/collection/components/molecules/inputs/mg-input-checkbox/doc/mg-input-checkbox.stories.js +0 -50
  143. package/dist/collection/components/molecules/inputs/mg-input-date/doc/mg-input-date.stories.js +0 -43
  144. package/dist/collection/components/molecules/inputs/mg-input-numeric/doc/mg-input-numeric.stories.js +0 -68
  145. package/dist/collection/components/molecules/inputs/mg-input-password/doc/mg-input-password.stories.js +0 -46
  146. package/dist/collection/components/molecules/inputs/mg-input-radio/doc/mg-input-radio.stories.js +0 -59
  147. package/dist/collection/components/molecules/inputs/mg-input-select/doc/mg-input-select.stories.js +0 -77
  148. package/dist/collection/components/molecules/inputs/mg-input-text/doc/mg-input-text.stories.js +0 -110
  149. package/dist/collection/components/molecules/inputs/mg-input-textarea/doc/mg-input-textarea.stories.js +0 -54
  150. package/dist/collection/components/molecules/inputs/mg-input-toggle/doc/mg-input-toggle.stories.js +0 -51
  151. package/dist/collection/components/molecules/menu/mg-menu/doc/mg-menu.stories.js +0 -119
  152. package/dist/collection/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.js +0 -34
  153. package/dist/collection/components/molecules/mg-details/doc/mg-details.stories.js +0 -24
  154. package/dist/collection/components/molecules/mg-form/doc/mg-form.stories.js +0 -47
  155. package/dist/collection/components/molecules/mg-illustrated-message/doc/mg-illustrated-message.stories.js +0 -19
  156. package/dist/collection/components/molecules/mg-message/doc/mg-message.stories.js +0 -39
  157. package/dist/collection/components/molecules/mg-modal/doc/mg-modal.stories.js +0 -39
  158. package/dist/collection/components/molecules/mg-pagination/doc/mg-pagination.stories.js +0 -20
  159. package/dist/collection/components/molecules/mg-panel/doc/mg-panel.stories.js +0 -22
  160. package/dist/collection/components/molecules/mg-popover/doc/mg-popover.stories.js +0 -34
  161. package/dist/collection/components/molecules/mg-skip-links/doc/mg-skip-links.stories.js +0 -24
  162. package/dist/collection/components/molecules/mg-tabs/doc/mg-tabs.stories.js +0 -53
  163. package/dist/collection/stories/grids.stories.js +0 -7
  164. package/dist/collection/stories/helpers.stories.js +0 -23
  165. package/dist/collection/stories/icons.stories.js +0 -25
  166. package/dist/collection/stories/typography.stories.js +0 -24
  167. package/dist/mg-components/p-182bd802.js +0 -2
  168. package/dist/mg-components/p-f7da9dd2.entry.js +0 -1
  169. package/dist/types/components/atoms/mg-badge/doc/mg-badge.stories.d.ts +0 -13
  170. package/dist/types/components/atoms/mg-button/doc/mg-button.stories.d.ts +0 -16
  171. package/dist/types/components/atoms/mg-card/doc/mg-card.stories.d.ts +0 -6
  172. package/dist/types/components/atoms/mg-character-left/doc/mg-character-left.stories.d.ts +0 -6
  173. package/dist/types/components/atoms/mg-divider/doc/mg-divider.stories.d.ts +0 -6
  174. package/dist/types/components/atoms/mg-icon/doc/mg-icon.stories.d.ts +0 -26
  175. package/dist/types/components/atoms/mg-input-title/doc/mg-input-title.stories.d.ts +0 -6
  176. package/dist/types/components/atoms/mg-tag/doc/mg-tag.stories.d.ts +0 -6
  177. package/dist/types/components/atoms/mg-tooltip/doc/mg-tooltip.stories.d.ts +0 -18
  178. package/dist/types/components/molecules/inputs/mg-input-checkbox/doc/mg-input-checkbox.stories.d.ts +0 -11
  179. package/dist/types/components/molecules/inputs/mg-input-date/doc/mg-input-date.stories.d.ts +0 -12
  180. package/dist/types/components/molecules/inputs/mg-input-numeric/doc/mg-input-numeric.stories.d.ts +0 -32
  181. package/dist/types/components/molecules/inputs/mg-input-password/doc/mg-input-password.stories.d.ts +0 -22
  182. package/dist/types/components/molecules/inputs/mg-input-radio/doc/mg-input-radio.stories.d.ts +0 -20
  183. package/dist/types/components/molecules/inputs/mg-input-select/doc/mg-input-select.stories.d.ts +0 -34
  184. package/dist/types/components/molecules/inputs/mg-input-text/doc/mg-input-text.stories.d.ts +0 -39
  185. package/dist/types/components/molecules/inputs/mg-input-textarea/doc/mg-input-textarea.stories.d.ts +0 -19
  186. package/dist/types/components/molecules/inputs/mg-input-toggle/doc/mg-input-toggle.stories.d.ts +0 -12
  187. package/dist/types/components/molecules/menu/mg-menu/doc/mg-menu.stories.d.ts +0 -22
  188. package/dist/types/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.d.ts +0 -12
  189. package/dist/types/components/molecules/mg-details/doc/mg-details.stories.d.ts +0 -11
  190. package/dist/types/components/molecules/mg-form/doc/mg-form.stories.d.ts +0 -11
  191. package/dist/types/components/molecules/mg-illustrated-message/doc/mg-illustrated-message.stories.d.ts +0 -6
  192. package/dist/types/components/molecules/mg-message/doc/mg-message.stories.d.ts +0 -26
  193. package/dist/types/components/molecules/mg-modal/doc/mg-modal.stories.d.ts +0 -13
  194. package/dist/types/components/molecules/mg-pagination/doc/mg-pagination.stories.d.ts +0 -11
  195. package/dist/types/components/molecules/mg-panel/doc/mg-panel.stories.d.ts +0 -11
  196. package/dist/types/components/molecules/mg-popover/doc/mg-popover.stories.d.ts +0 -22
  197. package/dist/types/components/molecules/mg-skip-links/doc/mg-skip-links.stories.d.ts +0 -11
  198. package/dist/types/components/molecules/mg-tabs/doc/mg-tabs.stories.d.ts +0 -20
  199. package/dist/types/home/runner/work/mg-components/mg-components/.stencil/.storybook/utils.d.ts +0 -1
  200. package/dist/types/stories/grids.stories.d.ts +0 -5
  201. package/dist/types/stories/helpers.stories.d.ts +0 -13
  202. package/dist/types/stories/icons.stories.d.ts +0 -13
  203. package/dist/types/stories/typography.stories.d.ts +0 -5
@@ -1,6 +1,5 @@
1
1
  import { h, Host } from '@stencil/core';
2
- import { OverflowBehaviorElements } from '../../../../utils/behaviors.utils';
3
- import { ClassList } from '../../../../utils/components.utils';
2
+ import { ClassList, createID } from '../../../../utils/components.utils';
4
3
  import { initLocales } from '../../../../locales';
5
4
  import { Direction } from '../mg-menu/mg-menu.conf';
6
5
  import { Status } from './mg-menu-item.conf';
@@ -25,18 +24,100 @@ export class MgMenuItem {
25
24
  /**
26
25
  * Does an Element have given Status
27
26
  *
28
- * @param {Element} element to parse
27
+ * @param {HTMLMgMenuItemElement} mgMenuItemElement to parse
29
28
  * @param {MgMenuItem['status']} status to check
30
29
  * @returns {boolean} true if element with status is found
31
30
  */
32
- this.hasStatus = (element, status) => element.querySelector(`${this.name}[status="${status}"]`) !== null;
31
+ this.hasStatus = (mgMenuItemElement, status) => mgMenuItemElement.status === status;
33
32
  /**
34
33
  * Is component contextual direction match the given direction
35
34
  *
36
35
  * @param {MgMenuItem['direction']} direction in parent menu
36
+ * @param {MgMenuItem['direction']} compareWith direction to compare with. Default: `this.direction`
37
37
  * @returns {boolean} true is direction match the direction propertie
38
38
  */
39
- this.isDirection = (direction) => this.direction === direction;
39
+ this.isDirection = (direction, compareWith = this.direction) => direction === compareWith;
40
+ /**
41
+ * Update displayNotificationBadge
42
+ * current component notification badge have priority over the slot badge when submenu contain badge
43
+ *
44
+ * @returns {void} update displayNotificationBadge value
45
+ */
46
+ this.updateDisplayNotificationBadge = () => {
47
+ const childMenu = this.element.querySelector('mg-menu');
48
+ this.displayNotificationBadge =
49
+ childMenu !== null &&
50
+ Array.from(childMenu.children).some((subItem) => subItem.querySelector('mg-badge') !== null && subItem.getAttribute('hidden') === null);
51
+ };
52
+ /**
53
+ * Method to control if one of component children have active status
54
+ *
55
+ * @returns {boolean} truthy if component has active child
56
+ */
57
+ this.hasActiveChild = () => {
58
+ var _a;
59
+ return Array.from(((_a = this.element.querySelector('mg-menu')) === null || _a === void 0 ? void 0 : _a.children) || []).some((element) => element.nodeName === 'MG-MENU-ITEM' && this.hasStatus(element, Status.ACTIVE) && element.getAttribute('hidden') === null);
60
+ };
61
+ /**
62
+ * Validate slots
63
+ *
64
+ * @param {boolean} guard prevent action whith guard. Default: false.
65
+ * @returns {void}
66
+ */
67
+ this.validateSlot = (guard = false) => {
68
+ // slot title AND metadata validation
69
+ // add title on label AND metada slots due to text-overflow on these element
70
+ if (Array.from(this.element.children).find(child => child.getAttribute('slot') === 'label') === undefined)
71
+ throw new Error(`<${this.name}> slot "label" is required.`);
72
+ ['label', 'metadata'].forEach(slot => {
73
+ Array.from(this.element.querySelectorAll(`[slot="${slot}"]`)).forEach(element => {
74
+ if (element.textContent.trim().length < 1)
75
+ throw new Error(`<${this.name}> slot "${slot}" must have text content.`);
76
+ if ((guard && element.getAttribute('title') === null) || !guard)
77
+ element.setAttribute('title', element.textContent);
78
+ });
79
+ });
80
+ };
81
+ /**
82
+ * Update status
83
+ *
84
+ * @param {Status[]} guard status to exclude from process in addition to [Status.HIDDEN, Status.DISABLED] . Default: [].
85
+ * @returns {void}
86
+ */
87
+ this.updateStatus = (guard = []) => {
88
+ if (![Status.HIDDEN, Status.DISABLED, ...guard].includes(this.status)) {
89
+ this.status = this.hasActiveChild() ? Status.ACTIVE : Status.VISIBLE;
90
+ }
91
+ };
92
+ /**
93
+ * Init event-listeners
94
+ *
95
+ * @returns {void}
96
+ */
97
+ this.initListeners = () => {
98
+ var _a;
99
+ // manage first sub-level menu-items
100
+ Array.from(((_a = this.element.querySelector('mg-menu')) === null || _a === void 0 ? void 0 : _a.children) || []).forEach(item => {
101
+ if (item.nodeName === 'MG-MENU-ITEM') {
102
+ // manage child menu listener
103
+ item.addEventListener('status-change', () => {
104
+ this.updateStatus();
105
+ });
106
+ }
107
+ });
108
+ };
109
+ /**
110
+ * Get mg-popover identifier
111
+ *
112
+ * @returns {MgPopover['identifier']} generated mg-popover identifier
113
+ */
114
+ this.getPopoverIdentifier = () => `${this.identifier}-popover`;
115
+ /**
116
+ * Condition to know if component should display a mg-popover
117
+ *
118
+ * @returns {boolean} truthy if component display popover
119
+ */
120
+ this.displayPopover = () => this.isDirection(Direction.HORIZONTAL) && this.hasChildren && this.href === undefined;
40
121
  /************
41
122
  * Handlers *
42
123
  ************/
@@ -64,24 +145,13 @@ export class MgMenuItem {
64
145
  this.handlePopoverDisplay = (event) => {
65
146
  this.expanded = event.detail;
66
147
  };
67
- /**
68
- * Update displayNotificationBadge
69
- * current component notification badge have priority over the slot badge when submenu contain badge
70
- *
71
- * @returns {void} update displayNotificationBadge value
72
- */
73
- this.updateDisplayNotificationBadge = () => {
74
- const childMenu = this.element.querySelector('mg-menu');
75
- this.displayNotificationBadge =
76
- childMenu !== null &&
77
- Array.from(childMenu.children).some((subItem) => subItem.querySelector('mg-badge') !== null && subItem.getAttribute('hidden') === null);
78
- };
79
148
  /**
80
149
  * Render slot
81
150
  *
82
151
  * @returns {HTMLElement} HTML Element
83
152
  */
84
153
  this.renderSlot = () => h("slot", null);
154
+ this.identifier = createID('mg-menu-item');
85
155
  this.href = undefined;
86
156
  this.status = Status.VISIBLE;
87
157
  this.expanded = false;
@@ -89,6 +159,7 @@ export class MgMenuItem {
89
159
  this.navigationButtonClassList = new ClassList([this.navigationButton]);
90
160
  this.direction = undefined;
91
161
  this.isInMainMenu = undefined;
162
+ this.isItemMore = undefined;
92
163
  this.hasChildren = false;
93
164
  this.displayNotificationBadge = undefined;
94
165
  }
@@ -111,7 +182,7 @@ export class MgMenuItem {
111
182
  item.expanded = false;
112
183
  });
113
184
  }
114
- else if (this.hasStatus(this.element, Status.ACTIVE)) {
185
+ else if (this.element.querySelector(`${this.name}[status="${Status.ACTIVE}"]`) !== null) {
115
186
  // - when expanded and contain an active item parents are expended too
116
187
  subItems.forEach(item => {
117
188
  if (this.hasStatus(item, Status.ACTIVE)) {
@@ -125,11 +196,33 @@ export class MgMenuItem {
125
196
  this.navigationButtonClassList.delete(`${this.navigationButton}--size-${oldValue}`);
126
197
  this.navigationButtonClassList.add(`${this.navigationButton}--size-${newValue}`);
127
198
  }
199
+ validateDirection(newValue) {
200
+ // manage menu items style depending to parent menu horientation
201
+ this.element.setAttribute(`data-style-direction-${newValue}`, '');
202
+ this.navigationButtonClassList.add(`${this.navigationButton}--${newValue}`);
203
+ // manage all sub levels child menu-items level with data-level attribut
204
+ if (this.isDirection(Direction.VERTICAL, newValue)) {
205
+ Array.from(this.element.querySelectorAll('mg-menu-item')).forEach(item => {
206
+ item.dataset.level = `${(Number(item.dataset.level) || 1) + 1}`;
207
+ });
208
+ }
209
+ }
128
210
  validateHasChildren(newValue) {
129
211
  if (newValue && this.element.href !== undefined) {
130
212
  throw new Error(`<${this.name}> prop "href" is unauthorizied when element is a parent.`);
131
213
  }
132
214
  }
215
+ /**
216
+ * Render popover clickoutside guard for content slot
217
+ *
218
+ * @returns {void}
219
+ */
220
+ updatePopoverGuard() {
221
+ if (this.displayPopover())
222
+ Array.from(this.element.children)
223
+ .filter((child) => child.getAttribute('slot') === null && child.nodeName !== 'MG-MENU' && Boolean(child.dataset))
224
+ .forEach((slot) => (slot.dataset.mgPopoverGuard = this.getPopoverIdentifier()));
225
+ }
133
226
  /*************
134
227
  * Lifecycle *
135
228
  *************/
@@ -142,11 +235,13 @@ export class MgMenuItem {
142
235
  // has children items that is NOT [slot='image' | 'information' | 'label' | 'metadata'] element
143
236
  // we store only matching elements
144
237
  this.hasChildren = Array.from(this.element.children).some(child => !['image', 'information', 'label', 'metadata'].includes(child.getAttribute('slot')));
238
+ this.badgeLabel = initLocales(this.element).messages.plusMenu.badgeLabel;
239
+ this.isItemMore = this.element.dataset.overflowMore !== undefined;
145
240
  // Validate props
146
- this.validateSize(this.size);
147
241
  this.validateStatus(this.status);
148
242
  this.validateExpanded(this.expanded);
149
- this.badgeLabel = initLocales(this.element).messages.plusMenu.badgeLabel;
243
+ // Validate states
244
+ this.validateSize(this.size);
150
245
  }
151
246
  /**
152
247
  * Check if component slots configuration
@@ -154,54 +249,36 @@ export class MgMenuItem {
154
249
  * @returns {ReturnType<typeof setTimeout>} timeout
155
250
  */
156
251
  componentDidLoad() {
157
- // slot title AND metadata validation
158
- // add title on label AND metada slots due to text-overflow on these element
159
- if (Array.from(this.element.children).find(child => child.getAttribute('slot') === 'label') === undefined)
160
- throw new Error(`<${this.name}> slot "label" is required.`);
161
- ['label', 'metadata'].forEach(slot => {
162
- Array.from(this.element.querySelectorAll(`[slot="${slot}"]`)).forEach(element => {
163
- if (element.textContent.trim().length < 1)
164
- throw new Error(`<${this.name}> slot "${slot}" must have text content.`);
165
- if (element.getAttribute('title') === null)
166
- element.setAttribute('title', element.textContent);
167
- });
168
- });
252
+ // validation
253
+ this.validateSlot(true);
169
254
  // update props and states after componentDidLoad hook
170
255
  // return a promise to process action only in the FIRST render().
171
256
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
172
257
  return setTimeout(() => {
173
- var _a;
174
258
  // define menu-item context states
175
259
  const menu = this.element.closest('mg-menu');
176
- this.direction = this.element.getAttribute(OverflowBehaviorElements.MORE) !== null || menu === null ? Direction.HORIZONTAL : menu.direction;
177
- this.size = menu === null || menu === void 0 ? void 0 : menu.size;
178
- this.isInMainMenu = this.element.parentElement.closest('mg-menu-item') === null;
260
+ this.direction = this.isItemMore || menu === null ? Direction.HORIZONTAL : menu.direction;
261
+ this.isInMainMenu = menu !== null && this.element.parentElement.closest('mg-menu-item') === null;
262
+ if ((menu === null || menu === void 0 ? void 0 : menu.size) !== undefined)
263
+ this.size = menu.size;
264
+ if (this.isItemMore)
265
+ this.size = this.element.dataset.size;
179
266
  // when main menu item contain an active item it will get the active style
180
267
  // AND if item is in vertical menu it will be expanded
181
- const hasActiveChild = Array.from(this.element.children).some(element => this.hasStatus(element, Status.ACTIVE) && element.getAttribute('hidden') === null);
182
- if (this.isInMainMenu && hasActiveChild) {
183
- this.status = Status.ACTIVE;
268
+ if (this.hasActiveChild() && this.isInMainMenu)
184
269
  this.expanded = this.isDirection(Direction.VERTICAL);
185
- }
186
- // manage menu items style depending to parent menu horientation
187
- this.element.setAttribute(`data-style-direction-${this.direction}`, '');
188
- this.navigationButtonClassList.add(`${this.navigationButton}--${this.direction}`);
270
+ this.updateStatus([Status.ACTIVE]);
189
271
  this.updateDisplayNotificationBadge();
190
- // manage all sub levels child menu-items level with data-level attribut
191
- if (this.isDirection(Direction.VERTICAL)) {
192
- Array.from(this.element.querySelectorAll('mg-menu-item')).forEach(item => {
193
- const itemLevel = Number(item.getAttribute('data-level')) || 1;
194
- item.setAttribute('data-level', `${itemLevel + 1}`);
195
- });
196
- }
197
- // manage first sub-level menu-items
198
- const childItems = Array.from(((_a = this.element.querySelector('mg-menu')) === null || _a === void 0 ? void 0 : _a.children) || []).filter(item => item.nodeName === 'MG-MENU-ITEM');
199
- childItems.forEach(item => {
200
- // manage child menu listener
201
- new MutationObserver(() => {
202
- this.updateDisplayNotificationBadge();
203
- }).observe(item, { attributes: true });
204
- });
272
+ this.updatePopoverGuard();
273
+ // manage child dom changes with mutationObserver and listzners
274
+ this.initListeners();
275
+ new MutationObserver(mutationsList => {
276
+ if (mutationsList.some(mutation => mutation.attributeName === 'hidden'))
277
+ this.updateStatus();
278
+ if (mutationsList.some(mutation => mutation.type === 'characterData'))
279
+ this.validateSlot();
280
+ this.updateDisplayNotificationBadge();
281
+ }).observe(this.element, { attributes: true, childList: true, characterData: true, subtree: true });
205
282
  }, 0);
206
283
  }
207
284
  /**
@@ -211,7 +288,7 @@ export class MgMenuItem {
211
288
  */
212
289
  renderInteractiveElement() {
213
290
  const TagName = this.href !== undefined ? 'a' : 'button';
214
- return (h(TagName, { href: this.href, class: this.navigationButtonClassList.join(), tabindex: [Status.DISABLED, Status.HIDDEN].includes(this.status) ? -1 : 0, disabled: this.status === Status.DISABLED, hidden: this.status === Status.HIDDEN, "aria-expanded": this.hasChildren && this.expanded.toString(), "aria-current": this.status === Status.ACTIVE && 'page', onClick: this.handleElementCLick }, h("slot", { name: "image" }), h("div", { class: `${this.navigationButton}-center` }, h("div", { class: `${this.navigationButton}-text-content` }, h("slot", { name: "label" }), !this.displayNotificationBadge && h("slot", { name: "information" }), this.displayNotificationBadge && (h("span", { class: "mg-menu-item__navigation-button-text-content-notification" }, h("mg-badge", { label: this.badgeLabel, value: "!", variant: "info", slot: "information" })))), this.size !== 'regular' && h("slot", { name: "metadata" })), this.hasChildren && this.href === undefined && (h("span", { class: {
291
+ return (h(TagName, { href: this.href, class: this.navigationButtonClassList.join(), tabindex: [Status.DISABLED, Status.HIDDEN].includes(this.status) ? -1 : 0, disabled: this.status === Status.DISABLED, hidden: this.status === Status.HIDDEN, "aria-expanded": this.hasChildren && this.expanded.toString(), "aria-current": this.status === Status.ACTIVE && 'page', onClick: this.handleElementCLick }, h("slot", { name: "image" }), h("div", { class: `${this.navigationButton}-center` }, h("div", { class: `${this.navigationButton}-text-content` }, h("slot", { name: "label" }), !this.displayNotificationBadge && h("slot", { name: "information" }), this.displayNotificationBadge && (h("span", { class: "mg-menu-item__navigation-button-text-content-notification" }, h("mg-badge", { label: this.badgeLabel, value: "!", variant: "text-color", slot: "information" })))), this.size !== 'regular' && h("slot", { name: "metadata" })), this.hasChildren && this.href === undefined && (h("span", { class: {
215
292
  [`${this.navigationButton}-chevron`]: true,
216
293
  [`${this.navigationButton}-chevron--rotate`]: this.expanded === true,
217
294
  'mg-a11y-animation': true,
@@ -227,9 +304,9 @@ export class MgMenuItem {
227
304
  [`${this.name}__collapse-container`]: true,
228
305
  [`${this.name}__collapse-container--first-level`]: this.isInMainMenu && this.isDirection(Direction.HORIZONTAL),
229
306
  });
230
- return (h(Host, { role: "menuitem", "aria-haspopup": this.hasChildren.toString() }, this.isDirection(Direction.HORIZONTAL) && this.hasChildren && this.href === undefined ? (h("mg-popover", { display: this.expanded, placement: "bottom-start", arrowHide: true, "onDisplay-change": this.handlePopoverDisplay }, this.renderInteractiveElement(), h("div", { class: getContainerClasses(), slot: "content" }, this.renderSlot()))) : ([
307
+ return (h(Host, { role: !this.isItemMore && 'menuitem', "aria-haspopup": !this.isItemMore && this.hasChildren.toString() }, this.displayPopover() ? (h("mg-popover", { display: this.expanded, placement: "bottom-start", arrowHide: true, "onDisplay-change": this.handlePopoverDisplay, identifier: this.getPopoverIdentifier() }, this.renderInteractiveElement(), h("div", { class: getContainerClasses(), slot: "content" }, this.renderSlot()))) : ([
231
308
  this.renderInteractiveElement(),
232
- h("div", { class: getContainerClasses(), hidden: !this.expanded }, this.renderSlot()),
309
+ h("div", { key: "vertical-container", class: getContainerClasses(), hidden: !this.expanded }, this.renderSlot()),
233
310
  ])));
234
311
  }
235
312
  static get is() { return "mg-menu-item"; }
@@ -246,6 +323,24 @@ export class MgMenuItem {
246
323
  }
247
324
  static get properties() {
248
325
  return {
326
+ "identifier": {
327
+ "type": "string",
328
+ "mutable": false,
329
+ "complexType": {
330
+ "original": "string",
331
+ "resolved": "string",
332
+ "references": {}
333
+ },
334
+ "required": false,
335
+ "optional": false,
336
+ "docs": {
337
+ "tags": [],
338
+ "text": "Identifier is used to control mg-popover\nDefault: createID('mg-menu-item');"
339
+ },
340
+ "attribute": "identifier",
341
+ "reflect": false,
342
+ "defaultValue": "createID('mg-menu-item')"
343
+ },
249
344
  "href": {
250
345
  "type": "string",
251
346
  "mutable": false,
@@ -312,6 +407,7 @@ export class MgMenuItem {
312
407
  "navigationButtonClassList": {},
313
408
  "direction": {},
314
409
  "isInMainMenu": {},
410
+ "isItemMore": {},
315
411
  "hasChildren": {},
316
412
  "displayNotificationBadge": {}
317
413
  };
@@ -349,6 +445,9 @@ export class MgMenuItem {
349
445
  }, {
350
446
  "propName": "size",
351
447
  "methodName": "validateSize"
448
+ }, {
449
+ "propName": "direction",
450
+ "methodName": "validateDirection"
352
451
  }, {
353
452
  "propName": "hasChildren",
354
453
  "methodName": "validateHasChildren"
@@ -0,0 +1,38 @@
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
+ }
28
+ :host {
29
+ --mg-popover-padding-vertical: 1rem;
30
+ --mg-popover-padding-horizontal: 0;
31
+ }
32
+
33
+ .mg-action-more__chevron {
34
+ transition: 200ms;
35
+ }
36
+ .mg-action-more__chevron--rotate.mg-action-more__chevron {
37
+ transform: rotate(180deg);
38
+ }
@@ -0,0 +1,252 @@
1
+ import { h, Host } from '@stencil/core';
2
+ import { initLocales } from '../../../locales';
3
+ import { Status } from '../menu/mg-menu-item/mg-menu-item.conf';
4
+ import { Direction } from '../menu/mg-menu/mg-menu.conf';
5
+ import { createID } from '../../../utils/components.utils';
6
+ /**
7
+ * MgActionMore['items'] type guard
8
+ *
9
+ * @param {unknown} prop commponent items prop
10
+ * @returns {boolean} return true if type is valid
11
+ */
12
+ const isMgActionMoreItems = (prop) => {
13
+ const items = prop;
14
+ return typeof items === 'object' && items.every(item => typeof item === 'object' && typeof item.label === 'string' && typeof item.mouseEventHandler === 'function');
15
+ };
16
+ /**
17
+ * MgActionMore['button'] type guard
18
+ *
19
+ * @param {unknown} prop commponent button prop
20
+ * @returns {boolean} return true if type is valid
21
+ */
22
+ const isMgActionMoreButton = (prop) => {
23
+ const button = prop;
24
+ return typeof button === 'object' && typeof button.variant === 'string' && typeof button.isIcon === 'boolean';
25
+ };
26
+ /**
27
+ * MgActionMore['icon'] type guard
28
+ *
29
+ * @param {unknown} prop commponent icon prop
30
+ * @returns {boolean} return true if type is valid
31
+ */
32
+ const isMgActionMoreIcon = (prop) => {
33
+ const icon = prop;
34
+ return typeof icon === 'object' && typeof icon.icon === 'string';
35
+ };
36
+ export class MgActionMore {
37
+ constructor() {
38
+ /************
39
+ * Internal *
40
+ ************/
41
+ this.name = 'mg-action-more';
42
+ this.mgPopoverIdentifier = createID(this.name);
43
+ /************
44
+ * Merthods *
45
+ ***********/
46
+ /**
47
+ * Toogle expanded props
48
+ *
49
+ * @returns {void}
50
+ */
51
+ this.toggleExpanded = () => {
52
+ this.expanded = !this.expanded;
53
+ };
54
+ /**
55
+ * Button click handler
56
+ *
57
+ * @returns {void}
58
+ */
59
+ this.handleButton = () => {
60
+ this.toggleExpanded();
61
+ };
62
+ /**
63
+ * Item click handler
64
+ *
65
+ * @param {MouseEvent} event click event
66
+ * @param {MgActionMoreItemType['mouseEventHandler']} customHandler item['mouseEventHandler']
67
+ * @returns {void}
68
+ */
69
+ this.handleItemClick = (event, customHandler) => {
70
+ this.expanded = false;
71
+ customHandler(event);
72
+ };
73
+ this.icon = { icon: 'ellipsis' };
74
+ this.button = { variant: 'flat', isIcon: true };
75
+ this.items = undefined;
76
+ this.displayChevron = undefined;
77
+ this.expanded = false;
78
+ }
79
+ validateIcon(newValue) {
80
+ if (newValue && !isMgActionMoreIcon(newValue)) {
81
+ throw new Error(`<${this.name}> prop icon must match MgActionMoreIconType.`);
82
+ }
83
+ }
84
+ validateButton(newValue) {
85
+ if (newValue && !isMgActionMoreButton(newValue)) {
86
+ throw new Error(`<${this.name}> prop button must match MgActionMoreButtonType.`);
87
+ }
88
+ }
89
+ validateItems(newValue) {
90
+ if (!isMgActionMoreItems(newValue)) {
91
+ throw new Error(`<${this.name}> prop "items" is required and all values must be the same type, MgActionMoreItemType.`);
92
+ }
93
+ }
94
+ validateDisplayChevron(newValue) {
95
+ if (newValue && this.button.isIcon === true) {
96
+ throw new Error(`<${this.name}> prop "displayChevron" can't be used with a 'button" prop "isIcon" attribute.`);
97
+ }
98
+ }
99
+ /*************
100
+ * Lifecycle *
101
+ *************/
102
+ /**
103
+ * Validate props
104
+ *
105
+ * @returns {void}
106
+ */
107
+ componentWillLoad() {
108
+ this.messages = initLocales(this.element).messages.actionMore;
109
+ this.validateItems(this.items);
110
+ this.validateButton(this.button);
111
+ this.validateIcon(this.icon);
112
+ this.validateDisplayChevron(this.displayChevron);
113
+ }
114
+ /**
115
+ * Render
116
+ *
117
+ * @returns {HTMLElement} HTML Element
118
+ */
119
+ render() {
120
+ const buttonLabel = this.button.label || this.messages.label;
121
+ const buttonContent = [buttonLabel];
122
+ if (!this.button.isIcon && this.displayChevron) {
123
+ buttonContent.push(h("span", { class: {
124
+ [`${this.name}__chevron`]: true,
125
+ [`${this.name}__chevron--rotate`]: this.expanded === true,
126
+ 'mg-a11y-animation': true,
127
+ } }, h("mg-icon", { icon: "chevron-down", size: "small" })));
128
+ }
129
+ return (h(Host, { "data-mg-popover-guard": this.mgPopoverIdentifier }, h("span", { class: "mg-action-more" }, h("mg-popover", { identifier: this.mgPopoverIdentifier, display: this.expanded }, h("mg-button", { variant: this.button.variant, isIcon: this.button.isIcon, type: "button", label: buttonLabel, onClick: this.handleButton }, h("mg-icon", Object.assign({}, this.icon)), !this.button.isIcon && buttonContent), h("div", { slot: "content" }, h("mg-menu", { direction: Direction.VERTICAL, label: this.messages.label }, this.items.map(item => {
130
+ var _a;
131
+ return (
132
+ // eslint-disable-next-line react/jsx-no-bind
133
+ h("mg-menu-item", { key: item.label, status: item.status || Status.VISIBLE, onClick: e => this.handleItemClick(e, item.mouseEventHandler), href: item.href }, item.icon && h("mg-icon", { icon: item.icon, slot: "image" }), h("span", { slot: "label" }, item.label), ((_a = item.badge) === null || _a === void 0 ? void 0 : _a.label) && h("mg-badge", { label: item.badge.label, value: item.badge.value, slot: "information", variant: "text-color" })));
134
+ })))))));
135
+ }
136
+ static get is() { return "mg-action-more"; }
137
+ static get encapsulation() { return "shadow"; }
138
+ static get originalStyleUrls() {
139
+ return {
140
+ "$": ["mg-action-more.scss"]
141
+ };
142
+ }
143
+ static get styleUrls() {
144
+ return {
145
+ "$": ["mg-action-more.css"]
146
+ };
147
+ }
148
+ static get properties() {
149
+ return {
150
+ "icon": {
151
+ "type": "unknown",
152
+ "mutable": false,
153
+ "complexType": {
154
+ "original": "MgActionMoreIconType",
155
+ "resolved": "{ icon: string; }",
156
+ "references": {
157
+ "MgActionMoreIconType": {
158
+ "location": "import",
159
+ "path": "./mg-action-more.conf"
160
+ }
161
+ }
162
+ },
163
+ "required": false,
164
+ "optional": false,
165
+ "docs": {
166
+ "tags": [],
167
+ "text": "Define displaied icon\nDefault: {icon: 'ellipsis'}"
168
+ },
169
+ "defaultValue": "{ icon: 'ellipsis' }"
170
+ },
171
+ "button": {
172
+ "type": "unknown",
173
+ "mutable": false,
174
+ "complexType": {
175
+ "original": "MgActionMoreButtonType",
176
+ "resolved": "{ isIcon: boolean; variant: \"flat\" | \"info\" | \"success\" | \"link\" | \"primary\" | \"secondary\" | \"danger\" | \"danger-alt\"; label?: string; }",
177
+ "references": {
178
+ "MgActionMoreButtonType": {
179
+ "location": "import",
180
+ "path": "./mg-action-more.conf"
181
+ }
182
+ }
183
+ },
184
+ "required": false,
185
+ "optional": false,
186
+ "docs": {
187
+ "tags": [],
188
+ "text": "Define button properties\nDefault: {variant: 'flat', isIcon: true}."
189
+ },
190
+ "defaultValue": "{ variant: 'flat', isIcon: true }"
191
+ },
192
+ "items": {
193
+ "type": "unknown",
194
+ "mutable": false,
195
+ "complexType": {
196
+ "original": "MgActionMoreItemType[]",
197
+ "resolved": "MgActionMoreItemType[]",
198
+ "references": {
199
+ "MgActionMoreItemType": {
200
+ "location": "import",
201
+ "path": "./mg-action-more.conf"
202
+ }
203
+ }
204
+ },
205
+ "required": true,
206
+ "optional": false,
207
+ "docs": {
208
+ "tags": [],
209
+ "text": "Define the menu-items elements"
210
+ }
211
+ },
212
+ "displayChevron": {
213
+ "type": "boolean",
214
+ "mutable": false,
215
+ "complexType": {
216
+ "original": "boolean",
217
+ "resolved": "boolean",
218
+ "references": {}
219
+ },
220
+ "required": false,
221
+ "optional": false,
222
+ "docs": {
223
+ "tags": [],
224
+ "text": "Define if chevron is display"
225
+ },
226
+ "attribute": "display-chevron",
227
+ "reflect": false
228
+ }
229
+ };
230
+ }
231
+ static get states() {
232
+ return {
233
+ "expanded": {}
234
+ };
235
+ }
236
+ static get elementRef() { return "element"; }
237
+ static get watchers() {
238
+ return [{
239
+ "propName": "icon",
240
+ "methodName": "validateIcon"
241
+ }, {
242
+ "propName": "button",
243
+ "methodName": "validateButton"
244
+ }, {
245
+ "propName": "items",
246
+ "methodName": "validateItems"
247
+ }, {
248
+ "propName": "displayChevron",
249
+ "methodName": "validateDisplayChevron"
250
+ }];
251
+ }
252
+ }
@@ -23,12 +23,12 @@ export class MgForm {
23
23
  // All fields are required
24
24
  // mg-input-toggle can not be required
25
25
  if (requiredInputs.length > 0 && requiredInputs.length === this.mgInputs.filter(input => input.nodeName !== 'MG-INPUT-TOGGLE').length) {
26
- this.requiredMessage = this.messages.form.allRequired;
26
+ this.requiredMessage = requiredInputs.length === 1 ? this.messages.form.allRequiredSingle : this.messages.form.allRequired;
27
27
  this.classList.add(this.classAllRequired);
28
28
  }
29
29
  // Some fields are required
30
30
  else if (requiredInputs.length > 0) {
31
- this.requiredMessage = this.messages.form.required;
31
+ this.requiredMessage = requiredInputs.length === 1 ? this.messages.form.requiredSingle : this.messages.form.required;
32
32
  }
33
33
  }
34
34
  };