@mgdis/mg-components 5.4.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/cjs/{index-94497267.js → index-4dcc1812.js} +11 -1
  2. package/dist/cjs/loader.cjs.js +3 -3
  3. package/dist/cjs/{mg-badge_29.cjs.entry.js → mg-badge_30.cjs.entry.js} +1112 -859
  4. package/dist/cjs/mg-components.cjs.js +3 -3
  5. package/dist/collection/collection-manifest.json +5 -4
  6. package/dist/collection/components/atoms/mg-badge/doc/mg-badge.stories.js +0 -7
  7. package/dist/collection/components/atoms/mg-badge/mg-badge.conf.js +1 -1
  8. package/dist/collection/components/atoms/mg-badge/mg-badge.css +13 -0
  9. package/dist/collection/components/atoms/mg-badge/mg-badge.js +7 -10
  10. package/dist/collection/components/atoms/mg-button/doc/mg-button.stories.js +0 -7
  11. package/dist/collection/components/atoms/mg-button/mg-button.conf.js +1 -1
  12. package/dist/collection/components/atoms/mg-button/mg-button.css +15 -1
  13. package/dist/collection/components/atoms/mg-button/mg-button.js +12 -29
  14. package/dist/collection/components/atoms/mg-card/mg-card.css +17 -5
  15. package/dist/collection/components/atoms/mg-character-left/mg-character-left.js +2 -3
  16. package/dist/collection/components/atoms/mg-divider/mg-divider.js +0 -6
  17. package/dist/collection/components/atoms/mg-icon/mg-icon.conf.js +13 -3
  18. package/dist/collection/components/atoms/mg-icon/mg-icon.js +5 -12
  19. package/dist/collection/components/atoms/mg-input-title/mg-input-title.js +4 -8
  20. package/dist/collection/components/atoms/mg-tag/doc/mg-tag.stories.js +1 -9
  21. package/dist/collection/components/atoms/mg-tag/mg-tag.css +58 -0
  22. package/dist/collection/components/atoms/mg-tag/mg-tag.js +61 -16
  23. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.css +2 -0
  24. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.js +9 -22
  25. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +17 -33
  26. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.css +3 -3
  27. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +21 -26
  28. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.css +3 -3
  29. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.js +24 -47
  30. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.css +3 -3
  31. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.js +17 -29
  32. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.js +18 -33
  33. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.css +3 -3
  34. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +30 -36
  35. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.css +3 -3
  36. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.js +23 -41
  37. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.css +3 -3
  38. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.js +23 -45
  39. package/dist/collection/components/molecules/inputs/mg-input-toggle/mg-input-toggle.js +16 -33
  40. package/dist/collection/components/molecules/menu/mg-menu/doc/mg-menu.stories.js +43 -11
  41. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.conf.js +17 -0
  42. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.css +27 -0
  43. package/dist/collection/components/molecules/menu/mg-menu/mg-menu.js +145 -25
  44. package/dist/collection/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.js +7 -5
  45. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.conf.js +0 -4
  46. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.css +51 -21
  47. package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.js +129 -92
  48. package/dist/collection/components/molecules/mg-details/mg-details.js +4 -8
  49. package/dist/collection/components/molecules/mg-form/mg-form.js +8 -22
  50. package/dist/collection/components/molecules/mg-illustrated-message/mg-illustrated-message.css +2 -2
  51. package/dist/collection/components/molecules/mg-illustrated-message/mg-illustrated-message.js +4 -9
  52. package/dist/collection/components/molecules/mg-message/mg-message.css +20 -19
  53. package/dist/collection/components/molecules/mg-message/mg-message.js +55 -33
  54. package/dist/collection/components/molecules/mg-modal/mg-modal.css +20 -8
  55. package/dist/collection/components/molecules/mg-modal/mg-modal.js +8 -26
  56. package/dist/collection/components/molecules/mg-pagination/mg-pagination.js +4 -13
  57. package/dist/collection/components/molecules/mg-panel/mg-panel.css +17 -5
  58. package/dist/collection/components/molecules/mg-panel/mg-panel.js +11 -22
  59. package/dist/collection/components/molecules/mg-popover/mg-popover.css +82 -20
  60. package/dist/collection/components/molecules/mg-popover/mg-popover.js +54 -26
  61. package/dist/collection/components/molecules/mg-skip-links/doc/mg-skip-links.stories.js +24 -0
  62. package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.conf.js +1 -0
  63. package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.css +28 -0
  64. package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.js +108 -0
  65. package/dist/collection/components/molecules/mg-tabs/doc/mg-tabs.stories.js +5 -3
  66. package/dist/collection/components/molecules/mg-tabs/mg-tabs.css +11 -7
  67. package/dist/collection/components/molecules/mg-tabs/mg-tabs.js +109 -75
  68. package/dist/collection/locales/en/messages.json +7 -0
  69. package/dist/collection/locales/fr/messages.json +7 -0
  70. package/dist/collection/locales/index.js +2 -25
  71. package/dist/collection/styles/a11y.scss +32 -0
  72. package/dist/collection/styles/components.scss +3 -0
  73. package/dist/collection/styles/fonts.scss +21 -0
  74. package/dist/collection/styles/form.scss +3 -0
  75. package/dist/collection/styles/global.scss +87 -0
  76. package/dist/collection/styles/layout.scss +29 -0
  77. package/dist/collection/styles/main.scss +23 -0
  78. package/dist/collection/styles/navigation-button.scss +76 -0
  79. package/dist/collection/styles/reset-mg-card-slotted-variables.scss +9 -0
  80. package/dist/collection/styles/typography.scss +75 -0
  81. package/dist/collection/styles/utilities.scss +21 -0
  82. package/dist/collection/utils/behaviors.utils.js +169 -0
  83. package/dist/collection/utils/components.utils.js +50 -0
  84. package/dist/collection/utils/locale.utils.js +22 -0
  85. package/dist/collection/utils/unit.test.utils.js +37 -32
  86. package/dist/collection/variables.css +9 -9
  87. package/dist/components/components.utils.js +51 -1
  88. package/dist/components/index.d.ts +1 -0
  89. package/dist/components/index.js +1 -0
  90. package/dist/components/index2.js +73 -18
  91. package/dist/components/mg-badge2.js +8 -11
  92. package/dist/components/mg-button2.js +13 -30
  93. package/dist/components/mg-card.js +1 -37
  94. package/dist/components/mg-card2.js +39 -0
  95. package/dist/components/mg-character-left2.js +2 -3
  96. package/dist/components/mg-details.js +4 -8
  97. package/dist/components/mg-divider.js +0 -6
  98. package/dist/components/mg-form.js +8 -22
  99. package/dist/components/mg-icon2.js +18 -15
  100. package/dist/components/mg-illustrated-message.js +5 -10
  101. package/dist/components/mg-input-checkbox.js +17 -33
  102. package/dist/components/mg-input-date.js +23 -29
  103. package/dist/components/mg-input-numeric.js +26 -50
  104. package/dist/components/mg-input-password.js +18 -30
  105. package/dist/components/mg-input-radio.js +18 -33
  106. package/dist/components/mg-input-select2.js +32 -38
  107. package/dist/components/mg-input-text2.js +24 -42
  108. package/dist/components/mg-input-textarea.js +24 -46
  109. package/dist/components/mg-input-title2.js +4 -8
  110. package/dist/components/mg-input-toggle.js +16 -33
  111. package/dist/components/mg-menu-item.js +1 -264
  112. package/dist/components/mg-menu-item2.js +517 -0
  113. package/dist/components/mg-menu.js +142 -28
  114. package/dist/components/mg-message.js +64 -36
  115. package/dist/components/mg-modal.js +18 -30
  116. package/dist/components/mg-pagination.js +4 -13
  117. package/dist/components/mg-panel.js +20 -25
  118. package/dist/components/mg-popover.js +1 -200
  119. package/dist/components/mg-popover2.js +212 -0
  120. package/dist/components/mg-skip-links.d.ts +11 -0
  121. package/dist/components/mg-skip-links.js +80 -0
  122. package/dist/components/mg-tabs.js +108 -73
  123. package/dist/components/mg-tag.js +35 -13
  124. package/dist/components/mg-tooltip2.js +10 -23
  125. package/dist/esm/{index-aad0184c.js → index-dc9a2348.js} +11 -1
  126. package/dist/esm/loader.js +3 -3
  127. package/dist/esm/{mg-badge_29.entry.js → mg-badge_30.entry.js} +1112 -860
  128. package/dist/esm/mg-components.js +3 -3
  129. package/dist/esm/polyfills/core-js.js +0 -0
  130. package/dist/esm/polyfills/css-shim.js +1 -1
  131. package/dist/esm/polyfills/dom.js +0 -0
  132. package/dist/esm/polyfills/es5-html-element.js +0 -0
  133. package/dist/esm/polyfills/index.js +0 -0
  134. package/dist/esm/polyfills/system.js +0 -0
  135. package/dist/mg-components/locales/en/messages.json +7 -0
  136. package/dist/mg-components/locales/fr/messages.json +7 -0
  137. package/dist/mg-components/mg-components.css +1 -1
  138. package/dist/mg-components/mg-components.esm.js +1 -1
  139. package/dist/mg-components/{p-3899d5d2.js → p-182bd802.js} +2 -2
  140. package/dist/mg-components/p-f7da9dd2.entry.js +1 -0
  141. package/dist/mg-components/styles/a11y.scss +32 -0
  142. package/dist/mg-components/styles/components.scss +3 -0
  143. package/dist/mg-components/styles/fonts.scss +21 -0
  144. package/dist/mg-components/styles/form.scss +3 -0
  145. package/dist/mg-components/styles/global.scss +87 -0
  146. package/dist/mg-components/styles/layout.scss +29 -0
  147. package/dist/mg-components/styles/main.scss +23 -0
  148. package/dist/mg-components/styles/navigation-button.scss +76 -0
  149. package/dist/mg-components/styles/reset-mg-card-slotted-variables.scss +9 -0
  150. package/dist/mg-components/styles/typography.scss +75 -0
  151. package/dist/mg-components/styles/utilities.scss +21 -0
  152. package/dist/mg-components/variables.css +9 -9
  153. package/dist/types/components/atoms/mg-badge/doc/mg-badge.stories.d.ts +0 -11
  154. package/dist/types/components/atoms/mg-badge/mg-badge.conf.d.ts +2 -2
  155. package/dist/types/components/atoms/mg-badge/mg-badge.d.ts +1 -1
  156. package/dist/types/components/atoms/mg-button/doc/mg-button.stories.d.ts +0 -11
  157. package/dist/types/components/atoms/mg-button/mg-button.conf.d.ts +4 -4
  158. package/dist/types/components/atoms/mg-button/mg-button.d.ts +6 -6
  159. package/dist/types/components/atoms/mg-icon/mg-icon.conf.d.ts +2 -2
  160. package/dist/types/components/atoms/mg-tag/doc/mg-tag.stories.d.ts +0 -13
  161. package/dist/types/components/atoms/mg-tag/mg-tag.conf.d.ts +5 -1
  162. package/dist/types/components/atoms/mg-tag/mg-tag.d.ts +27 -6
  163. package/dist/types/components/molecules/inputs/MgInput.conf.d.ts +2 -2
  164. package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.conf.d.ts +2 -2
  165. package/dist/types/components/molecules/inputs/mg-input-radio/mg-input-radio.conf.d.ts +1 -1
  166. package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.conf.d.ts +2 -2
  167. package/dist/types/components/molecules/inputs/mg-input-toggle/mg-input-toggle.conf.d.ts +1 -1
  168. package/dist/types/components/molecules/menu/mg-menu/doc/mg-menu.stories.d.ts +5 -0
  169. package/dist/types/components/molecules/menu/mg-menu/mg-menu.conf.d.ts +37 -0
  170. package/dist/types/components/molecules/menu/mg-menu/mg-menu.d.ts +51 -3
  171. package/dist/types/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.d.ts +1 -0
  172. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.conf.d.ts +0 -8
  173. package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.d.ts +55 -15
  174. package/dist/types/components/molecules/mg-form/mg-form.d.ts +1 -1
  175. package/dist/types/components/molecules/mg-message/mg-message.d.ts +22 -5
  176. package/dist/types/components/molecules/mg-modal/mg-modal.d.ts +1 -1
  177. package/dist/types/components/molecules/mg-popover/mg-popover.d.ts +12 -0
  178. package/dist/types/components/molecules/mg-skip-links/doc/mg-skip-links.stories.d.ts +11 -0
  179. package/dist/types/components/molecules/mg-skip-links/mg-skip-links.conf.d.ts +7 -0
  180. package/dist/types/components/molecules/mg-skip-links/mg-skip-links.d.ts +49 -0
  181. package/dist/types/components/molecules/mg-tabs/mg-tabs.conf.d.ts +5 -3
  182. package/dist/types/components/molecules/mg-tabs/mg-tabs.d.ts +24 -14
  183. package/dist/types/components.d.ts +81 -18
  184. package/dist/types/locales/index.d.ts +16 -9
  185. package/dist/types/stencil-public-runtime.d.ts +44 -3
  186. package/dist/types/utils/behaviors.utils.d.ts +83 -0
  187. package/dist/types/utils/components.utils.d.ts +14 -0
  188. package/dist/types/utils/locale.utils.d.ts +13 -0
  189. package/dist/types/utils/unit.test.utils.d.ts +78 -0
  190. package/package.json +51 -46
  191. package/readme.md +25 -14
  192. package/dist/components/locale.utils.js +0 -40
  193. package/dist/components/mg-menu.conf.js +0 -10
  194. package/dist/mg-components/p-059a9a59.entry.js +0 -1
@@ -0,0 +1,24 @@
1
+ import { h } from '@stencil/core';
2
+ import { filterArgs } from '../../../../../.storybook/utils';
3
+ export default {
4
+ component: 'mg-skip-links',
5
+ title: 'Molecules/mg-skip-links',
6
+ parameters: { actions: { handles: ['go-to-anchor'] } },
7
+ };
8
+ /**
9
+ * Template
10
+ *
11
+ * @param {any} args component arguments
12
+ * @returns {HTMLElement} HTMLElement
13
+ */
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ const Template = (args) => h("mg-skip-links", Object.assign({}, filterArgs(args)));
16
+ export const MgSkipLinks = Template.bind({});
17
+ MgSkipLinks.args = {
18
+ links: [
19
+ { href: '#content', label: 'Content' },
20
+ { href: '#menu', label: 'Menu' },
21
+ { href: '#search', label: 'Search' },
22
+ { href: '#footer', label: 'Footer' },
23
+ ],
24
+ };
@@ -0,0 +1,28 @@
1
+ .mg-skip-links {
2
+ position: absolute;
3
+ transform: translateY(-100%);
4
+ opacity: 0;
5
+ background: hsl(var(--color-light));
6
+ }
7
+ .mg-skip-links:focus-within {
8
+ position: relative;
9
+ transform: translateY(0);
10
+ opacity: 1;
11
+ }
12
+ .mg-skip-links__list {
13
+ display: flex;
14
+ flex-wrap: wrap;
15
+ align-items: center;
16
+ gap: 0.6rem;
17
+ margin: 0;
18
+ padding: 0.64rem 1.8rem;
19
+ list-style: none;
20
+ }
21
+ .mg-skip-links__link {
22
+ display: inline-block;
23
+ padding: 1.2rem;
24
+ color: hsl(var(--color-dark));
25
+ }
26
+ .mg-skip-links__link:hover {
27
+ background: hsl(var(--color-dark), 0.1);
28
+ }
@@ -0,0 +1,108 @@
1
+ import { h } from '@stencil/core';
2
+ import { initLocales } from '../../../locales';
3
+ export class MgSkipLinks {
4
+ constructor() {
5
+ /***********
6
+ * Methods *
7
+ **********/
8
+ /**
9
+ * Handle link click and emit go-to-anchor event
10
+ *
11
+ * @param {MouseEvent} event mouse event
12
+ * @returns {void}
13
+ */
14
+ this.handleLinkCLick = (event) => {
15
+ event.currentTarget.blur();
16
+ this.goToAnchor.emit(event.currentTarget.getAttribute('href'));
17
+ };
18
+ this.links = undefined;
19
+ }
20
+ validateLinks(links) {
21
+ if (links === undefined ||
22
+ links.length === 0 ||
23
+ links.some(link => link.href === undefined || !link.href.startsWith('#') || link.label === undefined || link.label.trim() === '')) {
24
+ throw new Error(`<mg-skip-links> prop "links": Cannot be empty and each link must contains an href starting with a "#" and a non empty label attributes.`);
25
+ }
26
+ }
27
+ /*************
28
+ * Lifecycle *
29
+ *************/
30
+ /**
31
+ * Check if props are well configured on init
32
+ *
33
+ * @returns {void}
34
+ */
35
+ componentWillLoad() {
36
+ this.validateLinks(this.links);
37
+ this.messages = initLocales(this.element).messages;
38
+ }
39
+ /**
40
+ * Render
41
+ *
42
+ * @returns {HTMLElement} HTML Element
43
+ */
44
+ render() {
45
+ return (h("nav", { class: "mg-skip-links", role: "navigation", "aria-label": this.messages.skipLinks.navLabel }, h("ul", { class: "mg-skip-links__list" }, this.links.map(link => (h("li", null, h("a", { class: "mg-skip-links__link", href: link.href, onClick: this.handleLinkCLick }, link.label)))))));
46
+ }
47
+ static get is() { return "mg-skip-links"; }
48
+ static get encapsulation() { return "shadow"; }
49
+ static get originalStyleUrls() {
50
+ return {
51
+ "$": ["mg-skip-links.scss"]
52
+ };
53
+ }
54
+ static get styleUrls() {
55
+ return {
56
+ "$": ["mg-skip-links.css"]
57
+ };
58
+ }
59
+ static get properties() {
60
+ return {
61
+ "links": {
62
+ "type": "unknown",
63
+ "mutable": true,
64
+ "complexType": {
65
+ "original": "SkipLink[]",
66
+ "resolved": "SkipLink[]",
67
+ "references": {
68
+ "SkipLink": {
69
+ "location": "import",
70
+ "path": "./mg-skip-links.conf"
71
+ }
72
+ }
73
+ },
74
+ "required": false,
75
+ "optional": false,
76
+ "docs": {
77
+ "tags": [],
78
+ "text": "Skip links"
79
+ }
80
+ }
81
+ };
82
+ }
83
+ static get events() {
84
+ return [{
85
+ "method": "goToAnchor",
86
+ "name": "go-to-anchor",
87
+ "bubbles": true,
88
+ "cancelable": true,
89
+ "composed": true,
90
+ "docs": {
91
+ "tags": [],
92
+ "text": "Emited event when link is clicked"
93
+ },
94
+ "complexType": {
95
+ "original": "string",
96
+ "resolved": "string",
97
+ "references": {}
98
+ }
99
+ }];
100
+ }
101
+ static get elementRef() { return "element"; }
102
+ static get watchers() {
103
+ return [{
104
+ "propName": "links",
105
+ "methodName": "validateLinks"
106
+ }];
107
+ }
108
+ }
@@ -24,11 +24,11 @@ export const MgTabs = Template.bind({});
24
24
  MgTabs.args = {
25
25
  items: ['Tab 1', 'Tab 2', 'Tab 3', 'Tab 4'],
26
26
  label: 'Short tabs description. Needed for accessibility',
27
- activeTab: undefined,
27
+ activeTab: 2,
28
28
  size: sizes[0], // regular
29
29
  };
30
30
  export const MgTabsItems = Template.bind({});
31
- MgTabsItems.args = Object.assign(Object.assign({}, MgTabs.args), { activeTab: 3, items: [
31
+ MgTabsItems.args = Object.assign(Object.assign({}, MgTabs.args), { activeTab: undefined, items: [
32
32
  {
33
33
  label: 'Tab 1',
34
34
  icon: 'check',
@@ -36,12 +36,14 @@ MgTabsItems.args = Object.assign(Object.assign({}, MgTabs.args), { activeTab: 3,
36
36
  },
37
37
  {
38
38
  label: 'Tab 2',
39
- badge: { value: 5, label: 'messages' },
39
+ badge: { value: 5, label: 'messages', role: 'information' },
40
40
  status: Status.DISABLED,
41
41
  },
42
42
  {
43
43
  label: 'Tab 3',
44
44
  icon: 'cross',
45
+ badge: { value: '9+', label: 'messages', role: 'notification' },
46
+ status: Status.ACTIVE,
45
47
  },
46
48
  {
47
49
  label: 'Tab 4',
@@ -1,6 +1,7 @@
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();
4
5
  }
5
6
  .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button,
6
7
  .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button ::slotted([slot=label]),
@@ -8,7 +9,7 @@
8
9
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular,
9
10
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular ::slotted([slot=label]),
10
11
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular ::slotted([slot=metadata]) {
11
- font-size: 1.3rem;
12
+ font-size: var(--font-size);
12
13
  }
13
14
  .mg-tabs.mg-tabs--size-regular .mg-tabs__navigation-button.mg-tabs__navigation-button--horizontal,
14
15
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-regular.mg-tabs__navigation-button--horizontal {
@@ -22,6 +23,7 @@
22
23
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button,
23
24
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large {
24
25
  padding: 1.5rem 3rem;
26
+ height: calc();
25
27
  }
26
28
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button,
27
29
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button ::slotted([slot=label]),
@@ -29,7 +31,7 @@
29
31
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large,
30
32
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large ::slotted([slot=label]),
31
33
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large ::slotted([slot=metadata]) {
32
- font-size: 1.5rem;
34
+ font-size: calc(var(--font-size) + 0.2rem);
33
35
  }
34
36
  .mg-tabs.mg-tabs--size-large .mg-tabs__navigation-button.mg-tabs__navigation-button--horizontal,
35
37
  .mg-tabs__navigation-button.mg-tabs__navigation-button--size-large.mg-tabs__navigation-button--horizontal {
@@ -43,28 +45,30 @@
43
45
  .mg-tabs__navigation-button {
44
46
  display: flex;
45
47
  align-items: center;
46
- column-gap: 1rem;
48
+ column-gap: var(--mg-tabs-navigation-button-column-gap, 1rem);
47
49
  background-color: unset;
48
50
  border: none;
49
51
  font-family: var(--font-family);
50
52
  color: hsl(var(--mg-tabs-color-hsl, var(--color-dark)));
51
53
  line-height: var(--line-height);
52
54
  text-decoration: none;
55
+ white-space: nowrap;
56
+ box-sizing: border-box;
53
57
  cursor: pointer;
54
58
  }
55
59
  .mg-tabs__navigation-button:disabled, .mg-tabs__navigation-button--disabled {
56
60
  cursor: default;
57
- opacity: 30%;
61
+ opacity: 0.3;
58
62
  }
59
63
  .mg-tabs__navigation-button:focus-visible {
60
64
  z-index: 10;
61
65
  }
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%);
66
+ .mg-tabs__navigation-button:hover:not(.mg-tabs__navigation-button--disabled), .mg-tabs__navigation-button:focus-visible:not(.mg-tabs__navigation-button--disabled) {
67
+ background-color: hsl(var(--mg-tabs-focused-background-color-hsl), 0.1);
64
68
  }
65
69
  .mg-tabs__navigation-button.mg-tabs__navigation-button--active {
66
70
  color: hsl(var(--mg-tabs-color-active-hsl));
67
- font-weight: 700;
71
+ font-weight: 600;
68
72
  }
69
73
  .mg-tabs__navigation-button.mg-tabs__navigation-button--active.mg-tabs__navigation-button--horizontal {
70
74
  border-bottom-color: hsl(var(--mg-tabs-border-color-active-hsl));
@@ -13,48 +13,10 @@ export class MgTabs {
13
13
  /************
14
14
  * Internal *
15
15
  ************/
16
+ // classes
16
17
  this.tabPanel = 'panel';
17
- this.startIndex = 1;
18
18
  this.buttonTabBaseClass = 'mg-tabs__navigation-button';
19
- /**
20
- * Identifier is used for the element ID (id is a reserved prop in Stencil.js)
21
- * If not set, it will be created.
22
- */
23
- this.identifier = createID('mg-tabs');
24
- /**
25
- * Define tabs size
26
- */
27
- this.size = 'regular';
28
- /**
29
- * Active tab number
30
- * default: first is 1
31
- */
32
- this.activeTab = 1;
33
- /**
34
- * Component tabs
35
- */
36
- this.tabs = [];
37
- /**
38
- * Component classes
39
- */
40
- this.classList = new ClassList(['mg-tabs']);
41
- /**
42
- * Method to set active tab
43
- *
44
- * @param {number} tabKey item tab key to set to ACTIVE status
45
- * @returns {void}
46
- */
47
- this.setActiveTab = (tabKey) => {
48
- // reset active tabs
49
- this.tabs.forEach(tab => {
50
- if (this.tabHasGivenStatus(tab, Status.ACTIVE))
51
- tab.status = Status.VISIBLE;
52
- });
53
- // set active tab from given tab key
54
- this.tabs[tabKey - this.startIndex].status = Status.ACTIVE;
55
- // emit change active tab key event
56
- this.activeTabChange.emit(tabKey);
57
- };
19
+ this.startIndex = 1;
58
20
  /**
59
21
  * Method to know if given tab has the given status
60
22
  *
@@ -62,7 +24,7 @@ export class MgTabs {
62
24
  * @param {Status} status status to valide
63
25
  * @returns {boolean} status comparaison
64
26
  */
65
- this.tabHasGivenStatus = (tab, status) => tab.status === status;
27
+ this.tabHasStatus = (tab, status) => tab.status === status;
66
28
  /**
67
29
  * Method to get element id from index
68
30
  *
@@ -70,14 +32,20 @@ export class MgTabs {
70
32
  * @param {number} index to generate id
71
33
  * @returns {string} generated element id
72
34
  */
73
- this.getElementId = (element, index) => `${element}-${this.getTabIndex(index)}`;
35
+ this.getElementId = (element, index) => `${element}-${this.getTabItemIndex(index)}`;
74
36
  /**
75
- * Method to get tab index
37
+ * Method to get tab item index
76
38
  *
77
39
  * @param {number} index to get
78
40
  * @returns {number} index
79
41
  */
80
- this.getTabIndex = (index) => index + this.startIndex;
42
+ this.getTabItemIndex = (index) => index + this.startIndex;
43
+ /**
44
+ * Method to get the active-tab value
45
+ *
46
+ * @returns {number} of the active-tab
47
+ */
48
+ this.getActiveTab = () => this.activeTab || this.getTabItemIndex(this.tabs.map((tab, index) => (Object.assign(Object.assign({}, tab), { index }))).find(tab => this.tabHasStatus(tab, Status.ACTIVE)).index);
81
49
  /**
82
50
  * Handle click events on tabs
83
51
  *
@@ -85,16 +53,22 @@ export class MgTabs {
85
53
  */
86
54
  this.handleClick = (event) => {
87
55
  const tabId = event.currentTarget.getAttribute('data-index');
88
- this.activeTab = Number(tabId);
56
+ const tab = this.tabs[Number(tabId) - this.startIndex];
57
+ if (this.tabHasStatus(tab, Status.HIDDEN) || this.tabHasStatus(tab, Status.DISABLED)) {
58
+ event.preventDefault();
59
+ }
60
+ else {
61
+ this.activeTab = Number(tabId);
62
+ this.tabFocus = undefined;
63
+ }
89
64
  };
90
65
  /**
91
66
  * get navigation button class from given status
92
67
  *
93
68
  * @param {Status} status button tab status
94
- * @param {boolean} isSelector set if we need a CSS selector with the dot '.' at the begin. default value = false.
95
69
  * @returns {string} button class/selector variant
96
70
  */
97
- this.getNavigationButtonClass = (status, isSelector = false) => `${isSelector ? '.' : ''}${this.buttonTabBaseClass}--${status}`;
71
+ this.getNavigationButtonClass = (status) => `${this.buttonTabBaseClass}--${status}`;
98
72
  /**
99
73
  * Handle keyboard event on tabs
100
74
  *
@@ -102,32 +76,67 @@ export class MgTabs {
102
76
  * @returns {void}
103
77
  */
104
78
  this.handleKeydown = (event) => {
105
- let tabId = Number(event.target.getAttribute('data-index'));
106
79
  const parent = event.target.parentElement;
107
- // change selected id from key code
108
- if (event.key === 'ArrowRight') {
109
- tabId++;
110
- }
111
- else if (event.key === 'ArrowLeft') {
112
- tabId--;
80
+ if (['ArrowRight', 'ArrowLeft'].includes(event.key)) {
81
+ this.tabFocus = Number(event.target.getAttribute('data-index'));
82
+ parent.querySelector(`[data-index="${this.tabFocus}"]`).setAttribute('tabindex', '-1');
83
+ // Move right
84
+ if (event.key === 'ArrowRight') {
85
+ this.tabFocus++;
86
+ // If we're at the end, go to the start
87
+ if (this.tabFocus > this.tabs.length)
88
+ this.tabFocus = this.startIndex;
89
+ // Move left
90
+ }
91
+ else if (event.key === 'ArrowLeft') {
92
+ this.tabFocus--;
93
+ // If we're at the start, move to the end
94
+ if (this.tabFocus < this.startIndex)
95
+ this.tabFocus = this.tabs.length;
96
+ }
97
+ // if focus item is ['hidden'] we recursively repeat action
98
+ if (this.tabHasStatus(this.tabs[this.tabFocus - 1], Status.HIDDEN)) {
99
+ parent.querySelector(`[data-index="${this.tabFocus}"]`).dispatchEvent(new KeyboardEvent('keydown', { key: event.key, bubbles: true }));
100
+ // else run focus methods on tabFocus element
101
+ }
102
+ else {
103
+ parent.querySelector(`[data-index="${this.tabFocus}"]`).setAttribute('tabindex', '0');
104
+ parent.querySelector(`[data-index="${this.tabFocus}"]`).focus();
105
+ }
113
106
  }
114
- // get selected tab if NOT hidden, disabled
115
- const selectedTab = parent.querySelector(`[data-index="${tabId}"]:not(${[this.getNavigationButtonClass(Status.HIDDEN, true), this.getNavigationButtonClass(Status.DISABLED, true)].join()})`);
116
- // apply selected tab if exist
117
- if (selectedTab !== null) {
118
- selectedTab.focus();
119
- this.activeTab = tabId;
107
+ else if (event.key === 'Tab') {
108
+ this.resetFocus();
120
109
  }
121
110
  };
111
+ /**
112
+ * Method to reset focus behavior
113
+ *
114
+ * @returns {void}
115
+ */
116
+ this.resetFocus = () => {
117
+ // update asynchronously tabindex to prevent get focus on new tabindex at then end of event process
118
+ setTimeout(() => {
119
+ this.tabFocus = undefined;
120
+ Array.from(this.element.shadowRoot.querySelectorAll('[data-index]')).forEach((tab, index) => {
121
+ tab.setAttribute('tabindex', this.getActiveTab() - this.startIndex !== index ? '-1' : '0');
122
+ });
123
+ }, 0);
124
+ };
122
125
  /**
123
126
  * Validate slots setting
124
127
  */
125
128
  this.validateSlots = () => {
126
129
  const slots = Array.from(this.element.children).filter(slot => { var _a; return (_a = slot.getAttribute('slot')) === null || _a === void 0 ? void 0 : _a.includes('tab_content-'); });
127
- if (slots.length !== this.tabs.length) {
130
+ if (slots.length !== this.tabs.length)
128
131
  throw new Error('<mg-tabs> Must have slots counts equal to tabs count.');
129
- }
130
132
  };
133
+ this.identifier = createID('mg-tabs');
134
+ this.label = undefined;
135
+ this.size = 'regular';
136
+ this.items = undefined;
137
+ this.activeTab = undefined;
138
+ this.tabs = [];
139
+ this.classList = new ClassList(['mg-tabs']);
131
140
  }
132
141
  validateLabel(newValue) {
133
142
  if (typeof newValue !== 'string' || newValue.trim() === '') {
@@ -143,22 +152,37 @@ export class MgTabs {
143
152
  validateItems(newValue) {
144
153
  // String array
145
154
  if (allItemsAreString(newValue)) {
146
- this.tabs = newValue.map(item => ({ label: item, status: Status.VISIBLE }));
155
+ this.tabs = newValue.map((item, index) => ({ label: item, status: index === 0 ? Status.ACTIVE : Status.VISIBLE }));
147
156
  }
148
157
  // Object array
149
- else if (newValue && newValue.every(item => isTabItem(item))) {
158
+ else if (newValue && newValue.length > 0 && newValue.every(item => isTabItem(item))) {
150
159
  this.tabs = newValue;
160
+ // init active tabs if not set. Default: index 0.
161
+ if (this.tabs.find(tab => this.tabHasStatus(tab, Status.ACTIVE)) === undefined)
162
+ this.tabs[0].status = Status.ACTIVE;
151
163
  }
152
164
  else {
153
165
  throw new Error('<mg-tabs> prop "items" is required and all items must be the same type: TabItem.');
154
166
  }
155
167
  }
156
168
  validateActiveTab(newValue) {
157
- if (newValue < 1 || newValue > this.tabs.length) {
158
- throw new Error('<mg-tabs> prop "activeTab" must be between 1 and tabs length.');
169
+ if (typeof newValue === 'number' && newValue >= 1 && newValue <= this.tabs.length) {
170
+ this.tabs.forEach((tab, index) => {
171
+ const isNewActiveTab = index === newValue - this.startIndex;
172
+ // reset active tabs
173
+ if (this.tabHasStatus(tab, Status.ACTIVE) && !isNewActiveTab)
174
+ tab.status = Status.VISIBLE;
175
+ // set active tab from given tab key
176
+ else if ((tab.status === undefined || this.tabHasStatus(tab, Status.VISIBLE)) && isNewActiveTab)
177
+ tab.status = Status.ACTIVE;
178
+ });
179
+ // emit change active tab key event
180
+ if (this.tabs.find(tab => this.tabHasStatus(tab, Status.ACTIVE)) !== undefined) {
181
+ this.activeTabChange.emit(newValue);
182
+ }
159
183
  }
160
- else {
161
- this.setActiveTab(newValue);
184
+ else if (newValue !== undefined) {
185
+ throw new Error('<mg-tabs> prop "activeTab" must be between 1 and tabs length.');
162
186
  }
163
187
  }
164
188
  /*************
@@ -177,6 +201,17 @@ export class MgTabs {
177
201
  this.validateSize(this.size);
178
202
  this.validateSlots();
179
203
  }
204
+ /**
205
+ * add listners
206
+ *
207
+ * @returns {void}
208
+ */
209
+ componentDidLoad() {
210
+ document.addEventListener('click', (event) => {
211
+ if (event.target.closest('mg-tabs') !== this.element)
212
+ this.resetFocus();
213
+ }, false);
214
+ }
180
215
  /**
181
216
  * Render
182
217
  *
@@ -186,10 +221,10 @@ export class MgTabs {
186
221
  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
222
  [`${this.buttonTabBaseClass}`]: true,
188
223
  [`${this.buttonTabBaseClass}--horizontal`]: true,
189
- [`${this.getNavigationButtonClass(Status.ACTIVE)}`]: this.tabHasGivenStatus(tab, Status.ACTIVE),
190
- [`${this.getNavigationButtonClass(Status.DISABLED)}`]: this.tabHasGivenStatus(tab, Status.DISABLED),
191
- [`${this.getNavigationButtonClass(Status.HIDDEN)}`]: this.tabHasGivenStatus(tab, Status.HIDDEN),
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) }))))));
224
+ [`${this.getNavigationButtonClass(Status.ACTIVE)}`]: this.tabHasStatus(tab, Status.ACTIVE),
225
+ [`${this.getNavigationButtonClass(Status.DISABLED)}`]: this.tabHasStatus(tab, Status.DISABLED),
226
+ [`${this.getNavigationButtonClass(Status.HIDDEN)}`]: this.tabHasStatus(tab, Status.HIDDEN),
227
+ }, tabindex: this.tabHasStatus(tab, Status.ACTIVE) ? 0 : -1, "aria-selected": this.tabHasStatus(tab, Status.ACTIVE).toString(), "aria-controls": this.getElementId(this.tabPanel, index), "aria-disabled": this.tabHasStatus(tab, Status.DISABLED), onClick: this.handleClick, onKeyDown: this.handleKeydown, "data-index": this.getTabItemIndex(index) }, tab.icon !== undefined && h("mg-icon", { icon: tab.icon }), tab.label, tab.badge !== undefined && h("mg-badge", { variant: "text-color", value: tab.badge.value, label: tab.badge.label, outline: tab.badge.role === 'information' }))))), this.tabs.map((tab, index) => (h("article", { role: "tabpanel", id: this.getElementId(this.tabPanel, index), hidden: !this.tabHasStatus(tab, Status.ACTIVE), "aria-labelledby": this.getElementId(this.identifier, index), tabindex: this.tabHasStatus(tab, Status.ACTIVE) ? 0 : -1, class: "mg-tabs__content-container" }, h("slot", { name: this.getElementId('tab_content', index) }))))));
193
228
  }
194
229
  static get is() { return "mg-tabs"; }
195
230
  static get encapsulation() { return "shadow"; }
@@ -295,11 +330,10 @@ export class MgTabs {
295
330
  "optional": false,
296
331
  "docs": {
297
332
  "tags": [],
298
- "text": "Active tab number\ndefault: first is 1"
333
+ "text": "Active tab number"
299
334
  },
300
335
  "attribute": "active-tab",
301
- "reflect": true,
302
- "defaultValue": "1"
336
+ "reflect": true
303
337
  }
304
338
  };
305
339
  }
@@ -40,11 +40,18 @@
40
40
  "panel": {
41
41
  "editLabel": "Edit section title."
42
42
  },
43
+ "skipLinks": {
44
+ "navLabel": "Quick access"
45
+ },
43
46
  "general": {
44
47
  "confirm": "Confirm",
45
48
  "cancel": "Cancel",
46
49
  "close": "Close",
47
50
  "next": "next",
48
51
  "previous": "previous"
52
+ },
53
+ "plusMenu": {
54
+ "moreLabel": "Additional menu",
55
+ "badgeLabel": "Include notification(s)"
49
56
  }
50
57
  }
@@ -40,11 +40,18 @@
40
40
  "panel": {
41
41
  "editLabel": "Modifier le titre de la section."
42
42
  },
43
+ "skipLinks": {
44
+ "navLabel": "Accès rapide"
45
+ },
43
46
  "general": {
44
47
  "confirm": "Valider",
45
48
  "cancel": "Annuler",
46
49
  "close": "Fermer",
47
50
  "next": "suivant",
48
51
  "previous": "précédent"
52
+ },
53
+ "plusMenu": {
54
+ "moreLabel": "Menu complémentaire",
55
+ "badgeLabel": "Notification(s) incluse(s)"
49
56
  }
50
57
  }
@@ -1,35 +1,12 @@
1
1
  import en from './en/messages.json';
2
2
  import fr from './fr/messages.json';
3
+ import { getLocaleMessages } from '../utils/locale.utils';
3
4
  const defaultLocale = 'en';
4
5
  const messages = { en, fr };
5
- /**
6
- * Get locale
7
- *
8
- * @param {HTMLElement} element element that needs to know the locale to use
9
- * @returns {string} locale
10
- */
11
- const getLocale = (element) => {
12
- var _a;
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;
16
- };
17
6
  /**
18
7
  * Get Intl object
19
- * We load the defined locale but for now we only support the first subtag for messages
20
8
  *
21
9
  * @param {HTMLElement} element element we need to get the language
22
10
  * @returns {{ locale: string; messages: unknown }} messages object
23
11
  */
24
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
- export const initLocales = (element) => {
26
- // Get local
27
- const locale = getLocale(element);
28
- // Only keep first subtag
29
- const localeSubtag = locale.split('-').shift();
30
- // Return
31
- return {
32
- locale,
33
- messages: messages[localeSubtag] || messages[defaultLocale],
34
- };
35
- };
12
+ export const initLocales = (element) => getLocaleMessages(element, messages, defaultLocale);
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A11Y
3
+ */
4
+
5
+ // Make content available only for screen reader
6
+ // https://gist.github.com/ffoodd/000b59f431e3e64e4ce1a24d5bb36034
7
+ .sr-only {
8
+ border: 0 !important;
9
+ clip: rect(1px, 1px, 1px, 1px) !important;
10
+ -webkit-clip-path: inset(50%) !important;
11
+ clip-path: inset(50%) !important;
12
+ height: 1px !important;
13
+ margin: -1px !important;
14
+ overflow: hidden !important;
15
+ padding: 0 !important;
16
+ position: absolute !important;
17
+ width: 1px !important;
18
+ white-space: nowrap !important;
19
+ }
20
+
21
+ // Remove outline for non-keyboard :focus
22
+ // https://www.tpgi.com/focus-visible-and-backwards-compatibility/
23
+ *:focus:not(:focus-visible) {
24
+ outline: none;
25
+ }
26
+
27
+ @media (prefers-reduced-motion) {
28
+ .mg-a11y-animation {
29
+ animation: none !important;
30
+ transition: none !important;
31
+ }
32
+ }
@@ -0,0 +1,3 @@
1
+ [hide] {
2
+ display: none;
3
+ }