@mgdis/mg-components 5.5.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/{index-c3450336.js → index-4dcc1812.js} +11 -1
- package/dist/cjs/loader.cjs.js +3 -3
- package/dist/cjs/mg-badge_30.cjs.entry.js +742 -244
- package/dist/cjs/mg-components.cjs.js +3 -3
- package/dist/collection/collection-manifest.json +4 -4
- package/dist/collection/components/atoms/mg-badge/mg-badge.conf.js +1 -1
- package/dist/collection/components/atoms/mg-badge/mg-badge.css +13 -0
- package/dist/collection/components/atoms/mg-badge/mg-badge.js +3 -3
- package/dist/collection/components/atoms/mg-button/mg-button.css +2 -1
- package/dist/collection/components/atoms/mg-card/mg-card.css +13 -6
- package/dist/collection/components/atoms/mg-icon/mg-icon.conf.js +13 -3
- package/dist/collection/components/atoms/mg-tag/mg-tag.css +6 -6
- package/dist/collection/components/atoms/mg-tag/mg-tag.js +3 -3
- package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.css +2 -0
- package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.js +3 -3
- package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.css +3 -3
- package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +4 -1
- package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.css +3 -3
- package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.css +3 -3
- package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.css +3 -3
- package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +7 -3
- package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.css +3 -3
- package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.css +3 -3
- package/dist/collection/components/molecules/menu/mg-menu/doc/mg-menu.stories.js +43 -11
- package/dist/collection/components/molecules/menu/mg-menu/mg-menu.conf.js +17 -0
- package/dist/collection/components/molecules/menu/mg-menu/mg-menu.css +27 -0
- package/dist/collection/components/molecules/menu/mg-menu/mg-menu.js +141 -18
- package/dist/collection/components/molecules/menu/mg-menu-item/doc/mg-menu-item.stories.js +5 -10
- package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.conf.js +0 -4
- package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.css +47 -21
- package/dist/collection/components/molecules/menu/mg-menu-item/mg-menu-item.js +118 -70
- package/dist/collection/components/molecules/mg-illustrated-message/mg-illustrated-message.js +4 -3
- package/dist/collection/components/molecules/mg-message/mg-message.css +7 -0
- package/dist/collection/components/molecules/mg-message/mg-message.js +53 -12
- package/dist/collection/components/molecules/mg-modal/mg-modal.css +8 -1
- package/dist/collection/components/molecules/mg-panel/mg-panel.css +7 -0
- package/dist/collection/components/molecules/mg-popover/mg-popover.css +72 -14
- package/dist/collection/components/molecules/mg-popover/mg-popover.js +48 -4
- package/dist/collection/components/molecules/mg-skip-links/doc/mg-skip-links.stories.js +1 -1
- package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.js +32 -1
- package/dist/collection/components/molecules/mg-tabs/doc/mg-tabs.stories.js +5 -3
- package/dist/collection/components/molecules/mg-tabs/mg-tabs.css +11 -7
- package/dist/collection/components/molecules/mg-tabs/mg-tabs.js +101 -54
- package/dist/collection/locales/en/messages.json +4 -0
- package/dist/collection/locales/fr/messages.json +4 -0
- package/dist/collection/locales/index.js +2 -25
- package/dist/collection/styles/a11y.scss +32 -0
- package/dist/collection/styles/components.scss +3 -0
- package/dist/collection/styles/fonts.scss +21 -0
- package/dist/collection/styles/form.scss +3 -0
- package/dist/collection/styles/global.scss +87 -0
- package/dist/collection/styles/layout.scss +29 -0
- package/dist/collection/styles/main.scss +23 -0
- package/dist/collection/styles/navigation-button.scss +76 -0
- package/dist/collection/styles/reset-mg-card-slotted-variables.scss +9 -0
- package/dist/collection/styles/typography.scss +75 -0
- package/dist/collection/styles/utilities.scss +21 -0
- package/dist/collection/utils/behaviors.utils.js +169 -0
- package/dist/collection/utils/components.utils.js +50 -0
- package/dist/collection/utils/locale.utils.js +22 -0
- package/dist/collection/utils/unit.test.utils.js +37 -32
- package/dist/collection/variables.css +9 -9
- package/dist/components/components.utils.js +51 -1
- package/dist/components/index2.js +65 -18
- package/dist/components/mg-badge2.js +4 -4
- package/dist/components/mg-button2.js +1 -1
- package/dist/components/mg-card2.js +1 -1
- package/dist/components/mg-icon2.js +13 -3
- package/dist/components/mg-illustrated-message.js +4 -3
- package/dist/components/mg-input-date.js +6 -4
- package/dist/components/mg-input-numeric.js +2 -3
- package/dist/components/mg-input-password.js +1 -1
- package/dist/components/mg-input-select2.js +8 -4
- package/dist/components/mg-input-text2.js +1 -1
- package/dist/components/mg-input-textarea.js +1 -1
- package/dist/components/mg-menu-item.js +1 -253
- package/dist/components/mg-menu-item2.js +517 -0
- package/dist/components/mg-menu.js +138 -21
- package/dist/components/mg-message.js +54 -13
- package/dist/components/mg-modal.js +1 -1
- package/dist/components/mg-panel.js +1 -1
- package/dist/components/mg-popover.js +1 -190
- package/dist/components/mg-popover2.js +212 -0
- package/dist/components/mg-skip-links.js +16 -2
- package/dist/components/mg-tabs.js +100 -52
- package/dist/components/mg-tag.js +4 -4
- package/dist/components/mg-tooltip2.js +4 -4
- package/dist/esm/{index-78edde1d.js → index-dc9a2348.js} +11 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/mg-badge_30.entry.js +742 -244
- package/dist/esm/mg-components.js +3 -3
- package/dist/esm/polyfills/css-shim.js +1 -1
- package/dist/mg-components/locales/en/messages.json +4 -0
- package/dist/mg-components/locales/fr/messages.json +4 -0
- package/dist/mg-components/mg-components.css +1 -1
- package/dist/mg-components/mg-components.esm.js +1 -1
- package/dist/mg-components/{p-125c54ca.js → p-182bd802.js} +2 -2
- package/dist/mg-components/p-f7da9dd2.entry.js +1 -0
- package/dist/mg-components/styles/a11y.scss +32 -0
- package/dist/mg-components/styles/components.scss +3 -0
- package/dist/mg-components/styles/fonts.scss +21 -0
- package/dist/mg-components/styles/form.scss +3 -0
- package/dist/mg-components/styles/global.scss +87 -0
- package/dist/mg-components/styles/layout.scss +29 -0
- package/dist/mg-components/styles/main.scss +23 -0
- package/dist/mg-components/styles/navigation-button.scss +76 -0
- package/dist/mg-components/styles/reset-mg-card-slotted-variables.scss +9 -0
- package/dist/mg-components/styles/typography.scss +75 -0
- package/dist/mg-components/styles/utilities.scss +21 -0
- package/dist/mg-components/variables.css +9 -9
- package/dist/types/components/atoms/mg-badge/mg-badge.conf.d.ts +2 -2
- package/dist/types/components/atoms/mg-button/mg-button.conf.d.ts +2 -2
- package/dist/types/components/atoms/mg-icon/mg-icon.conf.d.ts +2 -2
- package/dist/types/components/atoms/mg-tag/mg-tag.conf.d.ts +1 -1
- package/dist/types/components/molecules/inputs/MgInput.conf.d.ts +2 -2
- package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.conf.d.ts +2 -2
- package/dist/types/components/molecules/inputs/mg-input-radio/mg-input-radio.conf.d.ts +1 -1
- package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.conf.d.ts +2 -2
- package/dist/types/components/molecules/inputs/mg-input-toggle/mg-input-toggle.conf.d.ts +1 -1
- package/dist/types/components/molecules/menu/mg-menu/doc/mg-menu.stories.d.ts +5 -0
- package/dist/types/components/molecules/menu/mg-menu/mg-menu.conf.d.ts +37 -0
- package/dist/types/components/molecules/menu/mg-menu/mg-menu.d.ts +51 -3
- package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.conf.d.ts +0 -8
- package/dist/types/components/molecules/menu/mg-menu-item/mg-menu-item.d.ts +55 -15
- package/dist/types/components/molecules/mg-message/mg-message.d.ts +21 -4
- package/dist/types/components/molecules/mg-popover/mg-popover.d.ts +12 -0
- package/dist/types/components/molecules/mg-skip-links/mg-skip-links.conf.d.ts +1 -1
- package/dist/types/components/molecules/mg-skip-links/mg-skip-links.d.ts +15 -0
- package/dist/types/components/molecules/mg-tabs/mg-tabs.conf.d.ts +5 -3
- package/dist/types/components/molecules/mg-tabs/mg-tabs.d.ts +22 -12
- package/dist/types/components.d.ts +44 -12
- package/dist/types/locales/index.d.ts +10 -9
- package/dist/types/stencil-public-runtime.d.ts +39 -3
- package/dist/types/utils/behaviors.utils.d.ts +83 -0
- package/dist/types/utils/components.utils.d.ts +14 -0
- package/dist/types/utils/locale.utils.d.ts +13 -0
- package/dist/types/utils/unit.test.utils.d.ts +50 -14
- package/package.json +26 -26
- package/readme.md +22 -13
- package/dist/components/locale.utils.js +0 -40
- package/dist/components/mg-menu.conf.js +0 -10
- package/dist/mg-components/p-4961c96c.entry.js +0 -1
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Host, h } from '@stencil/core';
|
|
2
2
|
import { createID, isTagName } from '../../../utils/components.utils';
|
|
3
3
|
import { createPopper } from '@popperjs/core';
|
|
4
|
+
import { getWindows, ClassList } from '../../../utils/components.utils';
|
|
4
5
|
import { initLocales } from '../../../locales';
|
|
5
6
|
export class MgPopover {
|
|
6
7
|
constructor() {
|
|
7
8
|
this.closeButtonId = '';
|
|
9
|
+
// Classes
|
|
10
|
+
this.classArrowHide = `mg-popover--arrow-hide`;
|
|
8
11
|
/**
|
|
9
12
|
* Check if clicked outside of component
|
|
10
13
|
*
|
|
@@ -31,7 +34,9 @@ export class MgPopover {
|
|
|
31
34
|
// hide when click outside
|
|
32
35
|
// setTimeout is used to prevent event to trigger after creation
|
|
33
36
|
setTimeout(() => {
|
|
34
|
-
|
|
37
|
+
this.windows.forEach((localWindow) => {
|
|
38
|
+
localWindow.addEventListener('click', this.clickOutside, false);
|
|
39
|
+
});
|
|
35
40
|
}, 0);
|
|
36
41
|
};
|
|
37
42
|
/**
|
|
@@ -45,7 +50,9 @@ export class MgPopover {
|
|
|
45
50
|
// Disable the event listeners
|
|
46
51
|
this.popper.setOptions(options => (Object.assign(Object.assign({}, options), { modifiers: [...options.modifiers, { name: 'eventListeners', enabled: false }] })));
|
|
47
52
|
// Remove event listener
|
|
48
|
-
|
|
53
|
+
this.windows.forEach((localWindow) => {
|
|
54
|
+
localWindow.removeEventListener('click', this.clickOutside, false);
|
|
55
|
+
});
|
|
49
56
|
};
|
|
50
57
|
/**
|
|
51
58
|
* Handle action for close button
|
|
@@ -57,9 +64,17 @@ export class MgPopover {
|
|
|
57
64
|
};
|
|
58
65
|
this.identifier = createID('mg-popover');
|
|
59
66
|
this.placement = 'bottom';
|
|
67
|
+
this.arrowHide = false;
|
|
60
68
|
this.closeButton = false;
|
|
61
69
|
this.display = false;
|
|
62
70
|
this.disabled = false;
|
|
71
|
+
this.classList = new ClassList(['mg-popover']);
|
|
72
|
+
}
|
|
73
|
+
validateArrowHide(newValue) {
|
|
74
|
+
if (newValue)
|
|
75
|
+
this.classList.add(this.classArrowHide);
|
|
76
|
+
else
|
|
77
|
+
this.classList.delete(this.classArrowHide);
|
|
63
78
|
}
|
|
64
79
|
handleDisplay(newValue) {
|
|
65
80
|
if (newValue) {
|
|
@@ -79,8 +94,11 @@ export class MgPopover {
|
|
|
79
94
|
* @returns {void} timeout
|
|
80
95
|
*/
|
|
81
96
|
componentWillLoad() {
|
|
97
|
+
// Get windows to attach events
|
|
98
|
+
this.windows = getWindows(window);
|
|
82
99
|
// Get locales
|
|
83
100
|
this.messages = initLocales(this.element).messages;
|
|
101
|
+
this.validateArrowHide(this.arrowHide);
|
|
84
102
|
}
|
|
85
103
|
/**
|
|
86
104
|
* Check if component props are well configured on init
|
|
@@ -112,7 +130,7 @@ export class MgPopover {
|
|
|
112
130
|
{
|
|
113
131
|
name: 'offset',
|
|
114
132
|
options: {
|
|
115
|
-
offset: [0,
|
|
133
|
+
offset: [0, 0],
|
|
116
134
|
},
|
|
117
135
|
},
|
|
118
136
|
],
|
|
@@ -135,7 +153,7 @@ export class MgPopover {
|
|
|
135
153
|
* @returns {HTMLElement} HTML Element
|
|
136
154
|
*/
|
|
137
155
|
render() {
|
|
138
|
-
return (h(Host, null, h("slot", null), h("div", { id: this.identifier, class:
|
|
156
|
+
return (h(Host, null, h("slot", null), h("div", { id: this.identifier, class: this.classList.join() }, h("mg-card", null, this.closeButton && (h("mg-button", { identifier: this.closeButtonId, "is-icon": true, variant: "flat", label: this.messages.general.close, onClick: this.handleCloseButton }, h("mg-icon", { icon: "cross" }))), h("div", { class: "mg-popover__title" }, h("slot", { name: "title" })), h("slot", { name: "content" })), !this.arrowHide && h("div", { class: "mg-popover__arrow", "data-popper-arrow": true }))));
|
|
139
157
|
}
|
|
140
158
|
static get is() { return "mg-popover"; }
|
|
141
159
|
static get encapsulation() { return "shadow"; }
|
|
@@ -192,6 +210,24 @@ export class MgPopover {
|
|
|
192
210
|
"reflect": false,
|
|
193
211
|
"defaultValue": "'bottom'"
|
|
194
212
|
},
|
|
213
|
+
"arrowHide": {
|
|
214
|
+
"type": "boolean",
|
|
215
|
+
"mutable": false,
|
|
216
|
+
"complexType": {
|
|
217
|
+
"original": "boolean",
|
|
218
|
+
"resolved": "boolean",
|
|
219
|
+
"references": {}
|
|
220
|
+
},
|
|
221
|
+
"required": false,
|
|
222
|
+
"optional": false,
|
|
223
|
+
"docs": {
|
|
224
|
+
"tags": [],
|
|
225
|
+
"text": "Hide popover arrow"
|
|
226
|
+
},
|
|
227
|
+
"attribute": "arrow-hide",
|
|
228
|
+
"reflect": false,
|
|
229
|
+
"defaultValue": "false"
|
|
230
|
+
},
|
|
195
231
|
"closeButton": {
|
|
196
232
|
"type": "boolean",
|
|
197
233
|
"mutable": false,
|
|
@@ -248,6 +284,11 @@ export class MgPopover {
|
|
|
248
284
|
}
|
|
249
285
|
};
|
|
250
286
|
}
|
|
287
|
+
static get states() {
|
|
288
|
+
return {
|
|
289
|
+
"classList": {}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
251
292
|
static get events() {
|
|
252
293
|
return [{
|
|
253
294
|
"method": "displayChange",
|
|
@@ -269,6 +310,9 @@ export class MgPopover {
|
|
|
269
310
|
static get elementRef() { return "element"; }
|
|
270
311
|
static get watchers() {
|
|
271
312
|
return [{
|
|
313
|
+
"propName": "arrowHide",
|
|
314
|
+
"methodName": "validateArrowHide"
|
|
315
|
+
}, {
|
|
272
316
|
"propName": "display",
|
|
273
317
|
"methodName": "handleDisplay"
|
|
274
318
|
}];
|
|
@@ -3,7 +3,7 @@ import { filterArgs } from '../../../../../.storybook/utils';
|
|
|
3
3
|
export default {
|
|
4
4
|
component: 'mg-skip-links',
|
|
5
5
|
title: 'Molecules/mg-skip-links',
|
|
6
|
-
parameters: { actions: { handles: ['
|
|
6
|
+
parameters: { actions: { handles: ['go-to-anchor'] } },
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
* Template
|
|
@@ -2,6 +2,19 @@ import { h } from '@stencil/core';
|
|
|
2
2
|
import { initLocales } from '../../../locales';
|
|
3
3
|
export class MgSkipLinks {
|
|
4
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
|
+
};
|
|
5
18
|
this.links = undefined;
|
|
6
19
|
}
|
|
7
20
|
validateLinks(links) {
|
|
@@ -29,7 +42,7 @@ export class MgSkipLinks {
|
|
|
29
42
|
* @returns {HTMLElement} HTML Element
|
|
30
43
|
*/
|
|
31
44
|
render() {
|
|
32
|
-
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 }, link.label)))))));
|
|
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)))))));
|
|
33
46
|
}
|
|
34
47
|
static get is() { return "mg-skip-links"; }
|
|
35
48
|
static get encapsulation() { return "shadow"; }
|
|
@@ -67,6 +80,24 @@ export class MgSkipLinks {
|
|
|
67
80
|
}
|
|
68
81
|
};
|
|
69
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
|
+
}
|
|
70
101
|
static get elementRef() { return "element"; }
|
|
71
102
|
static get watchers() {
|
|
72
103
|
return [{
|
|
@@ -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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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));
|
|
@@ -16,25 +16,7 @@ export class MgTabs {
|
|
|
16
16
|
// classes
|
|
17
17
|
this.tabPanel = 'panel';
|
|
18
18
|
this.buttonTabBaseClass = 'mg-tabs__navigation-button';
|
|
19
|
-
// variables
|
|
20
19
|
this.startIndex = 1;
|
|
21
|
-
/**
|
|
22
|
-
* Method to set active tab
|
|
23
|
-
*
|
|
24
|
-
* @param {number} tabKey item tab key to set to ACTIVE status
|
|
25
|
-
* @returns {void}
|
|
26
|
-
*/
|
|
27
|
-
this.setActiveTab = (tabKey) => {
|
|
28
|
-
// reset active tabs
|
|
29
|
-
this.tabs.forEach(tab => {
|
|
30
|
-
if (this.tabHasGivenStatus(tab, Status.ACTIVE))
|
|
31
|
-
tab.status = Status.VISIBLE;
|
|
32
|
-
});
|
|
33
|
-
// set active tab from given tab key
|
|
34
|
-
this.tabs[tabKey - this.startIndex].status = Status.ACTIVE;
|
|
35
|
-
// emit change active tab key event
|
|
36
|
-
this.activeTabChange.emit(tabKey);
|
|
37
|
-
};
|
|
38
20
|
/**
|
|
39
21
|
* Method to know if given tab has the given status
|
|
40
22
|
*
|
|
@@ -42,7 +24,7 @@ export class MgTabs {
|
|
|
42
24
|
* @param {Status} status status to valide
|
|
43
25
|
* @returns {boolean} status comparaison
|
|
44
26
|
*/
|
|
45
|
-
this.
|
|
27
|
+
this.tabHasStatus = (tab, status) => tab.status === status;
|
|
46
28
|
/**
|
|
47
29
|
* Method to get element id from index
|
|
48
30
|
*
|
|
@@ -50,14 +32,20 @@ export class MgTabs {
|
|
|
50
32
|
* @param {number} index to generate id
|
|
51
33
|
* @returns {string} generated element id
|
|
52
34
|
*/
|
|
53
|
-
this.getElementId = (element, index) => `${element}-${this.
|
|
35
|
+
this.getElementId = (element, index) => `${element}-${this.getTabItemIndex(index)}`;
|
|
54
36
|
/**
|
|
55
|
-
* Method to get tab index
|
|
37
|
+
* Method to get tab item index
|
|
56
38
|
*
|
|
57
39
|
* @param {number} index to get
|
|
58
40
|
* @returns {number} index
|
|
59
41
|
*/
|
|
60
|
-
this.
|
|
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);
|
|
61
49
|
/**
|
|
62
50
|
* Handle click events on tabs
|
|
63
51
|
*
|
|
@@ -65,16 +53,22 @@ export class MgTabs {
|
|
|
65
53
|
*/
|
|
66
54
|
this.handleClick = (event) => {
|
|
67
55
|
const tabId = event.currentTarget.getAttribute('data-index');
|
|
68
|
-
|
|
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
|
+
}
|
|
69
64
|
};
|
|
70
65
|
/**
|
|
71
66
|
* get navigation button class from given status
|
|
72
67
|
*
|
|
73
68
|
* @param {Status} status button tab status
|
|
74
|
-
* @param {boolean} isSelector set if we need a CSS selector with the dot '.' at the begin. default value = false.
|
|
75
69
|
* @returns {string} button class/selector variant
|
|
76
70
|
*/
|
|
77
|
-
this.getNavigationButtonClass = (status
|
|
71
|
+
this.getNavigationButtonClass = (status) => `${this.buttonTabBaseClass}--${status}`;
|
|
78
72
|
/**
|
|
79
73
|
* Handle keyboard event on tabs
|
|
80
74
|
*
|
|
@@ -82,37 +76,65 @@ export class MgTabs {
|
|
|
82
76
|
* @returns {void}
|
|
83
77
|
*/
|
|
84
78
|
this.handleKeydown = (event) => {
|
|
85
|
-
let tabId = Number(event.target.getAttribute('data-index'));
|
|
86
79
|
const parent = event.target.parentElement;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
+
}
|
|
93
106
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// apply selected tab if exist
|
|
97
|
-
if (selectedTab !== null) {
|
|
98
|
-
selectedTab.focus();
|
|
99
|
-
this.activeTab = tabId;
|
|
107
|
+
else if (event.key === 'Tab') {
|
|
108
|
+
this.resetFocus();
|
|
100
109
|
}
|
|
101
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
|
+
};
|
|
102
125
|
/**
|
|
103
126
|
* Validate slots setting
|
|
104
127
|
*/
|
|
105
128
|
this.validateSlots = () => {
|
|
106
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-'); });
|
|
107
|
-
if (slots.length !== this.tabs.length)
|
|
130
|
+
if (slots.length !== this.tabs.length)
|
|
108
131
|
throw new Error('<mg-tabs> Must have slots counts equal to tabs count.');
|
|
109
|
-
}
|
|
110
132
|
};
|
|
111
133
|
this.identifier = createID('mg-tabs');
|
|
112
134
|
this.label = undefined;
|
|
113
135
|
this.size = 'regular';
|
|
114
136
|
this.items = undefined;
|
|
115
|
-
this.activeTab =
|
|
137
|
+
this.activeTab = undefined;
|
|
116
138
|
this.tabs = [];
|
|
117
139
|
this.classList = new ClassList(['mg-tabs']);
|
|
118
140
|
}
|
|
@@ -130,22 +152,37 @@ export class MgTabs {
|
|
|
130
152
|
validateItems(newValue) {
|
|
131
153
|
// String array
|
|
132
154
|
if (allItemsAreString(newValue)) {
|
|
133
|
-
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 }));
|
|
134
156
|
}
|
|
135
157
|
// Object array
|
|
136
|
-
else if (newValue && newValue.every(item => isTabItem(item))) {
|
|
158
|
+
else if (newValue && newValue.length > 0 && newValue.every(item => isTabItem(item))) {
|
|
137
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;
|
|
138
163
|
}
|
|
139
164
|
else {
|
|
140
165
|
throw new Error('<mg-tabs> prop "items" is required and all items must be the same type: TabItem.');
|
|
141
166
|
}
|
|
142
167
|
}
|
|
143
168
|
validateActiveTab(newValue) {
|
|
144
|
-
if (newValue
|
|
145
|
-
|
|
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
|
+
}
|
|
146
183
|
}
|
|
147
|
-
else {
|
|
148
|
-
|
|
184
|
+
else if (newValue !== undefined) {
|
|
185
|
+
throw new Error('<mg-tabs> prop "activeTab" must be between 1 and tabs length.');
|
|
149
186
|
}
|
|
150
187
|
}
|
|
151
188
|
/*************
|
|
@@ -164,6 +201,17 @@ export class MgTabs {
|
|
|
164
201
|
this.validateSize(this.size);
|
|
165
202
|
this.validateSlots();
|
|
166
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
|
+
}
|
|
167
215
|
/**
|
|
168
216
|
* Render
|
|
169
217
|
*
|
|
@@ -173,10 +221,10 @@ export class MgTabs {
|
|
|
173
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: {
|
|
174
222
|
[`${this.buttonTabBaseClass}`]: true,
|
|
175
223
|
[`${this.buttonTabBaseClass}--horizontal`]: true,
|
|
176
|
-
[`${this.getNavigationButtonClass(Status.ACTIVE)}`]: this.
|
|
177
|
-
[`${this.getNavigationButtonClass(Status.DISABLED)}`]: this.
|
|
178
|
-
[`${this.getNavigationButtonClass(Status.HIDDEN)}`]: this.
|
|
179
|
-
}, tabindex: this.
|
|
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) }))))));
|
|
180
228
|
}
|
|
181
229
|
static get is() { return "mg-tabs"; }
|
|
182
230
|
static get encapsulation() { return "shadow"; }
|
|
@@ -282,11 +330,10 @@ export class MgTabs {
|
|
|
282
330
|
"optional": false,
|
|
283
331
|
"docs": {
|
|
284
332
|
"tags": [],
|
|
285
|
-
"text": "Active tab number
|
|
333
|
+
"text": "Active tab number"
|
|
286
334
|
},
|
|
287
335
|
"attribute": "active-tab",
|
|
288
|
-
"reflect": true
|
|
289
|
-
"defaultValue": "1"
|
|
336
|
+
"reflect": true
|
|
290
337
|
}
|
|
291
338
|
};
|
|
292
339
|
}
|
|
@@ -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
|
-
|
|
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,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open Sans
|
|
3
|
+
* https://fonts.google.com/specimen/Open+Sans
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
@font-face {
|
|
7
|
+
font-family: 'Open Sans';
|
|
8
|
+
src: url('fonts/OpenSans-Regular.ttf') format('truetype');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@font-face {
|
|
12
|
+
font-family: 'Open Sans';
|
|
13
|
+
font-weight: 600;
|
|
14
|
+
src: url('fonts/OpenSans-SemiBold.ttf') format('truetype');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@font-face {
|
|
18
|
+
font-family: 'Open Sans';
|
|
19
|
+
font-weight: 700;
|
|
20
|
+
src: url('fonts/OpenSans-Bold.ttf') format('truetype');
|
|
21
|
+
}
|