@brightspace-ui/core 3.93.1 → 3.94.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.
@@ -40,12 +40,12 @@
|
|
40
40
|
|
41
41
|
<d2l-demo-snippet>
|
42
42
|
<template>
|
43
|
-
<d2l-tabs>
|
43
|
+
<d2l-tabs text="Courses">
|
44
44
|
<d2l-tab id="all" text="All" slot="tabs"></d2l-tab>
|
45
|
-
<d2l-tab id="biology" text="Biology" slot="tabs"></d2l-tab>
|
45
|
+
<d2l-tab id="biology" text="Biology" slot="tabs" selected></d2l-tab>
|
46
46
|
<d2l-tab id="chemistry" text="Chemistry" slot="tabs"></d2l-tab>
|
47
|
-
<d2l-tab-panel labelled-by="all" slot="panels">Tab content for All</d2l-tab-panel>
|
48
|
-
<d2l-tab-panel labelled-by="biology" slot="panels">Tab content for Biology</d2l-tab-panel>
|
47
|
+
<d2l-tab-panel labelled-by="all" slot="panels" id="all-panel">Tab content for All</d2l-tab-panel>
|
48
|
+
<d2l-tab-panel labelled-by="biology" slot="panels" id="biology-panel">Tab content for Biology</d2l-tab-panel>
|
49
49
|
<d2l-tab-panel labelled-by="chemistry" slot="panels">Tab content for Chemistry</d2l-tab-panel>
|
50
50
|
</d2l-tabs>
|
51
51
|
</template>
|
@@ -13,7 +13,8 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
|
|
13
13
|
return {
|
14
14
|
selected: { type: Boolean, reflect: true },
|
15
15
|
// eslint-disable-next-line lit/no-native-attributes
|
16
|
-
role: { type: String, reflect: true }
|
16
|
+
role: { type: String, reflect: true },
|
17
|
+
tabIndex: { type: Number, reflect: true, attribute: 'tabindex' }
|
17
18
|
};
|
18
19
|
}
|
19
20
|
|
@@ -42,18 +43,18 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
|
|
42
43
|
margin-inline-start: 0;
|
43
44
|
width: calc(100% - 0.6rem);
|
44
45
|
}
|
45
|
-
:host([
|
46
|
+
:host([selected]:focus) {
|
46
47
|
text-decoration: none;
|
47
48
|
}
|
48
49
|
:host(:hover) {
|
49
50
|
color: var(--d2l-color-celestine);
|
50
51
|
cursor: pointer;
|
51
52
|
}
|
52
|
-
:host([
|
53
|
+
:host([selected]:hover) {
|
53
54
|
color: inherit;
|
54
55
|
cursor: default;
|
55
56
|
}
|
56
|
-
:host([
|
57
|
+
:host([selected]) .d2l-tab-selected-indicator {
|
57
58
|
display: block;
|
58
59
|
}
|
59
60
|
`];
|
@@ -66,6 +67,7 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
|
|
66
67
|
super();
|
67
68
|
this.role = 'tab';
|
68
69
|
this.selected = false;
|
70
|
+
this.tabIndex = -1;
|
69
71
|
}
|
70
72
|
|
71
73
|
connectedCallback() {
|
@@ -101,7 +103,7 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
|
|
101
103
|
super.update(changedProperties);
|
102
104
|
|
103
105
|
if (changedProperties.has('selected')) {
|
104
|
-
this.ariaSelected = this.selected
|
106
|
+
this.ariaSelected = `${this.selected}`;
|
105
107
|
if (this.selected) {
|
106
108
|
this.dispatchEvent(new CustomEvent(
|
107
109
|
'd2l-tab-selected', { bubbles: true, composed: true }
|
package/components/tabs/tabs.js
CHANGED
@@ -8,6 +8,7 @@ import { ArrowKeysMixin } from '../../mixins/arrow-keys/arrow-keys-mixin.js';
|
|
8
8
|
import { bodyCompactStyles } from '../typography/styles.js';
|
9
9
|
import { classMap } from 'lit/directives/class-map.js';
|
10
10
|
import { getFocusPseudoClass } from '../../helpers/focus.js';
|
11
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
11
12
|
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
|
12
13
|
import { repeat } from 'lit/directives/repeat.js';
|
13
14
|
import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
|
@@ -32,6 +33,11 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
32
33
|
* @type {number}
|
33
34
|
*/
|
34
35
|
maxToShow: { type: Number, attribute: 'max-to-show' },
|
36
|
+
/**
|
37
|
+
* REQUIRED: ACCESSIBILITY: Accessible text for the tablist
|
38
|
+
* @type {string}
|
39
|
+
*/
|
40
|
+
text: { type: String },
|
35
41
|
_allowScrollNext: { type: Boolean },
|
36
42
|
_allowScrollPrevious: { type: Boolean },
|
37
43
|
_defaultSlotBehavior: { state: true },
|
@@ -305,6 +311,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
305
311
|
<div class="d2l-tabs-container-list"
|
306
312
|
@d2l-tab-selected="${this._handleTabSelected}"
|
307
313
|
@focusout="${this._handleFocusOut}"
|
314
|
+
aria-label="${ifDefined(this.text)}"
|
308
315
|
role="tablist"
|
309
316
|
style="${styleMap(tabsContainerListStyles)}">
|
310
317
|
${repeat(this._tabInfos, (tabInfo) => tabInfo.id, (tabInfo) => html`
|
@@ -333,7 +340,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
333
340
|
@d2l-tab-panel-selected="${this._handlePanelSelected}"
|
334
341
|
@d2l-tab-panel-text-changed="${this._handlePanelTextChange}">
|
335
342
|
<slot @slotchange="${this._handleDefaultSlotChange}"></slot>
|
336
|
-
<slot name="panels"></slot>
|
343
|
+
<slot name="panels" @slotchange="${this._handlePanelsSlotChange}"></slot>
|
337
344
|
</div>
|
338
345
|
`;
|
339
346
|
}
|
@@ -630,6 +637,12 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
630
637
|
this.requestUpdate();
|
631
638
|
}
|
632
639
|
|
640
|
+
_handlePanelsSlotChange() {
|
641
|
+
if (this._defaultSlotBehavior) return;
|
642
|
+
|
643
|
+
this.#setAriaControls();
|
644
|
+
}
|
645
|
+
|
633
646
|
async _handlePanelTextChange(e) {
|
634
647
|
const tabInfo = this._getTabInfo(e.target.id);
|
635
648
|
// event could be from nested tabs
|
@@ -725,32 +738,14 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
725
738
|
|
726
739
|
}
|
727
740
|
|
728
|
-
|
741
|
+
_handleTabSelected(e) {
|
729
742
|
if (this._defaultSlotBehavior) {
|
730
743
|
this._handleTabSelectedDefaultSlotBehavior(e);
|
731
744
|
return;
|
732
745
|
}
|
733
746
|
|
734
747
|
const selectedTab = e.target;
|
735
|
-
|
736
|
-
selectedTab.tabIndex = 0;
|
737
|
-
|
738
|
-
await this.updateComplete;
|
739
|
-
|
740
|
-
selectedPanel.selected = true;
|
741
|
-
this._tabs.forEach((tab) => {
|
742
|
-
if (tab.id !== selectedTab.id) {
|
743
|
-
if (tab.selected) {
|
744
|
-
tab.selected = false;
|
745
|
-
const panel = this._getPanel(tab.id);
|
746
|
-
// panel may not exist if it's being removed
|
747
|
-
if (panel) panel.selected = false;
|
748
|
-
}
|
749
|
-
if (tab.tabIndex === 0) tab.tabIndex = -1;
|
750
|
-
}
|
751
|
-
});
|
752
|
-
|
753
|
-
this.requestUpdate();
|
748
|
+
this.#updateSelectedTab(selectedTab);
|
754
749
|
}
|
755
750
|
|
756
751
|
// remove after d2l-tab/d2l-tab-panel backport
|
@@ -791,26 +786,21 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
791
786
|
|
792
787
|
if (!this._initialized && this._tabs.length === 0) return;
|
793
788
|
|
794
|
-
let selectedTab;
|
795
|
-
if (
|
789
|
+
let selectedTab = this._tabs.find((tab) => tab.selected && tab.state !== 'removing');
|
790
|
+
if (!selectedTab) {
|
796
791
|
selectedTab = this._tabs.find((tab) => tab.state !== 'removing');
|
797
|
-
if (selectedTab)
|
798
|
-
|
799
|
-
|
800
|
-
|
792
|
+
if (selectedTab) selectedTab.selected = true;
|
793
|
+
}
|
794
|
+
if (selectedTab) {
|
795
|
+
this.#updateSelectedTab(selectedTab);
|
801
796
|
}
|
797
|
+
this.#setAriaControls();
|
802
798
|
|
803
799
|
await this.updateComplete;
|
804
800
|
|
805
801
|
if (!this._initialized && this._tabs.length > 0) {
|
806
802
|
this._initialized = true;
|
807
803
|
}
|
808
|
-
|
809
|
-
if (selectedTab) {
|
810
|
-
// set corresponding panel to selected
|
811
|
-
const selectedPanel = this._getPanel(selectedTab.id);
|
812
|
-
if (selectedPanel) selectedPanel.selected = true;
|
813
|
-
}
|
814
804
|
}
|
815
805
|
|
816
806
|
_isPositionInLeftScrollArea(position) {
|
@@ -1015,6 +1005,41 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
1015
1005
|
return document.documentElement.getAttribute('dir') === 'rtl';
|
1016
1006
|
}
|
1017
1007
|
|
1008
|
+
#setAriaControls() {
|
1009
|
+
// debounce so only runs once when tabs/panels slots changing
|
1010
|
+
if (this._updateAriaControlsRequested) return;
|
1011
|
+
|
1012
|
+
this._updateAriaControlsRequested = true;
|
1013
|
+
setTimeout(() => {
|
1014
|
+
this._tabs?.forEach((tab) => {
|
1015
|
+
const panel = this._getPanel(tab.id);
|
1016
|
+
if (!panel) return;
|
1017
|
+
tab.setAttribute('aria-controls', `${panel.id}`);
|
1018
|
+
});
|
1019
|
+
this._updateAriaControlsRequested = false;
|
1020
|
+
}, 0);
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
async #updateSelectedTab(selectedTab) {
|
1024
|
+
const selectedPanel = this._getPanel(selectedTab.id);
|
1025
|
+
selectedTab.tabIndex = 0;
|
1026
|
+
|
1027
|
+
await this.updateComplete;
|
1028
|
+
|
1029
|
+
selectedPanel.selected = true;
|
1030
|
+
this._tabs.forEach((tab) => {
|
1031
|
+
if (tab.id !== selectedTab.id) {
|
1032
|
+
if (tab.selected) {
|
1033
|
+
tab.selected = false;
|
1034
|
+
const panel = this._getPanel(tab.id);
|
1035
|
+
// panel may not exist if it's being removed
|
1036
|
+
if (panel) panel.selected = false;
|
1037
|
+
}
|
1038
|
+
if (tab.tabIndex === 0) tab.tabIndex = -1;
|
1039
|
+
}
|
1040
|
+
});
|
1041
|
+
}
|
1042
|
+
|
1018
1043
|
}
|
1019
1044
|
|
1020
1045
|
customElements.define('d2l-tabs', Tabs);
|
package/custom-elements.json
CHANGED
@@ -12848,6 +12848,11 @@
|
|
12848
12848
|
"type": "boolean",
|
12849
12849
|
"default": "false"
|
12850
12850
|
},
|
12851
|
+
{
|
12852
|
+
"name": "tabindex",
|
12853
|
+
"type": "number",
|
12854
|
+
"default": "-1"
|
12855
|
+
},
|
12851
12856
|
{
|
12852
12857
|
"name": "skeleton",
|
12853
12858
|
"description": "Render the component as a [skeleton loader](https://github.com/BrightspaceUI/core/tree/main/components/skeleton).",
|
@@ -12873,6 +12878,12 @@
|
|
12873
12878
|
"type": "boolean",
|
12874
12879
|
"default": "false"
|
12875
12880
|
},
|
12881
|
+
{
|
12882
|
+
"name": "tabIndex",
|
12883
|
+
"attribute": "tabindex",
|
12884
|
+
"type": "number",
|
12885
|
+
"default": "-1"
|
12886
|
+
},
|
12876
12887
|
{
|
12877
12888
|
"name": "skeleton",
|
12878
12889
|
"attribute": "skeleton",
|
@@ -12894,6 +12905,11 @@
|
|
12894
12905
|
"path": "./components/tabs/tabs.js",
|
12895
12906
|
"description": "A component for tabbed content. It supports the \"d2l-tab-panel\" component for the content, renders tabs responsively, and provides virtual scrolling for large tab lists.",
|
12896
12907
|
"attributes": [
|
12908
|
+
{
|
12909
|
+
"name": "text",
|
12910
|
+
"description": "REQUIRED: ACCESSIBILITY: Accessible text for the tablist",
|
12911
|
+
"type": "string"
|
12912
|
+
},
|
12897
12913
|
{
|
12898
12914
|
"name": "max-to-show",
|
12899
12915
|
"description": "Limit the number of tabs to initially display",
|
@@ -12907,6 +12923,12 @@
|
|
12907
12923
|
}
|
12908
12924
|
],
|
12909
12925
|
"properties": [
|
12926
|
+
{
|
12927
|
+
"name": "text",
|
12928
|
+
"attribute": "text",
|
12929
|
+
"description": "REQUIRED: ACCESSIBILITY: Accessible text for the tablist",
|
12930
|
+
"type": "string"
|
12931
|
+
},
|
12910
12932
|
{
|
12911
12933
|
"name": "maxToShow",
|
12912
12934
|
"attribute": "max-to-show",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.94.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",
|