@mgdis/mg-components 5.1.0 → 5.3.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 (108) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/{mg-badge_27.cjs.entry.js → mg-badge_29.cjs.entry.js} +730 -242
  3. package/dist/cjs/mg-components.cjs.js +1 -1
  4. package/dist/collection/collection-manifest.json +3 -1
  5. package/dist/collection/components/atoms/mg-badge/mg-badge.js +14 -19
  6. package/dist/collection/components/atoms/mg-button/mg-button.js +3 -3
  7. package/dist/collection/components/atoms/mg-icon/mg-icon.js +17 -7
  8. package/dist/collection/components/atoms/mg-tag/mg-tag.js +1 -1
  9. package/dist/collection/components/molecules/inputs/MgInput.js +3 -11
  10. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +41 -20
  11. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +50 -39
  12. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.css +25 -6
  13. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.js +42 -33
  14. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.css +25 -6
  15. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.js +36 -17
  16. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.js +35 -14
  17. package/dist/collection/components/molecules/inputs/mg-input-select/doc/mg-input-select.stories.js +2 -3
  18. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.css +28 -6
  19. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +36 -17
  20. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.css +25 -6
  21. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.js +38 -19
  22. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.css +25 -6
  23. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.js +37 -18
  24. package/dist/collection/components/molecules/inputs/mg-input-toggle/mg-input-toggle.js +1 -1
  25. package/dist/collection/components/molecules/menu/mg-menu/doc/mg-menu.stories.js +87 -0
  26. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.conf.js +8 -0
  27. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.css +10 -0
  28. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.js +185 -0
  29. package/dist/collection/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.js +32 -0
  30. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.conf.js +22 -0
  31. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.css +316 -0
  32. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.js +324 -0
  33. package/dist/collection/components/molecules/mg-form/mg-form.js +73 -27
  34. package/dist/collection/components/molecules/mg-illustrated-message/doc/mg-illustrated-message.stories.js +6 -6
  35. package/dist/collection/components/molecules/mg-message/mg-message.js +1 -1
  36. package/dist/collection/components/molecules/mg-modal/mg-modal.js +0 -4
  37. package/dist/collection/components/molecules/mg-tabs/mg-tabs.conf.js +3 -0
  38. package/dist/collection/components/molecules/mg-tabs/mg-tabs.css +67 -17
  39. package/dist/collection/components/molecules/mg-tabs/mg-tabs.js +10 -4
  40. package/dist/collection/locales/index.js +3 -1
  41. package/dist/collection/utils/unit.test.utils.js +51 -0
  42. package/dist/collection/variables.css +29 -7
  43. package/dist/components/MgInput.js +4 -12
  44. package/dist/components/index.d.ts +2 -0
  45. package/dist/components/index.js +2 -0
  46. package/dist/components/index2.js +3 -1
  47. package/dist/components/mg-badge2.js +1 -1
  48. package/dist/components/mg-button2.js +3 -3
  49. package/dist/components/mg-form.js +67 -26
  50. package/dist/components/mg-input-checkbox.js +36 -21
  51. package/dist/components/mg-input-date.js +44 -39
  52. package/dist/components/mg-input-numeric.js +37 -34
  53. package/dist/components/mg-input-password.js +32 -19
  54. package/dist/components/mg-input-radio.js +30 -15
  55. package/dist/components/mg-input-select2.js +32 -19
  56. package/dist/components/mg-input-text2.js +34 -21
  57. package/dist/components/mg-input-textarea.js +32 -19
  58. package/dist/components/mg-input-toggle.js +1 -1
  59. package/dist/components/mg-menu-item.d.ts +11 -0
  60. package/dist/components/mg-menu-item.js +273 -0
  61. package/dist/components/mg-menu.conf.js +10 -0
  62. package/dist/components/mg-menu.d.ts +11 -0
  63. package/dist/components/mg-menu.js +149 -0
  64. package/dist/components/mg-message.js +1 -1
  65. package/dist/components/mg-modal.js +0 -4
  66. package/dist/components/mg-tabs.js +6 -2
  67. package/dist/components/mg-tag.js +1 -1
  68. package/dist/esm/loader.js +1 -1
  69. package/dist/esm/{mg-badge_27.entry.js → mg-badge_29.entry.js} +729 -243
  70. package/dist/esm/mg-components.js +1 -1
  71. package/dist/mg-components/mg-components.css +1 -1
  72. package/dist/mg-components/mg-components.esm.js +1 -1
  73. package/dist/mg-components/p-204af46f.entry.js +1 -0
  74. package/dist/mg-components/variables.css +29 -7
  75. package/dist/types/components/atoms/mg-badge/doc/mg-badge.stories.d.ts +2 -2
  76. package/dist/types/components/atoms/mg-badge/mg-badge.conf.d.ts +5 -5
  77. package/dist/types/components/atoms/mg-badge/mg-badge.d.ts +8 -8
  78. package/dist/types/components/atoms/mg-button/mg-button.d.ts +2 -2
  79. package/dist/types/components/atoms/mg-icon/doc/mg-icon.stories.d.ts +2 -2
  80. package/dist/types/components/atoms/mg-icon/mg-icon.conf.d.ts +10 -2
  81. package/dist/types/components/atoms/mg-icon/mg-icon.d.ts +7 -6
  82. package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.d.ts +10 -8
  83. package/dist/types/components/molecules/inputs/mg-input-date/mg-input-date.d.ts +3 -8
  84. package/dist/types/components/molecules/inputs/mg-input-numeric/mg-input-numeric.d.ts +3 -8
  85. package/dist/types/components/molecules/inputs/mg-input-password/mg-input-password.d.ts +4 -3
  86. package/dist/types/components/molecules/inputs/mg-input-radio/mg-input-radio.d.ts +4 -2
  87. package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.d.ts +4 -3
  88. package/dist/types/components/molecules/inputs/mg-input-text/mg-input-text.d.ts +5 -4
  89. package/dist/types/components/molecules/inputs/mg-input-textarea/mg-input-textarea.d.ts +4 -3
  90. package/dist/types/components/molecules/menu/mg-menu/doc/mg-menu.stories.d.ts +17 -0
  91. package/dist/types/components/molecules/menu/mg-menu/mg-menu.conf.d.ts +7 -0
  92. package/dist/types/components/molecules/menu/mg-menu/mg-menu.d.ts +69 -0
  93. package/dist/types/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.d.ts +11 -0
  94. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.conf.d.ts +24 -0
  95. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.d.ts +119 -0
  96. package/dist/types/components/molecules/mg-form/mg-form.d.ts +21 -1
  97. package/dist/types/components/molecules/mg-message/mg-message.d.ts +3 -0
  98. package/dist/types/components/molecules/mg-modal/mg-modal.d.ts +3 -0
  99. package/dist/types/components/molecules/mg-tabs/doc/mg-tabs.stories.d.ts +1 -1
  100. package/dist/types/components/molecules/mg-tabs/mg-tabs.conf.d.ts +12 -4
  101. package/dist/types/components/molecules/mg-tabs/mg-tabs.d.ts +6 -6
  102. package/dist/types/components.d.ts +91 -14
  103. package/dist/types/locales/index.d.ts +7 -1
  104. package/dist/types/stories/icons.stories.d.ts +1 -1
  105. package/package.json +7 -8
  106. package/dist/collection/utils/test.utils.js +0 -38
  107. package/dist/mg-components/p-e131701a.entry.js +0 -1
  108. package/dist/types/utils/test.utils.d.ts +0 -17
@@ -3,6 +3,8 @@ import { createID, ClassList } from '../../../utils/components.utils';
3
3
  import { initLocales } from '../../../locales';
4
4
  export class MgForm {
5
5
  constructor() {
6
+ // Classes
7
+ this.classAllRequired = 'mg-form--all-required';
6
8
  /**
7
9
  * Identifier is used for the element ID (id is a reserved prop in Stencil.js)
8
10
  * If not set, it will be created.
@@ -32,17 +34,24 @@ export class MgForm {
32
34
  * @returns {void}
33
35
  */
34
36
  this.setRequiredMessage = () => {
35
- // Get required fields
36
- const requiredInputs = this.mgInputs.filter(input => input.required && !input.disabled && !this.disabled);
37
- // All fields are required
38
- // mg-input-toggle can not be required
39
- if (requiredInputs.length > 0 && requiredInputs.length === this.mgInputs.filter(input => input.nodeName !== 'MG-INPUT-TOGGLE').length) {
40
- this.requiredMessage = this.messages.form.allRequired;
41
- this.classList.add('mg-form--all-required');
42
- }
43
- // Some fields are required
44
- else if (requiredInputs.length > 0) {
45
- this.requiredMessage = this.messages.form.required;
37
+ // init required message
38
+ this.requiredMessage = null;
39
+ this.classList.delete(this.classAllRequired);
40
+ // If the form is disabled or readonly none of them are required
41
+ // Check if all fields are not editable (readonly or disabled)
42
+ if (!this.disabled && !this.readonly && !this.mgInputs.every(input => input.disabled || input.readonly)) {
43
+ // Get required fields
44
+ const requiredInputs = this.mgInputs.filter(input => input.required && !input.disabled && !input.readonly);
45
+ // All fields are required
46
+ // mg-input-toggle can not be required
47
+ if (requiredInputs.length > 0 && requiredInputs.length === this.mgInputs.filter(input => input.nodeName !== 'MG-INPUT-TOGGLE').length) {
48
+ this.requiredMessage = this.messages.form.allRequired;
49
+ this.classList.add(this.classAllRequired);
50
+ }
51
+ // Some fields are required
52
+ else if (requiredInputs.length > 0) {
53
+ this.requiredMessage = this.messages.form.required;
54
+ }
46
55
  }
47
56
  };
48
57
  /**
@@ -51,15 +60,46 @@ export class MgForm {
51
60
  * @returns {void}
52
61
  */
53
62
  this.checkValidity = () => {
54
- const validity = !this.mgInputs.some(input => input.invalid);
55
- this.valid = validity;
56
- this.invalid = !validity;
57
- this.formValid.emit(validity);
63
+ // Update required on input event
64
+ this.setRequiredMessage();
65
+ this.valid = !this.mgInputs.some(input => input.invalid);
66
+ this.invalid = !this.valid;
67
+ // We need to send valid event if it is the same value
68
+ this.formValid.emit(this.valid);
58
69
  };
70
+ /**
71
+ * Handle Form Submit
72
+ *
73
+ * @param {SubmitEvent} event submit event
74
+ * @returns {void}
75
+ */
59
76
  this.handleFormSubmit = (event) => {
60
77
  event.preventDefault();
61
78
  this.formSubmit.emit();
62
79
  };
80
+ /**
81
+ * Set mgInputs
82
+ *
83
+ * @returns {void}
84
+ */
85
+ this.setMgInputs = () => {
86
+ // Get slotted mgInputs
87
+ this.mgInputs = Array.from(this.element.querySelectorAll('*')).filter((node) => node.nodeName.startsWith('MG-INPUT-'));
88
+ // Set inputs readonly or disabled based on form configuration
89
+ // Othewise listen to events
90
+ this.mgInputs.map(input => {
91
+ if (this.readonly)
92
+ input.readonly = true;
93
+ else if (this.disabled)
94
+ input.disabled = true;
95
+ else
96
+ input.addEventListener('input-valid', this.checkValidity);
97
+ });
98
+ };
99
+ }
100
+ handleAttributeChange() {
101
+ this.setMgInputs();
102
+ this.setRequiredMessage();
63
103
  }
64
104
  /**
65
105
  * Public method to display errors
@@ -85,26 +125,18 @@ export class MgForm {
85
125
  componentWillLoad() {
86
126
  // Get locales
87
127
  this.messages = initLocales(this.element).messages;
88
- // Get slotted mgInputs
89
- this.mgInputs = Array.from(this.element.querySelectorAll('*')).filter((node) => node.nodeName.startsWith('MG-INPUT-'));
90
128
  // Get slotted mgButtons
91
- this.mgButtons = Array.from(this.element.querySelectorAll('*')).filter((node) => node.nodeName.startsWith('MG-BUTTON'));
129
+ this.mgButtons = Array.from(this.element.querySelectorAll('mg-button'));
92
130
  // Set button form identifier
93
131
  this.mgButtons.forEach(mgButton => {
94
132
  mgButton.setAttribute('form', this.identifier);
95
133
  });
134
+ // Set mgInputs
135
+ this.setMgInputs();
96
136
  // Define required message
97
137
  this.setRequiredMessage();
98
138
  // Check validity when slotted mgInputs are ready
99
139
  Promise.all(this.mgInputs.map(async (input) => {
100
- // Set inputs readonly or disabled based on form configuration
101
- // Othewise listen to events
102
- if (this.readonly)
103
- input.readonly = true;
104
- else if (this.disabled)
105
- input.disabled = true;
106
- else
107
- input.addEventListener('input-valid', this.checkValidity);
108
140
  try {
109
141
  await input.componentOnReady();
110
142
  }
@@ -127,6 +159,10 @@ export class MgForm {
127
159
  });
128
160
  }
129
161
  });
162
+ // Update mgInputs when mgForm content change
163
+ new MutationObserver(() => {
164
+ this.setMgInputs();
165
+ }).observe(this.element, { childList: true });
130
166
  }
131
167
  /**
132
168
  * Render
@@ -260,7 +296,8 @@ export class MgForm {
260
296
  }
261
297
  static get states() {
262
298
  return {
263
- "classList": {}
299
+ "classList": {},
300
+ "requiredMessage": {}
264
301
  };
265
302
  }
266
303
  static get events() {
@@ -320,4 +357,13 @@ export class MgForm {
320
357
  };
321
358
  }
322
359
  static get elementRef() { return "element"; }
360
+ static get watchers() {
361
+ return [{
362
+ "propName": "readonly",
363
+ "methodName": "handleAttributeChange"
364
+ }, {
365
+ "propName": "disabled",
366
+ "methodName": "handleAttributeChange"
367
+ }];
368
+ }
323
369
  }
@@ -5,13 +5,13 @@ export default {
5
5
  title: 'Molecules/mg-illustrated-message',
6
6
  };
7
7
  /**
8
- * 1. camelCase arguments must be written in the template, for exemple labelOnTop must be placed in the template as label-on-top={args.labelOnTop}
9
- * 2. boolean arguments with a default true value must be added like display-character-left={args.displayCharacterLeft ? 'true' : 'false'}
8
+ * Template
9
+ *
10
+ * @param {any} args component arguments
11
+ * @returns {HTMLElement} HTMLElement
10
12
  */
11
- const Template = args => {
12
- // return element
13
- return (h("mg-illustrated-message", Object.assign({}, filterArgs(args, { size: 'regular', direction: 'vertical' })), h("svg", { slot: "illustration", width: "190", height: "350", viewBox: "0 0 190 350", xmlns: "http://www.w3.org/2000/svg" }, h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M0 0H15C23.2843 0 30 6.71573 30 15V290H40V15C40 6.71573 46.7157 0 55 0C63.2843 0 70 6.71573 70 15V275C70 277.761 67.7615 280 65 280H60V40H50V340H60V290H65C67.7615 290 70 292.239 70 295V340H80V295C80 291.158 78.5558 287.654 76.1805 285C78.5558 282.346 80 278.842 80 275V0H95C103.284 0 110 6.71573 110 15V25C110 28.8418 108.556 32.3462 106.181 35C108.556 37.6538 110 41.1582 110 45V305C110 307.761 107.761 310 105 310H100V45C100 42.2386 97.7615 40 95 40H90V325C90 333.284 96.7157 340 105 340H120V330H105C102.239 330 100 327.761 100 325V320H105C113.284 320 120 313.284 120 305V15C120 6.71573 126.716 0 135 0C143.284 0 150 6.71573 150 15V330H140V15C140 12.2386 137.761 10 135 10C132.239 10 130 12.2386 130 15V340H165C173.284 340 180 333.284 180 325V15C180 12.2386 177.761 10 175 10H170V325C170 327.761 167.761 330 165 330H160V0H175C183.284 0 190 6.71573 190 15V350H0V0ZM10 325C10 333.284 16.7157 340 25 340C33.2843 340 40 333.284 40 325V300H30V325C30 327.761 27.7615 330 25 330C22.2385 330 20 327.761 20 325V15C20 12.2386 17.7615 10 15 10H10V325ZM60 15V30H50V15C50 12.2386 52.2385 10 55 10C57.7615 10 60 12.2386 60 15ZM95 30H90V10H95C97.7615 10 100 12.2386 100 15V25C100 27.7614 97.7615 30 95 30Z", fill: "black" })), h("h2", { slot: "title" }, "Lorem Ipsum"), h("h3", { slot: "details" }, "The standard Lorem Ipsum passage, used since the 1500s"), h("div", { slot: "details" }, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")));
14
- };
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ const Template = (args) => (h("mg-illustrated-message", Object.assign({}, filterArgs(args, { size: 'regular', direction: 'vertical' })), h("svg", { slot: "illustration", width: "190", height: "350", viewBox: "0 0 190 350", xmlns: "http://www.w3.org/2000/svg" }, h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M0 0H15C23.2843 0 30 6.71573 30 15V290H40V15C40 6.71573 46.7157 0 55 0C63.2843 0 70 6.71573 70 15V275C70 277.761 67.7615 280 65 280H60V40H50V340H60V290H65C67.7615 290 70 292.239 70 295V340H80V295C80 291.158 78.5558 287.654 76.1805 285C78.5558 282.346 80 278.842 80 275V0H95C103.284 0 110 6.71573 110 15V25C110 28.8418 108.556 32.3462 106.181 35C108.556 37.6538 110 41.1582 110 45V305C110 307.761 107.761 310 105 310H100V45C100 42.2386 97.7615 40 95 40H90V325C90 333.284 96.7157 340 105 340H120V330H105C102.239 330 100 327.761 100 325V320H105C113.284 320 120 313.284 120 305V15C120 6.71573 126.716 0 135 0C143.284 0 150 6.71573 150 15V330H140V15C140 12.2386 137.761 10 135 10C132.239 10 130 12.2386 130 15V340H165C173.284 340 180 333.284 180 325V15C180 12.2386 177.761 10 175 10H170V325C170 327.761 167.761 330 165 330H160V0H175C183.284 0 190 6.71573 190 15V350H0V0ZM10 325C10 333.284 16.7157 340 25 340C33.2843 340 40 333.284 40 325V300H30V325C30 327.761 27.7615 330 25 330C22.2385 330 20 327.761 20 325V15C20 12.2386 17.7615 10 15 10H10V325ZM60 15V30H50V15C50 12.2386 52.2385 10 55 10C57.7615 10 60 12.2386 60 15ZM95 30H90V10H95C97.7615 10 100 12.2386 100 15V25C100 27.7614 97.7615 30 95 30Z", fill: "black" })), h("h2", { slot: "title" }, "Lorem Ipsum"), h("h3", { slot: "details" }, "The standard Lorem Ipsum passage, used since the 1500s"), h("div", { slot: "details" }, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")));
15
15
  export const MgIllustratedMessage = Template.bind({});
16
16
  MgIllustratedMessage.args = {
17
17
  size: 'regular',
@@ -7,7 +7,7 @@ export class MgMessage {
7
7
  /************
8
8
  * Internal *
9
9
  ************/
10
- // classes
10
+ // Classes
11
11
  this.classHide = 'mg-message--hide';
12
12
  // IDs
13
13
  this.closeButtonId = '';
@@ -135,10 +135,6 @@ export class MgModal {
135
135
  */
136
136
  componentDidLoad() {
137
137
  new MutationObserver(mutationList => {
138
- /*
139
- TODO find a way to cover this callback
140
- */
141
- /* istanbul ignore next */
142
138
  if (mutationList.some(mutation => mutation.attributeName === 'aria-hidden' && mutation.target.ariaHidden === null)) {
143
139
  this.setFocus();
144
140
  }
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Available tabs items status
3
+ */
1
4
  export var Status;
2
5
  (function (Status) {
3
6
  Status["VISIBLE"] = "visible";
@@ -1,45 +1,95 @@
1
- .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button {
2
- padding: calc(1rem + 0.3rem) calc(1rem * 1.3) 1rem;
1
+ .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button,
2
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular {
3
+ padding: 1rem 2rem;
3
4
  }
4
-
5
- .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button {
6
- padding: calc(1.8rem + 0.3rem) calc(1.8rem * 1.3) 1.8rem;
5
+ .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button,
6
+ .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button ::slotted([slot=label]),
7
+ .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button ::slotted([slot=metadata]),
8
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular,
9
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular ::slotted([slot=label]),
10
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular ::slotted([slot=metadata]) {
11
+ font-size: 1.3rem;
12
+ }
13
+ .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button.mg-tabs__navigation-button--horizontal,
14
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular.mg-tabs__navigation-button--horizontal {
15
+ padding-bottom: calc(1rem - 0.3rem);
16
+ }
17
+ .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button.mg-tabs__navigation-button--vertical,
18
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular.mg-tabs__navigation-button--vertical {
19
+ padding-left: calc(2rem - 0.3rem);
7
20
  }
8
21
 
9
- .mg-tabs__header {
10
- display: flex;
11
- flex-direction: row;
12
- flex-wrap: wrap;
22
+ .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button,
23
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large {
24
+ padding: 1.5rem 3rem;
25
+ }
26
+ .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button,
27
+ .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button ::slotted([slot=label]),
28
+ .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button ::slotted([slot=metadata]),
29
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large,
30
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large ::slotted([slot=label]),
31
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large ::slotted([slot=metadata]) {
32
+ font-size: 1.5rem;
33
+ }
34
+ .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button.mg-tabs__navigation-button--horizontal,
35
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large.mg-tabs__navigation-button--horizontal {
36
+ padding-bottom: calc(1.5rem - 0.3rem);
37
+ }
38
+ .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button.mg-tabs__navigation-button--vertical,
39
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large.mg-tabs__navigation-button--vertical {
40
+ padding-left: calc(3rem - 0.3rem);
13
41
  }
14
42
 
15
43
  .mg-tabs__navigation-button {
16
44
  display: flex;
17
45
  align-items: center;
18
- column-gap: 0.5rem;
19
- background: none;
46
+ column-gap: 1rem;
47
+ background-color: unset;
20
48
  border: none;
21
- border-bottom: 0.3rem solid transparent;
22
49
  font-family: var(--font-family);
23
- color: hsl(var(--color-dark));
50
+ color: hsl(var(--mg-tabs-color-hsl, var(--color-dark)));
24
51
  line-height: var(--line-height);
52
+ text-decoration: none;
25
53
  cursor: pointer;
26
54
  }
27
55
  .mg-tabs__navigation-button:disabled, .mg-tabs__navigation-button--disabled {
28
56
  cursor: default;
29
57
  opacity: 30%;
30
58
  }
31
- .mg-tabs__navigation-button:hover:not(:disabled), .mg-tabs__navigation-button:focus:not(:disabled) {
32
- background-color: hsla(var(--color-info-h), var(--color-info-s), var(--color-info-l), 10%);
59
+ .mg-tabs__navigation-button:focus-visible {
60
+ z-index: 10;
61
+ }
62
+ .mg-tabs__navigation-button:hover:not(.mg-tabs__navigation-button--disabled), .mg-tabs__navigation-button:focus:not(.mg-tabs__navigation-button--disabled) {
63
+ background-color: hsla(var(--mg-tabs-focused-background-color-hsl), 10%);
33
64
  }
34
65
  .mg-tabs__navigation-button.mg-tabs__navigation-button--active {
35
- color: hsl(var(--color-info));
36
- border-bottom-color: hsl(var(--color-info));
66
+ color: hsl(var(--mg-tabs-color-active-hsl));
37
67
  font-weight: 700;
38
68
  }
69
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--active.mg-tabs__navigation-button--horizontal {
70
+ border-bottom-color: hsl(var(--mg-tabs-border-color-active-hsl));
71
+ }
72
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--active.mg-tabs__navigation-button--vertical {
73
+ border-left-color: hsl(var(--mg-tabs-border-color-active-hsl));
74
+ }
39
75
  .mg-tabs__navigation-button.mg-tabs__navigation-button--hidden {
40
76
  display: none;
41
77
  }
78
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--horizontal {
79
+ border-bottom: 0.3rem solid transparent;
80
+ }
81
+ .mg-tabs__navigation-button.mg-tabs__navigation-button--vertical {
82
+ border-left: 0.3rem solid transparent;
83
+ }
42
84
 
85
+ .mg-tabs__header {
86
+ display: flex;
87
+ flex-direction: row;
88
+ flex-wrap: wrap;
89
+ }
43
90
  .mg-tabs__content-container:focus-visible {
44
91
  outline: none;
92
+ }
93
+ .mg-tabs__navigation-button-text {
94
+ flex: 0 0 content;
45
95
  }
@@ -185,10 +185,11 @@ export class MgTabs {
185
185
  render() {
186
186
  return (h("div", { class: this.classList.join() }, h("header", { role: "tablist", "aria-label": this.label, class: "mg-tabs__header" }, this.tabs.map((tab, index) => (h("button", { role: "tab", id: this.getElementId(this.identifier, index), class: {
187
187
  [`${this.buttonTabBaseClass}`]: true,
188
+ [`${this.buttonTabBaseClass}--horizontal`]: true,
188
189
  [`${this.getNavigationButtonClass(Status.ACTIVE)}`]: this.tabHasGivenStatus(tab, Status.ACTIVE),
189
190
  [`${this.getNavigationButtonClass(Status.DISABLED)}`]: this.tabHasGivenStatus(tab, Status.DISABLED),
190
191
  [`${this.getNavigationButtonClass(Status.HIDDEN)}`]: this.tabHasGivenStatus(tab, Status.HIDDEN),
191
- }, tabindex: this.tabHasGivenStatus(tab, Status.ACTIVE) ? 0 : -1, "aria-selected": this.tabHasGivenStatus(tab, Status.ACTIVE).toString(), "aria-controls": this.getElementId(this.tabPanel, index), onClick: this.handleClick, onKeyDown: this.handleKeydown, "data-index": this.getTabIndex(index), disabled: this.tabHasGivenStatus(tab, Status.DISABLED) }, tab.icon !== undefined && h("mg-icon", { icon: tab.icon }), tab.label, tab.badge !== undefined && h("mg-badge", { variant: "info", value: tab.badge.value, label: tab.badge.label }))))), this.tabs.map((tab, index) => (h("article", { role: "tabpanel", id: this.getElementId(this.tabPanel, index), hidden: !this.tabHasGivenStatus(tab, Status.ACTIVE), "aria-labelledby": this.getElementId(this.identifier, index), tabindex: this.tabHasGivenStatus(tab, Status.ACTIVE) ? 0 : -1, class: "mg-tabs__content-container" }, h("slot", { name: this.getElementId('tab_content', index) }))))));
192
+ }, tabindex: this.tabHasGivenStatus(tab, Status.ACTIVE) ? 0 : -1, "aria-selected": this.tabHasGivenStatus(tab, Status.ACTIVE).toString(), "aria-controls": this.getElementId(this.tabPanel, index), onClick: this.handleClick, onKeyDown: this.handleKeydown, "data-index": this.getTabIndex(index), disabled: this.tabHasGivenStatus(tab, Status.DISABLED) }, tab.icon !== undefined && h("mg-icon", { icon: tab.icon }), tab.label, tab.badge !== undefined && h("mg-badge", { variant: tab.status !== Status.ACTIVE ? 'primary' : 'info', value: tab.badge.value, label: tab.badge.label }))))), this.tabs.map((tab, index) => (h("article", { role: "tabpanel", id: this.getElementId(this.tabPanel, index), hidden: !this.tabHasGivenStatus(tab, Status.ACTIVE), "aria-labelledby": this.getElementId(this.identifier, index), tabindex: this.tabHasGivenStatus(tab, Status.ACTIVE) ? 0 : -1, class: "mg-tabs__content-container" }, h("slot", { name: this.getElementId('tab_content', index) }))))));
192
193
  }
193
194
  static get is() { return "mg-tabs"; }
194
195
  static get encapsulation() { return "shadow"; }
@@ -243,9 +244,14 @@ export class MgTabs {
243
244
  "type": "string",
244
245
  "mutable": false,
245
246
  "complexType": {
246
- "original": "string",
247
- "resolved": "string",
248
- "references": {}
247
+ "original": "SizeType",
248
+ "resolved": "\"large\" | \"regular\"",
249
+ "references": {
250
+ "SizeType": {
251
+ "location": "import",
252
+ "path": "./mg-tabs.conf"
253
+ }
254
+ }
249
255
  },
250
256
  "required": false,
251
257
  "optional": false,
@@ -10,7 +10,9 @@ const messages = { en, fr };
10
10
  */
11
11
  const getLocale = (element) => {
12
12
  var _a;
13
- return ((_a = element.closest('[lang]')) === null || _a === void 0 ? void 0 : _a.lang) || navigator.language || defaultLocale;
13
+ // validate locale
14
+ const closestLang = Intl.NumberFormat.supportedLocalesOf((_a = element.closest('[lang]')) === null || _a === void 0 ? void 0 : _a.lang);
15
+ return closestLang.length > 0 ? closestLang[0] : navigator.language || defaultLocale;
14
16
  };
15
17
  /**
16
18
  * Get Intl object
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Clone Deep function
3
+ *
4
+ * @param {unknown} obj object to clone
5
+ * @returns {unknown} cloned json
6
+ */
7
+ export const cloneDeep = (obj) => JSON.parse(JSON.stringify(obj));
8
+ /**
9
+ * Utility function that mocks the `MutationObserver` API. Recommended to execute inside `beforeEach`.
10
+ *
11
+ * @param mutationObserverMock - Parameter that is sent to the `Object.defineProperty`
12
+ * overwrite method. `jest.fn()` mock functions can be passed here if the goal is to not only
13
+ * mock the resize observer, but its methods.
14
+ * You can manually fire an intersection entry:
15
+ * @param {Function} mutationObserverMock.disconnect disconnect function
16
+ * @param {Function} mutationObserverMock.observe observe fnuction
17
+ * @param {Function} mutationObserverMock.takeRecords takeRecords fnuction
18
+ * @returns {MutationObserver} Mocked MutationObserver
19
+ * @example
20
+ * ```
21
+ * let fireMo;
22
+ * setupMutationObserverMock({
23
+ * observe: function () {
24
+ * fireMo = this.cb;
25
+ * },
26
+ * });
27
+ * ...
28
+ * fireMo([{ type: 'childList', addedNodes: [AMockElemenet, AnotherMockElemenet], target: yourMockElemenet }]);;
29
+ * ```
30
+ */
31
+ export const setupMutationObserverMock = ({ disconnect, observe, takeRecords }) => {
32
+ class MockMutationObserver {
33
+ constructor(fn) {
34
+ this.disconnect = disconnect;
35
+ this.observe = observe;
36
+ this.takeRecords = takeRecords;
37
+ this.cb = fn;
38
+ }
39
+ }
40
+ Object.defineProperty(window, 'MutationObserver', {
41
+ writable: true,
42
+ configurable: true,
43
+ value: MockMutationObserver,
44
+ });
45
+ Object.defineProperty(global, 'MutationObserver', {
46
+ writable: true,
47
+ configurable: true,
48
+ value: MockMutationObserver,
49
+ });
50
+ return MockMutationObserver;
51
+ };
@@ -20,6 +20,13 @@
20
20
  https://jira.mgdis.fr/browse/PDA9-690
21
21
  */
22
22
 
23
+ /* App */
24
+ /* default color-info */
25
+ --mg-color-app-h: var(--color-info-h);
26
+ --mg-color-app-s: var(--color-info-s);
27
+ --mg-color-app-l: var(--color-info-l);
28
+ --mg-color-app-hsl: var(--mg-color-app-h), var(--mg-color-app-s), var(--mg-color-app-l);
29
+
23
30
  /* Neutral */
24
31
  /* #fefefe; */
25
32
  /* rgb(254, 254, 254); */
@@ -77,15 +84,15 @@
77
84
  --color-light: var(--color-light-h), var(--color-light-s), var(--color-light-l);
78
85
 
79
86
  /* Primary */
80
- --color-primary-h: hsl(var(--color-dark-h));
81
- --color-primary-s: hsl(var(--color-dark-s));
82
- --color-primary-l: hsl(var(--color-dark-l));
87
+ --color-primary-h: var(--color-dark-h);
88
+ --color-primary-s: var(--color-dark-s);
89
+ --color-primary-l: var(--color-dark-l);
83
90
  --color-primary: hsl(var(--color-dark));
84
91
 
85
92
  /* Secondary */
86
- --color-secondary-h: hsl(var(--color-neutral-h));
87
- --color-secondary-s: hsl(var(--color-neutral-s));
88
- --color-secondary-l: hsl(var(--color-neutral-l));
93
+ --color-secondary-h: var(--color-neutral-h);
94
+ --color-secondary-s: var(--color-neutral-s);
95
+ --color-secondary-l: var(--color-neutral-l);
89
96
  --color-secondary: hsl(var(--color-neutral));
90
97
 
91
98
  /* Shadow */
@@ -173,9 +180,10 @@
173
180
  --mg-panel-box-shadow: var(--box-shadow);
174
181
  --mg-panel-content-padding: 1.5rem;
175
182
 
176
- /*
183
+ /*
177
184
  <mg-illustrated-message>
178
185
  */
186
+
179
187
  --mg-illustrated-message-padding-vertical: 4rem;
180
188
 
181
189
  /*
@@ -230,4 +238,18 @@
230
238
  <mg-input-radio>
231
239
  */
232
240
  --mg-input-check-size: 1.3rem;
241
+
242
+ /*
243
+ <mg-menu-item>
244
+ */
245
+ --mg-menu-item-focused-background-color-hsl: var(--mg-color-app-hsl);
246
+ --mg-menu-item-border-color-active-hsl: var(--mg-color-app-hsl);
247
+ --mg-menu-item-color-active-hsl: var(--mg-color-app-hsl);
248
+
249
+ /*
250
+ <mg-tabs>
251
+ */
252
+ --mg-tabs-focused-background-color-hsl: var(--mg-color-app-hsl);
253
+ --mg-tabs-border-color-active-hsl: var(--mg-color-app-hsl);
254
+ --mg-tabs-color-active-hsl: var(--mg-color-app-hsl);
233
255
  }
@@ -77,15 +77,6 @@ const MgInput = (props, children, utils) => {
77
77
  if (typeof props.errorMessage === 'string' && props.errorMessage !== '') {
78
78
  ariaDescribedbyIDs.add(helpTextErrorId);
79
79
  }
80
- /**
81
- * Update input(s) in children
82
- */
83
- if (props.readonly) {
84
- children = children.filter(child => child.$name$ === 'append-input');
85
- }
86
- else {
87
- children = applyAriadescribedBy(children, ariaDescribedbyIDs, utils);
88
- }
89
80
  /**
90
81
  * Return template
91
82
  *
@@ -111,19 +102,20 @@ const MgInput = (props, children, utils) => {
111
102
  h("mg-icon", { icon: "info-circle" })));
112
103
  /**
113
104
  * Get input title (label) node
105
+ * Display asterisk only if not disabled and not readonly
114
106
  *
115
107
  * @returns {VNode[]} mg-input-title
116
108
  */
117
- const getInputTitle = () => (h("mg-input-title", { identifier: props.identifier, class: props.labelHide ? 'sr-only' : undefined, required: props.required && !props.disabled, "is-legend": props.isFieldset }, props.label));
109
+ const getInputTitle = () => (h("mg-input-title", { identifier: props.identifier, class: props.labelHide ? 'sr-only' : undefined, required: props.required && !props.disabled && !props.readonly, "is-legend": props.isFieldset }, props.label));
118
110
  return (h(TagName, { class: props.classList.join() },
119
111
  props.labelOnTop ? (h("div", { class: "mg-input__title" },
120
112
  getInputTitle(),
121
113
  !props.readonly && props.tooltip && getTooltip())) : (getInputTitle()),
122
114
  props.readonly ? (h("div", { class: "mg-input__input-container" },
123
115
  h("strong", null, props.readonlyValue || props.value),
124
- children)) : (h("div", { class: "mg-input__input-container" },
116
+ children.filter(child => child.$name$ === 'append-input'))) : (h("div", { class: "mg-input__input-container" },
125
117
  h("div", { class: { 'mg-input__input': true, 'mg-input__input--has-error': props.errorMessage !== undefined } },
126
- children,
118
+ applyAriadescribedBy(children, ariaDescribedbyIDs, utils),
127
119
  !props.labelOnTop && props.tooltip && getTooltip()),
128
120
  props.helpText && h("div", { id: helpTextId, class: "mg-input__help-text", innerHTML: props.helpText }),
129
121
  props.errorMessage && !props.readonly && !props.disabled && (h("div", { id: helpTextErrorId, class: "mg-input__error", innerHTML: props.errorMessage, "aria-live": "assertive" }))))));
@@ -18,6 +18,8 @@ export { MgInputText as MgInputText } from '../types/components/molecules/inputs
18
18
  export { MgInputTextarea as MgInputTextarea } from '../types/components/molecules/inputs/mg-input-textarea/mg-input-textarea';
19
19
  export { MgInputTitle as MgInputTitle } from '../types/components/atoms/mg-input-title/mg-input-title';
20
20
  export { MgInputToggle as MgInputToggle } from '../types/components/molecules/inputs/mg-input-toggle/mg-input-toggle';
21
+ export { MgMenu as MgMenu } from '../types/components/molecules/menu/mg-menu/mg-menu';
22
+ export { MgMenuItem as MgMenuItem } from '../types/components/molecules/menu/mg-menu-item/mg-menu-item';
21
23
  export { MgMessage as MgMessage } from '../types/components/molecules/mg-message/mg-message';
22
24
  export { MgModal as MgModal } from '../types/components/molecules/mg-modal/mg-modal';
23
25
  export { MgPagination as MgPagination } from '../types/components/molecules/mg-pagination/mg-pagination';
@@ -18,6 +18,8 @@ export { MgInputText, defineCustomElement as defineCustomElementMgInputText } fr
18
18
  export { MgInputTextarea, defineCustomElement as defineCustomElementMgInputTextarea } from './mg-input-textarea.js';
19
19
  export { MgInputTitle, defineCustomElement as defineCustomElementMgInputTitle } from './mg-input-title.js';
20
20
  export { MgInputToggle, defineCustomElement as defineCustomElementMgInputToggle } from './mg-input-toggle.js';
21
+ export { MgMenu, defineCustomElement as defineCustomElementMgMenu } from './mg-menu.js';
22
+ export { MgMenuItem, defineCustomElement as defineCustomElementMgMenuItem } from './mg-menu-item.js';
21
23
  export { MgMessage, defineCustomElement as defineCustomElementMgMessage } from './mg-message.js';
22
24
  export { MgModal, defineCustomElement as defineCustomElementMgModal } from './mg-modal.js';
23
25
  export { MgPagination, defineCustomElement as defineCustomElementMgPagination } from './mg-pagination.js';
@@ -128,7 +128,9 @@ const messages = { en, fr };
128
128
  */
129
129
  const getLocale = (element) => {
130
130
  var _a;
131
- return ((_a = element.closest('[lang]')) === null || _a === void 0 ? void 0 : _a.lang) || navigator.language || defaultLocale;
131
+ // validate locale
132
+ const closestLang = Intl.NumberFormat.supportedLocalesOf((_a = element.closest('[lang]')) === null || _a === void 0 ? void 0 : _a.lang);
133
+ return closestLang.length > 0 ? closestLang[0] : navigator.language || defaultLocale;
132
134
  };
133
135
  /**
134
136
  * Get Intl object
@@ -16,7 +16,7 @@ const MgBadge = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
16
16
  /************
17
17
  * Internal *
18
18
  ************/
19
- // classes
19
+ // Classes
20
20
  this.classOutline = `mg-badge--outline`;
21
21
  /**
22
22
  * Define button variant
@@ -65,7 +65,7 @@ const MgButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
65
65
  }
66
66
  };
67
67
  /**
68
- * Handle onKeyDown event
68
+ * Handle onKeydown event
69
69
  *
70
70
  * @param {KeyboardEvent} event keyboard event
71
71
  * @returns {void}
@@ -80,7 +80,7 @@ const MgButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
80
80
  }
81
81
  };
82
82
  /**
83
- * Handle onKeyUp event
83
+ * Handle onKeyup event
84
84
  *
85
85
  * @param {KeyboardEvent} event keyboard event
86
86
  * @returns {void}
@@ -163,7 +163,7 @@ const MgButton = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
163
163
  * @returns {HTMLElement} html element
164
164
  */
165
165
  render() {
166
- return (h(Host, { role: "button", tabIndex: this.disabled ? -1 : 0, type: this.type, form: this.form, "full-width": this.fullWidth, "aria-label": this.label, "aria-disabled": this.disabled !== undefined && this.disabled.toString(), onClick: this.handleClick, onKeyUp: this.handleKeyup, onKeyDown: this.handleKeydown }, h("div", { class: this.classList.join(), id: this.identifier }, this.loading && h("mg-icon", { icon: "loader", spin: true }), h("div", { class: "mg-button__content" }, h("slot", null)))));
166
+ return (h(Host, { role: "button", tabIndex: this.disabled ? -1 : 0, type: this.type, form: this.form, "full-width": this.fullWidth, "aria-label": this.label, "aria-disabled": this.disabled !== undefined && this.disabled.toString(), onClick: this.handleClick, onKeyup: this.handleKeyup, onKeydown: this.handleKeydown }, h("div", { class: this.classList.join(), id: this.identifier }, this.loading && h("mg-icon", { icon: "loader", spin: true }), h("div", { class: "mg-button__content" }, h("slot", null)))));
167
167
  }
168
168
  get element() { return this; }
169
169
  static get watchers() { return {