@mgdis/mg-components 5.7.0 → 5.8.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.
Files changed (66) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/mg-action-more_31.cjs.entry.js +351 -600
  3. package/dist/cjs/mg-components.cjs.js +1 -1
  4. package/dist/cjs/mg-item-more.cjs.entry.js +273 -0
  5. package/dist/cjs/mg-menu.conf-9afe6571.js +242 -0
  6. package/dist/collection/collection-manifest.json +2 -1
  7. package/dist/collection/components/atoms/mg-button/mg-button.js +24 -0
  8. package/dist/collection/components/atoms/mg-icon/mg-icon.conf.js +8 -0
  9. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.js +6 -2
  10. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +14 -10
  11. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +91 -21
  12. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.conf.js +0 -13
  13. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.js +80 -76
  14. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.css +7 -5
  15. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.js +174 -78
  16. package/dist/collection/components/molecules/mg-form/mg-form.js +1 -1
  17. package/dist/collection/components/molecules/mg-item-more/mg-item-more.conf.js +1 -0
  18. package/dist/collection/components/molecules/mg-item-more/mg-item-more.css +30 -0
  19. package/dist/collection/components/molecules/mg-item-more/mg-item-more.js +200 -0
  20. package/dist/collection/components/molecules/mg-tabs/mg-tabs.css +0 -2
  21. package/dist/collection/styles/navigation-button.scss +1 -1
  22. package/dist/collection/utils/behaviors.utils.js +33 -29
  23. package/dist/collection/utils/components.utils.js +2 -4
  24. package/dist/collection/utils/unit.test.utils.js +25 -0
  25. package/dist/components/components.utils.js +2 -4
  26. package/dist/components/index.d.ts +1 -0
  27. package/dist/components/index.js +1 -0
  28. package/dist/components/mg-action-more.js +2 -1
  29. package/dist/components/mg-button2.js +4 -1
  30. package/dist/components/mg-form.js +1 -1
  31. package/dist/components/mg-icon2.js +8 -0
  32. package/dist/components/mg-input-checkbox.js +5 -4
  33. package/dist/components/mg-input-select2.js +83 -17
  34. package/dist/components/mg-item-more.d.ts +11 -0
  35. package/dist/components/mg-item-more.js +336 -0
  36. package/dist/components/mg-menu-item2.js +138 -251
  37. package/dist/components/mg-menu.conf.js +14 -0
  38. package/dist/components/mg-menu2.js +76 -111
  39. package/dist/components/mg-tabs.js +1 -1
  40. package/dist/components/mg-tooltip2.js +6 -2
  41. package/dist/esm/loader.js +1 -1
  42. package/dist/esm/mg-action-more_31.entry.js +321 -570
  43. package/dist/esm/mg-components.js +1 -1
  44. package/dist/esm/mg-item-more.entry.js +269 -0
  45. package/dist/esm/mg-menu.conf-881fbd82.js +235 -0
  46. package/dist/mg-components/mg-components.css +1 -1
  47. package/dist/mg-components/mg-components.esm.js +1 -1
  48. package/dist/mg-components/p-1221773c.entry.js +1 -0
  49. package/dist/mg-components/p-30bc87db.entry.js +1 -0
  50. package/dist/mg-components/p-367f92d2.js +1 -0
  51. package/dist/mg-components/styles/navigation-button.scss +1 -1
  52. package/dist/types/components/atoms/mg-button/mg-button.d.ts +5 -0
  53. package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.d.ts +3 -3
  54. package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.d.ts +39 -4
  55. package/dist/types/components/molecules/menu/mg-menu/mg-menu.conf.d.ts +3 -27
  56. package/dist/types/components/molecules/menu/mg-menu/mg-menu.d.ts +38 -30
  57. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.conf.d.ts +5 -0
  58. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.d.ts +69 -16
  59. package/dist/types/components/molecules/mg-item-more/mg-item-more.conf.d.ts +26 -0
  60. package/dist/types/components/molecules/mg-item-more/mg-item-more.d.ts +74 -0
  61. package/dist/types/components.d.ts +75 -17
  62. package/dist/types/utils/behaviors.utils.d.ts +12 -5
  63. package/dist/types/utils/components.utils.d.ts +2 -2
  64. package/dist/types/utils/unit.test.utils.d.ts +11 -0
  65. package/package.json +1 -1
  66. package/dist/mg-components/p-4cfd5423.entry.js +0 -1
@@ -28,7 +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
+ height: 3.8rem;
32
32
  }
33
33
  .mg-menu-item.mg-menu-item--size-regular .mg-menu-item__navigation-button,
34
34
  .mg-menu-item.mg-menu-item--size-regular .mg-menu-item__navigation-button ::slotted([slot=label]),
@@ -50,7 +50,7 @@
50
50
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button,
51
51
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-medium {
52
52
  padding: 1rem 3rem;
53
- height: calc(5.1rem);
53
+ height: 5.1rem;
54
54
  }
55
55
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button,
56
56
  .mg-menu-item.mg-menu-item--size-medium .mg-menu-item__navigation-button ::slotted([slot=label]),
@@ -72,7 +72,7 @@
72
72
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button,
73
73
  .mg-menu-item__navigation-button.mg-menu-item__navigation-button--size-large {
74
74
  padding: 1rem 4rem;
75
- height: calc(7.1rem);
75
+ height: 7.1rem;
76
76
  }
77
77
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button,
78
78
  .mg-menu-item.mg-menu-item--size-large .mg-menu-item__navigation-button ::slotted([slot=label]),
@@ -303,10 +303,12 @@
303
303
  margin-left: auto;
304
304
  }
305
305
 
306
- :host([data-style-direction-horizontal]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level {
306
+ :host([data-style-direction-horizontal]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level,
307
+ :host([data-overflow-more]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level {
307
308
  background-color: hsl(var(--color-light));
308
309
  }
309
- :host([data-style-direction-horizontal]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level ::slotted(mg-menu) {
310
+ :host([data-style-direction-horizontal]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level ::slotted(mg-menu),
311
+ :host([data-overflow-more]) .mg-menu-item__collapse-container.mg-menu-item__collapse-container--first-level ::slotted(mg-menu) {
310
312
  padding: 1rem 0;
311
313
  }
312
314
 
@@ -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';
@@ -34,9 +33,91 @@ export class MgMenuItem {
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,35 +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
- /**
80
- * Method to control if one of component children have active status
81
- *
82
- * @returns {boolean} truthy if component has active child
83
- */
84
- this.hasActiveChild = () => {
85
- var _a;
86
- return Array.from(((_a = this.element.querySelector('mg-menu')) === null || _a === void 0 ? void 0 : _a.children) || [])
87
- .filter(element => element.nodeName === 'MG-MENU-ITEM')
88
- .some((element) => this.hasStatus(element, Status.ACTIVE) && element.getAttribute('hidden') === null);
89
- };
90
148
  /**
91
149
  * Render slot
92
150
  *
93
151
  * @returns {HTMLElement} HTML Element
94
152
  */
95
153
  this.renderSlot = () => h("slot", null);
154
+ this.identifier = createID('mg-menu-item');
96
155
  this.href = undefined;
97
156
  this.status = Status.VISIBLE;
98
157
  this.expanded = false;
@@ -100,6 +159,7 @@ export class MgMenuItem {
100
159
  this.navigationButtonClassList = new ClassList([this.navigationButton]);
101
160
  this.direction = undefined;
102
161
  this.isInMainMenu = undefined;
162
+ this.isItemMore = undefined;
103
163
  this.hasChildren = false;
104
164
  this.displayNotificationBadge = undefined;
105
165
  }
@@ -136,11 +196,33 @@ export class MgMenuItem {
136
196
  this.navigationButtonClassList.delete(`${this.navigationButton}--size-${oldValue}`);
137
197
  this.navigationButtonClassList.add(`${this.navigationButton}--size-${newValue}`);
138
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
+ }
139
210
  validateHasChildren(newValue) {
140
211
  if (newValue && this.element.href !== undefined) {
141
212
  throw new Error(`<${this.name}> prop "href" is unauthorizied when element is a parent.`);
142
213
  }
143
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
+ }
144
226
  /*************
145
227
  * Lifecycle *
146
228
  *************/
@@ -153,11 +235,13 @@ export class MgMenuItem {
153
235
  // has children items that is NOT [slot='image' | 'information' | 'label' | 'metadata'] element
154
236
  // we store only matching elements
155
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;
156
240
  // Validate props
157
- this.validateSize(this.size);
158
241
  this.validateStatus(this.status);
159
242
  this.validateExpanded(this.expanded);
160
- this.badgeLabel = initLocales(this.element).messages.plusMenu.badgeLabel;
243
+ // Validate states
244
+ this.validateSize(this.size);
161
245
  }
162
246
  /**
163
247
  * Check if component slots configuration
@@ -165,63 +249,38 @@ export class MgMenuItem {
165
249
  * @returns {ReturnType<typeof setTimeout>} timeout
166
250
  */
167
251
  componentDidLoad() {
168
- // slot title AND metadata validation
169
- // add title on label AND metada slots due to text-overflow on these element
170
- if (Array.from(this.element.children).find(child => child.getAttribute('slot') === 'label') === undefined)
171
- throw new Error(`<${this.name}> slot "label" is required.`);
172
- ['label', 'metadata'].forEach(slot => {
173
- Array.from(this.element.querySelectorAll(`[slot="${slot}"]`)).forEach(element => {
174
- if (element.textContent.trim().length < 1)
175
- throw new Error(`<${this.name}> slot "${slot}" must have text content.`);
176
- if (element.getAttribute('title') === null)
177
- element.setAttribute('title', element.textContent);
178
- });
179
- });
252
+ // validation
253
+ this.validateSlot(true);
180
254
  // update props and states after componentDidLoad hook
181
255
  // return a promise to process action only in the FIRST render().
182
256
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
183
257
  return setTimeout(() => {
184
- var _a;
185
258
  // define menu-item context states
186
259
  const menu = this.element.closest('mg-menu');
187
- this.direction = this.element.getAttribute(OverflowBehaviorElements.MORE) !== null || menu === null ? Direction.HORIZONTAL : menu.direction;
188
- this.size = menu === null || menu === void 0 ? void 0 : menu.size;
189
- 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;
190
266
  // when main menu item contain an active item it will get the active style
191
267
  // AND if item is in vertical menu it will be expanded
192
- if (this.hasActiveChild()) {
193
- this.status = Status.ACTIVE;
194
- if (this.isInMainMenu)
195
- this.expanded = this.isDirection(Direction.VERTICAL);
196
- }
197
- // manage menu items style depending to parent menu horientation
198
- this.element.setAttribute(`data-style-direction-${this.direction}`, '');
199
- this.navigationButtonClassList.add(`${this.navigationButton}--${this.direction}`);
268
+ if (this.hasActiveChild() && this.isInMainMenu)
269
+ this.expanded = this.isDirection(Direction.VERTICAL);
270
+ this.updateStatus([Status.ACTIVE]);
200
271
  this.updateDisplayNotificationBadge();
201
- // manage all sub levels child menu-items level with data-level attribut
202
- if (this.isDirection(Direction.VERTICAL)) {
203
- Array.from(this.element.querySelectorAll('mg-menu-item')).forEach(item => {
204
- item.dataset.level = `${(Number(item.dataset.level) || 1) + 1}`;
205
- });
206
- }
207
- // manage first sub-level menu-items
208
- 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');
209
- childItems.forEach(item => {
210
- const updateStatus = () => {
211
- if (![Status.HIDDEN, Status.DISABLED].includes(this.status)) {
212
- this.status = this.hasActiveChild() ? Status.ACTIVE : Status.VISIBLE;
213
- }
214
- };
215
- // manage child menu listener
216
- item.addEventListener('status-change', () => {
217
- updateStatus();
218
- });
219
- new MutationObserver(mutationsList => {
220
- if (mutationsList.some(mutation => mutation.attributeName === 'hidden'))
221
- updateStatus();
222
- this.updateDisplayNotificationBadge();
223
- }).observe(item, { attributes: true });
224
- });
272
+ this.updatePopoverGuard();
273
+ // manage child dom changes with mutationObserver and listzners
274
+ this.initListeners();
275
+ // emit loaded event when component is fully loaded
276
+ this.itemLoaded.emit();
277
+ new MutationObserver(mutationsList => {
278
+ if (mutationsList.some(mutation => mutation.attributeName === 'hidden'))
279
+ this.updateStatus();
280
+ if (mutationsList.some(mutation => mutation.type === 'characterData'))
281
+ this.validateSlot();
282
+ this.updateDisplayNotificationBadge();
283
+ }).observe(this.element, { attributes: true, childList: true, characterData: true, subtree: true });
225
284
  }, 0);
226
285
  }
227
286
  /**
@@ -245,9 +304,9 @@ export class MgMenuItem {
245
304
  render() {
246
305
  const getContainerClasses = () => ({
247
306
  [`${this.name}__collapse-container`]: true,
248
- [`${this.name}__collapse-container--first-level`]: this.isInMainMenu && this.isDirection(Direction.HORIZONTAL),
307
+ [`${this.name}__collapse-container--first-level`]: (this.isInMainMenu || this.isItemMore) && this.isDirection(Direction.HORIZONTAL),
249
308
  });
250
- 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()))) : ([
309
+ 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()))) : ([
251
310
  this.renderInteractiveElement(),
252
311
  h("div", { key: "vertical-container", class: getContainerClasses(), hidden: !this.expanded }, this.renderSlot()),
253
312
  ])));
@@ -266,6 +325,24 @@ export class MgMenuItem {
266
325
  }
267
326
  static get properties() {
268
327
  return {
328
+ "identifier": {
329
+ "type": "string",
330
+ "mutable": false,
331
+ "complexType": {
332
+ "original": "string",
333
+ "resolved": "string",
334
+ "references": {}
335
+ },
336
+ "required": false,
337
+ "optional": false,
338
+ "docs": {
339
+ "tags": [],
340
+ "text": "Identifier is used to control mg-popover\nDefault: createID('mg-menu-item');"
341
+ },
342
+ "attribute": "identifier",
343
+ "reflect": false,
344
+ "defaultValue": "createID('mg-menu-item')"
345
+ },
269
346
  "href": {
270
347
  "type": "string",
271
348
  "mutable": false,
@@ -332,6 +409,7 @@ export class MgMenuItem {
332
409
  "navigationButtonClassList": {},
333
410
  "direction": {},
334
411
  "isInMainMenu": {},
412
+ "isItemMore": {},
335
413
  "hasChildren": {},
336
414
  "displayNotificationBadge": {}
337
415
  };
@@ -356,6 +434,21 @@ export class MgMenuItem {
356
434
  }
357
435
  }
358
436
  }
437
+ }, {
438
+ "method": "itemLoaded",
439
+ "name": "item-loaded",
440
+ "bubbles": true,
441
+ "cancelable": true,
442
+ "composed": true,
443
+ "docs": {
444
+ "tags": [],
445
+ "text": "Emited event when item is loaded"
446
+ },
447
+ "complexType": {
448
+ "original": "void",
449
+ "resolved": "void",
450
+ "references": {}
451
+ }
359
452
  }];
360
453
  }
361
454
  static get elementRef() { return "element"; }
@@ -369,6 +462,9 @@ export class MgMenuItem {
369
462
  }, {
370
463
  "propName": "size",
371
464
  "methodName": "validateSize"
465
+ }, {
466
+ "propName": "direction",
467
+ "methodName": "validateDirection"
372
468
  }, {
373
469
  "propName": "hasChildren",
374
470
  "methodName": "validateHasChildren"
@@ -141,7 +141,7 @@ export class MgForm {
141
141
  // submit buttons should trigger form submition;
142
142
  if (['submit', null].includes(mgButton.getAttribute('type'))) {
143
143
  mgButton.addEventListener('click', () => {
144
- this.form.dispatchEvent(new CustomEvent('submit', { bubbles: true }));
144
+ this.form.dispatchEvent(new SubmitEvent('submit', { bubbles: true }));
145
145
  });
146
146
  }
147
147
  });
@@ -0,0 +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
+ }
28
+ :host {
29
+ display: flex;
30
+ }
@@ -0,0 +1,200 @@
1
+ import { h, Host } from '@stencil/core';
2
+ import { initLocales } from '../../../locales';
3
+ import { OverflowBehavior } from '../../../utils/behaviors.utils';
4
+ import { Direction } from '../menu/mg-menu/mg-menu.conf';
5
+ export class MgItemMore {
6
+ constructor() {
7
+ /************
8
+ * Internal *
9
+ ************/
10
+ this.name = 'mg-item-more';
11
+ /***********
12
+ * Methods *
13
+ ***********/
14
+ /**
15
+ * render mg-item-more overflow element
16
+ *
17
+ * @returns {HTMLMgItemMoreElement} mg-item-more element
18
+ */
19
+ this.renderMgMenuItemOverflowElement = () => {
20
+ // create menu items proxy element from item clones
21
+ const moreElementMenuItem = this.element.shadowRoot.querySelector('mg-menu-item');
22
+ this.menuItems.forEach((child) => {
23
+ moreElementMenuItem.querySelector('mg-menu').appendChild(child.cloneNode(true));
24
+ });
25
+ const allMenuItem = Array.from(this.parentMenu.querySelectorAll('mg-menu-item:not([data-overflow-more])'));
26
+ Array.from(moreElementMenuItem.querySelectorAll('mg-menu-item:not([data-overflow-more])')).forEach((proxy, index) => {
27
+ // manage click on proxy to mirror it on initial element
28
+ proxy.addEventListener('click', () => {
29
+ (allMenuItem[index].shadowRoot.querySelector('a') || allMenuItem[index].shadowRoot.querySelector('button')).dispatchEvent(new MouseEvent('click', { bubbles: true }));
30
+ });
31
+ // add id suffix to prevent duplicate key. default html id is: '';
32
+ if (proxy.id.trim() !== '')
33
+ proxy.id = `${proxy.id}-proxy`;
34
+ // manage status change miror in proxy
35
+ allMenuItem[index].addEventListener('status-change', (event) => {
36
+ proxy.setAttribute('status', event.detail);
37
+ });
38
+ });
39
+ return this.element;
40
+ };
41
+ this.icon = { icon: 'ellipsis-vertical' };
42
+ this.slotlabel = { display: false };
43
+ this.size = undefined;
44
+ this.parentMenu = undefined;
45
+ }
46
+ validateIcon(newValue) {
47
+ if (typeof newValue !== 'object' || (typeof newValue === 'object' && typeof newValue.icon !== 'string'))
48
+ throw new Error(`<${this.name}> prop "icon" must match MgItemMore['icon'] type.`);
49
+ }
50
+ validateSlotLabel(newValue) {
51
+ if (typeof newValue !== 'object' || (typeof newValue === 'object' && typeof newValue.display !== 'boolean'))
52
+ throw new Error(`<${this.name}> prop "slotlabel" must match MgItemMore['slotlabel'] type.`);
53
+ else if (typeof newValue.label !== 'string')
54
+ this.slotlabel.label = this.messages.moreLabel;
55
+ }
56
+ validateSize(newValue) {
57
+ if (newValue && typeof newValue !== 'string')
58
+ throw new Error(`<${this.name}> prop "size" must match MgItemMore['size'] type.`);
59
+ }
60
+ /*************
61
+ * Lifecycle *
62
+ *************/
63
+ /**
64
+ * Disconnect overflow ResizeObserver
65
+ *
66
+ * @returns {void} run overflow resize obeserver disconnexion
67
+ */
68
+ disconnectedCallback() {
69
+ this.overflowBehavior.disconnect();
70
+ }
71
+ /**
72
+ * Set variables and validate props
73
+ *
74
+ * @returns {void}
75
+ */
76
+ componentWillLoad() {
77
+ // init variables
78
+ this.messages = initLocales(this.element).messages.plusMenu;
79
+ this.parentMenu = this.element.closest('mg-menu');
80
+ this.menuItems = Array.from(this.parentMenu.children).filter(item => item.nodeName === 'MG-MENU-ITEM');
81
+ // validate props
82
+ this.validateIcon(this.icon);
83
+ this.validateSlotLabel(this.slotlabel);
84
+ this.validateSize(this.size);
85
+ }
86
+ /**
87
+ * Add overflow behavior
88
+ *
89
+ * @returns {void}
90
+ */
91
+ componentDidLoad() {
92
+ this.overflowBehavior = new OverflowBehavior(this.parentMenu, this.renderMgMenuItemOverflowElement);
93
+ }
94
+ /**
95
+ * Render
96
+ *
97
+ * @returns {HTMLElement} HTML Element
98
+ */
99
+ render() {
100
+ return (h(Host, { role: "menuitem", "aria-haspopup": "true" }, h("mg-menu-item", { "data-overflow-more": true, "data-size": this.parentMenu.size }, h("mg-icon", { icon: this.icon.icon, slot: "image" }), h("span", { class: { 'sr-only': !this.slotlabel.display }, slot: "label" }, this.slotlabel.label), h("mg-menu", { direction: Direction.VERTICAL, label: this.messages.moreLabel, size: this.size }))));
101
+ }
102
+ static get is() { return "mg-item-more"; }
103
+ static get encapsulation() { return "shadow"; }
104
+ static get originalStyleUrls() {
105
+ return {
106
+ "$": ["mg-item-more.scss"]
107
+ };
108
+ }
109
+ static get styleUrls() {
110
+ return {
111
+ "$": ["mg-item-more.css"]
112
+ };
113
+ }
114
+ static get properties() {
115
+ return {
116
+ "icon": {
117
+ "type": "unknown",
118
+ "mutable": false,
119
+ "complexType": {
120
+ "original": "IconType",
121
+ "resolved": "{ icon: string; }",
122
+ "references": {
123
+ "IconType": {
124
+ "location": "import",
125
+ "path": "./mg-item-more.conf"
126
+ }
127
+ }
128
+ },
129
+ "required": false,
130
+ "optional": false,
131
+ "docs": {
132
+ "tags": [],
133
+ "text": "Define icon\nDefault: {icon: 'ellipsis-vertical'}"
134
+ },
135
+ "defaultValue": "{ icon: 'ellipsis-vertical' }"
136
+ },
137
+ "slotlabel": {
138
+ "type": "unknown",
139
+ "mutable": false,
140
+ "complexType": {
141
+ "original": "SlotLabelType",
142
+ "resolved": "{ label?: string; display?: boolean; }",
143
+ "references": {
144
+ "SlotLabelType": {
145
+ "location": "import",
146
+ "path": "./mg-item-more.conf"
147
+ }
148
+ }
149
+ },
150
+ "required": false,
151
+ "optional": false,
152
+ "docs": {
153
+ "tags": [],
154
+ "text": "Define slot label element\nDefault: {display: false}"
155
+ },
156
+ "defaultValue": "{ display: false }"
157
+ },
158
+ "size": {
159
+ "type": "string",
160
+ "mutable": false,
161
+ "complexType": {
162
+ "original": "SizeType",
163
+ "resolved": "\"large\" | \"medium\" | \"regular\"",
164
+ "references": {
165
+ "SizeType": {
166
+ "location": "import",
167
+ "path": "./mg-item-more.conf"
168
+ }
169
+ }
170
+ },
171
+ "required": false,
172
+ "optional": false,
173
+ "docs": {
174
+ "tags": [],
175
+ "text": "Define component child menu size."
176
+ },
177
+ "attribute": "size",
178
+ "reflect": false
179
+ }
180
+ };
181
+ }
182
+ static get states() {
183
+ return {
184
+ "parentMenu": {}
185
+ };
186
+ }
187
+ static get elementRef() { return "element"; }
188
+ static get watchers() {
189
+ return [{
190
+ "propName": "icon",
191
+ "methodName": "validateIcon"
192
+ }, {
193
+ "propName": "slotlabel",
194
+ "methodName": "validateSlotLabel"
195
+ }, {
196
+ "propName": "size",
197
+ "methodName": "validateSize"
198
+ }];
199
+ }
200
+ }
@@ -1,7 +1,6 @@
1
1
  .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button,
2
2
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular {
3
3
  padding: 1rem 2rem;
4
- height: calc();
5
4
  }
6
5
  .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button,
7
6
  .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button ::slotted([slot=label]),
@@ -23,7 +22,6 @@
23
22
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button,
24
23
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large {
25
24
  padding: 1.5rem 3rem;
26
- height: calc();
27
25
  }
28
26
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button,
29
27
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button ::slotted([slot=label]),
@@ -9,7 +9,7 @@ $navigation-button-column-gap: 1rem;
9
9
  .#{$element}.#{$element}--size-#{$name} .#{$element}__navigation-button,
10
10
  .#{$element}__navigation-button.#{$element}__navigation-button--size-#{$name} {
11
11
  padding: #{map.get($size, 'vertical')} #{map.get($size, 'horizontal')};
12
- height: calc(#{map.get($size, 'height')});
12
+ height: #{map.get($size, 'height')};
13
13
  &,
14
14
  ::slotted([slot='label']),
15
15
  ::slotted([slot='metadata']) {