@brightspace-ui/core 2.0.2 → 2.1.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.
|
@@ -19,20 +19,26 @@
|
|
|
19
19
|
|
|
20
20
|
<div style="margin-bottom: 30px;">
|
|
21
21
|
<d2l-button-subtle id="add" text="Add"></d2l-button-subtle>
|
|
22
|
+
<d2l-button-subtle id="add-selected" text="Add Selected"></d2l-button-subtle>
|
|
22
23
|
<d2l-button-subtle id="remove" text="Remove"></d2l-button-subtle>
|
|
23
24
|
</div>
|
|
24
25
|
<script>
|
|
25
26
|
let newPanelId = 0;
|
|
26
|
-
|
|
27
|
+
const addPanel = selected => {
|
|
27
28
|
newPanelId += 1;
|
|
28
29
|
const panel = document.createElement('d2l-tab-panel');
|
|
30
|
+
panel.selected = selected;
|
|
29
31
|
panel.text = `New Panel ${newPanelId}`;
|
|
30
32
|
panel.textContent = `Content for new panel ${newPanelId}`;
|
|
31
33
|
const tabs = document.querySelector('d2l-tabs');
|
|
32
34
|
const panels = [...tabs.querySelectorAll('d2l-tab-panel')];
|
|
33
35
|
if (panels.length < 2) tabs.appendChild(panel);
|
|
34
36
|
else tabs.insertBefore(panel, panels[1]);
|
|
35
|
-
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
document.querySelector('#add').addEventListener('click', () => addPanel(false));
|
|
40
|
+
document.querySelector('#add-selected').addEventListener('click', () => addPanel(true));
|
|
41
|
+
|
|
36
42
|
document.querySelector('#remove').addEventListener('click', () => {
|
|
37
43
|
const tabs = document.querySelector('d2l-tabs');
|
|
38
44
|
const panels = [...tabs.querySelectorAll('d2l-tab-panel')];
|
|
@@ -73,30 +79,32 @@
|
|
|
73
79
|
|
|
74
80
|
<d2l-demo-snippet>
|
|
75
81
|
<template>
|
|
76
|
-
<
|
|
77
|
-
<d2l-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
82
|
+
<div style="max-width: 500px;">
|
|
83
|
+
<d2l-tabs>
|
|
84
|
+
<d2l-tab-panel text="S18">Tab content for S18</d2l-tab-panel>
|
|
85
|
+
<d2l-tab-panel text="W18">Tab content for W18</d2l-tab-panel>
|
|
86
|
+
<d2l-tab-panel text="F17">Tab content for F17</d2l-tab-panel>
|
|
87
|
+
<d2l-tab-panel text="S17">Tab content for S17</d2l-tab-panel>
|
|
88
|
+
<d2l-tab-panel text="W17">Tab content for W17</d2l-tab-panel>
|
|
89
|
+
<d2l-tab-panel text="F16">Tab content for F16</d2l-tab-panel>
|
|
90
|
+
<d2l-tab-panel text="S16">Tab content for S16</d2l-tab-panel>
|
|
91
|
+
<d2l-tab-panel text="W16">Tab content for W16</d2l-tab-panel>
|
|
92
|
+
<d2l-tab-panel text="F15">Tab content for F15</d2l-tab-panel>
|
|
93
|
+
<d2l-tab-panel text="S15">Tab content for S15</d2l-tab-panel>
|
|
94
|
+
<d2l-tab-panel text="W15">Tab content for W15</d2l-tab-panel>
|
|
95
|
+
<d2l-tab-panel text="F14">Tab content for F14</d2l-tab-panel>
|
|
96
|
+
<d2l-tab-panel text="S14">Tab content for S14</d2l-tab-panel>
|
|
97
|
+
<d2l-tab-panel text="W14">Tab content for W14</d2l-tab-panel>
|
|
98
|
+
<d2l-tab-panel text="F13">Tab content for F13</d2l-tab-panel>
|
|
99
|
+
<d2l-tab-panel text="S13">Tab content for S13</d2l-tab-panel>
|
|
100
|
+
<d2l-tab-panel text="W13">Tab content for W13</d2l-tab-panel>
|
|
101
|
+
<d2l-tab-panel text="F12">Tab content for F12</d2l-tab-panel>
|
|
102
|
+
<d2l-tab-panel text="S12">Tab content for S12</d2l-tab-panel>
|
|
103
|
+
<d2l-tab-panel text="W12">Tab content for W12</d2l-tab-panel>
|
|
104
|
+
<d2l-tab-panel text="F11">Tab content for F11</d2l-tab-panel>
|
|
105
|
+
<d2l-tab-panel text="S11">Tab content for S11</d2l-tab-panel>
|
|
106
|
+
</d2l-tabs>
|
|
107
|
+
</div>
|
|
100
108
|
</template>
|
|
101
109
|
</d2l-demo-snippet>
|
|
102
110
|
|
|
@@ -51,17 +51,6 @@ export const TabPanelMixin = superclass => class extends superclass {
|
|
|
51
51
|
this.selected = false;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
async attributeChangedCallback(name, oldval, newval) {
|
|
55
|
-
super.attributeChangedCallback(name, oldval, newval);
|
|
56
|
-
if (name === 'text') {
|
|
57
|
-
this.setAttribute('aria-label', this.text);
|
|
58
|
-
/** Dispatched when the text attribute is changed */
|
|
59
|
-
this.dispatchEvent(new CustomEvent(
|
|
60
|
-
'd2l-tab-panel-text-changed', { bubbles: true, composed: true, detail: { text: this.text } }
|
|
61
|
-
));
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
54
|
connectedCallback() {
|
|
66
55
|
super.connectedCallback();
|
|
67
56
|
if (this.id.length === 0) this.id = getUniqueId();
|
|
@@ -80,6 +69,11 @@ export const TabPanelMixin = superclass => class extends superclass {
|
|
|
80
69
|
));
|
|
81
70
|
});
|
|
82
71
|
}
|
|
72
|
+
} else if (prop === 'text') {
|
|
73
|
+
this.setAttribute('aria-label', this.text);
|
|
74
|
+
this.dispatchEvent(new CustomEvent(
|
|
75
|
+
'd2l-tab-panel-text-changed', { bubbles: true, composed: true, detail: { text: this.text } }
|
|
76
|
+
));
|
|
83
77
|
}
|
|
84
78
|
});
|
|
85
79
|
}
|
package/components/tabs/tabs.js
CHANGED
|
@@ -4,7 +4,6 @@ import '../../helpers/queueMicrotask.js';
|
|
|
4
4
|
import './tab-internal.js';
|
|
5
5
|
import { css, html, LitElement } from 'lit-element/lit-element.js';
|
|
6
6
|
import { cssEscape, findComposedAncestor } from '../../helpers/dom.js';
|
|
7
|
-
import { getNextFocusable, getPreviousFocusable } from '../../helpers/focus.js';
|
|
8
7
|
import { ArrowKeysMixin } from '../../mixins/arrow-keys-mixin.js';
|
|
9
8
|
import { bodyCompactStyles } from '../typography/styles.js';
|
|
10
9
|
import { classMap } from 'lit-html/directives/class-map.js';
|
|
@@ -125,11 +124,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
125
124
|
transition: transform 200ms ease-out;
|
|
126
125
|
white-space: nowrap;
|
|
127
126
|
}
|
|
128
|
-
.d2l-tabs-focus-start,
|
|
129
|
-
.d2l-tabs-focus-end {
|
|
130
|
-
left: 0;
|
|
131
|
-
position: absolute;
|
|
132
|
-
}
|
|
133
127
|
.d2l-tabs-scroll-previous-container,
|
|
134
128
|
.d2l-tabs-scroll-next-container {
|
|
135
129
|
background-color: var(--d2l-tabs-background-color);
|
|
@@ -280,6 +274,11 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
280
274
|
|
|
281
275
|
this.arrowKeysOnBeforeFocus = async(tab) => {
|
|
282
276
|
const tabInfo = this._getTabInfo(tab.controlsPanel);
|
|
277
|
+
this._setFocusable(tabInfo);
|
|
278
|
+
|
|
279
|
+
this.requestUpdate();
|
|
280
|
+
await this.updateComplete;
|
|
281
|
+
|
|
283
282
|
if (!this._scrollCollapsed) {
|
|
284
283
|
return this._updateScrollPosition(tabInfo);
|
|
285
284
|
} else {
|
|
@@ -340,22 +339,22 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
340
339
|
<d2l-icon icon="tier1:chevron-left"></d2l-icon>
|
|
341
340
|
</button>
|
|
342
341
|
</div>
|
|
343
|
-
<span class="d2l-tabs-focus-start" @focus="${this._handleFocusStart}" tabindex="0"></span>
|
|
344
342
|
${this.arrowKeysContainer(html`
|
|
345
343
|
<div class="d2l-tabs-container-list"
|
|
346
344
|
@d2l-tab-selected="${this._handleTabSelected}"
|
|
345
|
+
@focusout="${this._handleFocusOut}"
|
|
347
346
|
role="tablist"
|
|
348
347
|
style="${styleMap(tabsContainerListStyles)}">
|
|
349
348
|
${repeat(this._tabInfos, (tabInfo) => tabInfo.id, (tabInfo) => html`
|
|
350
349
|
<d2l-tab-internal aria-selected="${tabInfo.selected ? 'true' : 'false'}"
|
|
351
350
|
.controlsPanel="${tabInfo.id}"
|
|
352
351
|
data-state="${tabInfo.state}"
|
|
352
|
+
tabindex="${tabInfo.activeFocusable ? 0 : -1}"
|
|
353
353
|
text="${tabInfo.text}">
|
|
354
354
|
</d2l-tab-internal>
|
|
355
355
|
`)}
|
|
356
356
|
</div>
|
|
357
357
|
`)}
|
|
358
|
-
<span class="d2l-tabs-focus-end" @focus="${this._handleFocusEnd}" tabindex="0"></span>
|
|
359
358
|
<div class="d2l-tabs-scroll-next-container">
|
|
360
359
|
<button class="d2l-tabs-scroll-button"
|
|
361
360
|
@click="${this._handleScrollNext}"
|
|
@@ -552,28 +551,17 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
552
551
|
}
|
|
553
552
|
}
|
|
554
553
|
|
|
555
|
-
|
|
556
|
-
if (e.relatedTarget && e.relatedTarget.role
|
|
557
|
-
|
|
558
|
-
} else {
|
|
559
|
-
const nextFocusable = getNextFocusable(e.target, false);
|
|
560
|
-
if (nextFocusable) nextFocusable.focus();
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
_handleFocusStart(e) {
|
|
565
|
-
if (e.relatedTarget && e.relatedTarget.role === 'tab') {
|
|
566
|
-
const previousFocusable = getPreviousFocusable(e.target, false);
|
|
567
|
-
if (previousFocusable) previousFocusable.focus();
|
|
568
|
-
} else {
|
|
569
|
-
this._focusSelected();
|
|
570
|
-
}
|
|
554
|
+
_handleFocusOut(e) {
|
|
555
|
+
if (e.relatedTarget && e.relatedTarget.role === 'tab') return;
|
|
556
|
+
this._resetFocusables();
|
|
571
557
|
}
|
|
572
558
|
|
|
573
559
|
_handlePanelSelected(e) {
|
|
574
560
|
const tabInfo = this._getTabInfo(e.target.id);
|
|
575
561
|
// event could be from nested tabs
|
|
576
562
|
if (!tabInfo) return;
|
|
563
|
+
|
|
564
|
+
this._setFocusable(tabInfo);
|
|
577
565
|
tabInfo.selected = true;
|
|
578
566
|
this.requestUpdate();
|
|
579
567
|
}
|
|
@@ -603,7 +591,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
603
591
|
selected: panel.selected,
|
|
604
592
|
state: state
|
|
605
593
|
};
|
|
606
|
-
if (tabInfo.selected)
|
|
594
|
+
if (tabInfo.selected) {
|
|
595
|
+
selectedTabInfo = tabInfo;
|
|
596
|
+
this._setFocusable(tabInfo);
|
|
597
|
+
}
|
|
607
598
|
return tabInfo;
|
|
608
599
|
});
|
|
609
600
|
|
|
@@ -619,6 +610,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
619
610
|
this._tabInfos = newTabInfos;
|
|
620
611
|
|
|
621
612
|
if (this._tabInfos.length > 0 && !selectedTabInfo) {
|
|
613
|
+
this._tabInfos[0].activeFocusable = true;
|
|
622
614
|
this._tabInfos[0].selected = true;
|
|
623
615
|
selectedTabInfo = this._tabInfos[0];
|
|
624
616
|
}
|
|
@@ -756,19 +748,24 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
756
748
|
const selectedTab = e.target;
|
|
757
749
|
const selectedPanel = this._getPanel(selectedTab.controlsPanel);
|
|
758
750
|
const selectedTabInfo = this._getTabInfo(selectedTab.controlsPanel);
|
|
751
|
+
selectedTabInfo.activeFocusable = true;
|
|
759
752
|
|
|
760
753
|
await this.updateComplete;
|
|
761
754
|
this._updateScrollPosition(selectedTabInfo);
|
|
762
755
|
|
|
763
756
|
selectedPanel.selected = true;
|
|
764
757
|
this._tabInfos.forEach((tabInfo) => {
|
|
765
|
-
if (tabInfo.
|
|
766
|
-
tabInfo.selected
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
758
|
+
if (tabInfo.id !== selectedTab.controlsPanel) {
|
|
759
|
+
if (tabInfo.selected) {
|
|
760
|
+
tabInfo.selected = false;
|
|
761
|
+
const panel = this._getPanel(tabInfo.id);
|
|
762
|
+
// panel may not exist if it's being removed
|
|
763
|
+
if (panel) panel.selected = false;
|
|
764
|
+
}
|
|
765
|
+
if (tabInfo.activeFocusable) tabInfo.activeFocusable = false;
|
|
770
766
|
}
|
|
771
767
|
});
|
|
768
|
+
|
|
772
769
|
this.requestUpdate();
|
|
773
770
|
}
|
|
774
771
|
|
|
@@ -780,6 +777,12 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
780
777
|
return (position > measures.tabsContainerRect.width - scrollButtonWidth) && (position < measures.tabsContainerRect.width);
|
|
781
778
|
}
|
|
782
779
|
|
|
780
|
+
_resetFocusables() {
|
|
781
|
+
const selectedTab = this._tabInfos.find(ti => ti.selected);
|
|
782
|
+
if (selectedTab) this._setFocusable(selectedTab);
|
|
783
|
+
this.requestUpdate();
|
|
784
|
+
}
|
|
785
|
+
|
|
783
786
|
_scrollToPosition(translationValue) {
|
|
784
787
|
if (translationValue === this._translationValue) {
|
|
785
788
|
return Promise.resolve();
|
|
@@ -801,6 +804,13 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
|
|
|
801
804
|
});
|
|
802
805
|
}
|
|
803
806
|
|
|
807
|
+
_setFocusable(tabInfo) {
|
|
808
|
+
const currentFocusable = this._tabInfos.find(ti => ti.activeFocusable);
|
|
809
|
+
if (currentFocusable) currentFocusable.activeFocusable = false;
|
|
810
|
+
|
|
811
|
+
tabInfo.activeFocusable = true;
|
|
812
|
+
}
|
|
813
|
+
|
|
804
814
|
async _tryExpandTabsContainer(measures) {
|
|
805
815
|
|
|
806
816
|
if (!this._scrollCollapsed) return false;
|
package/custom-elements.json
CHANGED
|
@@ -9702,13 +9702,12 @@
|
|
|
9702
9702
|
}
|
|
9703
9703
|
],
|
|
9704
9704
|
"events": [
|
|
9705
|
-
{
|
|
9706
|
-
"name": "d2l-tab-panel-text-changed",
|
|
9707
|
-
"description": "Dispatched when the text attribute is changed"
|
|
9708
|
-
},
|
|
9709
9705
|
{
|
|
9710
9706
|
"name": "d2l-tab-panel-selected",
|
|
9711
9707
|
"description": "Dispatched when a tab is selected"
|
|
9708
|
+
},
|
|
9709
|
+
{
|
|
9710
|
+
"name": "d2l-tab-panel-text-changed"
|
|
9712
9711
|
}
|
|
9713
9712
|
],
|
|
9714
9713
|
"slots": [
|
|
@@ -2,11 +2,17 @@ import { getLocalizeOverrideResources } from '../helpers/getLocalizeResources.js
|
|
|
2
2
|
import { LocalizeMixin } from './localize-mixin.js';
|
|
3
3
|
|
|
4
4
|
const fallbackLang = 'en';
|
|
5
|
+
const supportedLangpacks = ['ar', 'cy', 'da', 'de', 'en', 'es', 'es-es', 'fr', 'fr-fr', 'fr-on', 'hi', 'ja', 'ko', 'nl', 'pt', 'sv', 'tr', 'zh-cn', 'zh-tw'];
|
|
5
6
|
|
|
6
7
|
export const LocalizeDynamicMixin = superclass => class extends LocalizeMixin(superclass) {
|
|
7
8
|
|
|
8
9
|
static async getLocalizeResources(langs, { importFunc, osloCollection }) {
|
|
9
10
|
|
|
11
|
+
// in dev, don't request unsupported langpacks
|
|
12
|
+
if (!importFunc.toString().includes('switch')) {
|
|
13
|
+
langs = langs.filter(lang => supportedLangpacks.includes(lang));
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
for (const lang of [...langs, fallbackLang]) {
|
|
11
17
|
|
|
12
18
|
const resources = await importFunc(lang).catch(() => {});
|
package/mixins/localize-mixin.md
CHANGED
|
@@ -83,7 +83,9 @@ class MyComponent extends LocalizeDynamicMixin(LitElement) {
|
|
|
83
83
|
}
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
When using this method, depending on various user settings, it's possible that a language file that does not exist will be requested, resulting in a network error (404). In production, your build system should prevent this by transpiling the variable dynamic import into a `switch` statement.
|
|
87
|
+
|
|
88
|
+
If your build system does not support variable dynamic imports, you'll need to manually set up imports for each supported language:
|
|
87
89
|
|
|
88
90
|
```javascript
|
|
89
91
|
static get localizeConfig() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A collection of accessible, free, open-source web components for building Brightspace applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://github.com/BrightspaceUI/core.git",
|