@brightspace-ui/core 3.94.1 → 3.94.3
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/components/tabs/tabs.js +119 -38
- package/package.json +1 -1
package/components/tabs/tabs.js
CHANGED
@@ -242,33 +242,61 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
242
242
|
super.firstUpdated(changedProperties);
|
243
243
|
|
244
244
|
this.arrowKeysFocusablesProvider = async() => {
|
245
|
-
return [...this.shadowRoot.querySelectorAll('d2l-tab-internal')];
|
245
|
+
return this._defaultSlotBehavior ? [...this.shadowRoot.querySelectorAll('d2l-tab-internal')] : this._tabs;
|
246
246
|
};
|
247
247
|
|
248
248
|
this.arrowKeysOnBeforeFocus = async(tab) => {
|
249
|
-
|
250
|
-
|
249
|
+
if (this._defaultSlotBehavior) {
|
250
|
+
// remove this section after d2l-tab/d2l-tab-panel backport
|
251
|
+
const tabInfo = this._getTabInfo(tab.controlsPanel);
|
252
|
+
this._setFocusableDefaultSlotBehavior(tabInfo);
|
251
253
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
if (!this._scrollCollapsed) {
|
256
|
-
return this._updateScrollPositionDefaultSlotBehavior(tabInfo);
|
257
|
-
} else {
|
258
|
-
const measures = this._getMeasures();
|
259
|
-
const newTranslationValue = this._calculateScrollPositionDefaultSlotBehavior(tabInfo, measures);
|
254
|
+
this.requestUpdate();
|
255
|
+
await this.updateComplete;
|
260
256
|
|
261
|
-
if (!this
|
262
|
-
|
257
|
+
if (!this._scrollCollapsed) {
|
258
|
+
return this._updateScrollPositionDefaultSlotBehavior(tabInfo);
|
263
259
|
} else {
|
264
|
-
|
260
|
+
const measures = this._getMeasures();
|
261
|
+
const newTranslationValue = this._calculateScrollPositionDefaultSlotBehavior(tabInfo, measures);
|
262
|
+
|
263
|
+
if (!this.#isRTL()) {
|
264
|
+
if (newTranslationValue >= 0) return;
|
265
|
+
} else {
|
266
|
+
if (newTranslationValue <= 0) return;
|
267
|
+
}
|
268
|
+
|
269
|
+
const expanded = await this._tryExpandTabsContainer(measures);
|
270
|
+
if (expanded) {
|
271
|
+
return;
|
272
|
+
} else {
|
273
|
+
return this._updateScrollPositionDefaultSlotBehavior(tabInfo);
|
274
|
+
}
|
265
275
|
}
|
276
|
+
} else {
|
277
|
+
this._setFocusable(tab);
|
266
278
|
|
267
|
-
|
268
|
-
|
269
|
-
|
279
|
+
this.requestUpdate();
|
280
|
+
await this.updateComplete;
|
281
|
+
|
282
|
+
if (!this._scrollCollapsed) {
|
283
|
+
return this._updateScrollPosition(tab);
|
270
284
|
} else {
|
271
|
-
|
285
|
+
const measures = this._getMeasures();
|
286
|
+
const newTranslationValue = this._calculateScrollPosition(tab, measures);
|
287
|
+
|
288
|
+
if (!this.#isRTL()) {
|
289
|
+
if (newTranslationValue >= 0) return;
|
290
|
+
} else {
|
291
|
+
if (newTranslationValue <= 0) return;
|
292
|
+
}
|
293
|
+
|
294
|
+
const expanded = await this._tryExpandTabsContainer(measures);
|
295
|
+
if (expanded) {
|
296
|
+
return;
|
297
|
+
} else {
|
298
|
+
return this._updateScrollPosition(tab);
|
299
|
+
}
|
272
300
|
}
|
273
301
|
}
|
274
302
|
};
|
@@ -364,6 +392,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
364
392
|
return this.shadowRoot.querySelector('.d2l-tabs-container-list').getBoundingClientRect();
|
365
393
|
}
|
366
394
|
|
395
|
+
#checkTabPanelMatchRequested;
|
396
|
+
#panels;
|
397
|
+
#updateAriaControlsRequested;
|
398
|
+
|
367
399
|
_animateTabAddition(tabInfo) {
|
368
400
|
const tab = this.shadowRoot
|
369
401
|
&& this.shadowRoot.querySelector(`d2l-tab-internal[controls-panel="${cssEscape(tabInfo.id)}"]`);
|
@@ -407,6 +439,21 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
407
439
|
}
|
408
440
|
|
409
441
|
async _focusSelected() {
|
442
|
+
if (this._defaultSlotBehavior) {
|
443
|
+
this._focusSelectedDefaultSlotBehavior();
|
444
|
+
return;
|
445
|
+
}
|
446
|
+
|
447
|
+
const selectedTab = this._tabs.find(ti => ti.selected);
|
448
|
+
if (!selectedTab) return;
|
449
|
+
|
450
|
+
await this._updateScrollPosition(selectedTab);
|
451
|
+
|
452
|
+
selectedTab.focus();
|
453
|
+
}
|
454
|
+
|
455
|
+
// remove after d2l-tab/d2l-tab-panel backport
|
456
|
+
async _focusSelectedDefaultSlotBehavior() {
|
410
457
|
const selectedTab = this.shadowRoot && this.shadowRoot.querySelector('d2l-tab-internal[aria-selected="true"]');
|
411
458
|
if (!selectedTab) return;
|
412
459
|
|
@@ -438,10 +485,8 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
438
485
|
_getPanel(id) {
|
439
486
|
if (this._defaultSlotBehavior) return this._getPanelDefaultSlotBehavior(id);
|
440
487
|
|
441
|
-
if (!this
|
442
|
-
|
443
|
-
const panels = this._getPanels(slot);
|
444
|
-
return panels.find(panel => panel.labelledBy === id);
|
488
|
+
if (!this.#panels) return;
|
489
|
+
return this.#panels.find(panel => panel.labelledBy === id);
|
445
490
|
}
|
446
491
|
|
447
492
|
// remove after d2l-tab/d2l-tab-panel backport
|
@@ -449,7 +494,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
449
494
|
if (!this.shadowRoot) return;
|
450
495
|
// use simple selector for slot (Edge)
|
451
496
|
const slot = this.shadowRoot.querySelector('.d2l-panels-container').querySelector('slot');
|
452
|
-
const panels = this.
|
497
|
+
const panels = this._getPanelsDefaultSlotBehavior(slot);
|
453
498
|
for (let i = 0; i < panels.length; i++) {
|
454
499
|
if (panels[i].nodeType === Node.ELEMENT_NODE && panels[i].role === 'tabpanel' && panels[i].id === id) {
|
455
500
|
return panels[i];
|
@@ -457,7 +502,8 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
457
502
|
}
|
458
503
|
}
|
459
504
|
|
460
|
-
|
505
|
+
// remove after d2l-tab/d2l-tab-panel backport
|
506
|
+
_getPanelsDefaultSlotBehavior(slot) {
|
461
507
|
if (!slot) return;
|
462
508
|
return slot.assignedElements({ flatten: true }).filter((node) => node.role === 'tabpanel');
|
463
509
|
}
|
@@ -470,7 +516,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
470
516
|
async _handleDefaultSlotChange(e) {
|
471
517
|
if (!this._defaultSlotBehavior) return;
|
472
518
|
|
473
|
-
const panels = this.
|
519
|
+
const panels = this._getPanelsDefaultSlotBehavior(e.target);
|
474
520
|
|
475
521
|
// handle case where there are less than two tabs initially
|
476
522
|
this._updateTabListVisibility(panels);
|
@@ -495,7 +541,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
495
541
|
};
|
496
542
|
if (tabInfo.selected) {
|
497
543
|
selectedTabInfo = tabInfo;
|
498
|
-
this.
|
544
|
+
this._setFocusableDefaultSlotBehavior(tabInfo);
|
499
545
|
}
|
500
546
|
return tabInfo;
|
501
547
|
});
|
@@ -563,17 +609,20 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
563
609
|
// event could be from nested tabs
|
564
610
|
if (!tabInfo) return;
|
565
611
|
|
566
|
-
this.
|
612
|
+
this._setFocusableDefaultSlotBehavior(tabInfo);
|
567
613
|
tabInfo.selected = true;
|
568
614
|
this.requestUpdate();
|
569
615
|
}
|
570
616
|
|
571
|
-
_handlePanelsSlotChange() {
|
617
|
+
_handlePanelsSlotChange(e) {
|
572
618
|
if (this._defaultSlotBehavior) return;
|
573
619
|
|
620
|
+
this.#panels = e.target.assignedElements({ flatten: true }).filter((node) => node.role === 'tabpanel');
|
621
|
+
this.#checkTabPanelMatch();
|
574
622
|
this.#setAriaControls();
|
575
623
|
}
|
576
624
|
|
625
|
+
// remove after d2l-tab/d2l-tab-panel backport
|
577
626
|
async _handlePanelTextChange(e) {
|
578
627
|
const tabInfo = this._getTabInfo(e.target.id);
|
579
628
|
// event could be from nested tabs
|
@@ -727,9 +776,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
727
776
|
if (selectedTab) {
|
728
777
|
this.#updateSelectedTab(selectedTab);
|
729
778
|
}
|
730
|
-
this.#setAriaControls();
|
731
779
|
|
732
780
|
await this.updateComplete;
|
781
|
+
this.#checkTabPanelMatch();
|
782
|
+
this.#setAriaControls();
|
733
783
|
|
734
784
|
if (!this._initialized && this._tabs.length > 0) {
|
735
785
|
this._initialized = true;
|
@@ -751,8 +801,13 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
751
801
|
}
|
752
802
|
|
753
803
|
_resetFocusables() {
|
754
|
-
|
755
|
-
|
804
|
+
if (this._defaultSlotBehavior) {
|
805
|
+
const selectedTab = this._tabInfos.find(ti => ti.selected);
|
806
|
+
if (selectedTab) this._setFocusableDefaultSlotBehavior(selectedTab);
|
807
|
+
} else {
|
808
|
+
const selectedTab = this._tabs.find(ti => ti.selected);
|
809
|
+
if (selectedTab) this._setFocusable(selectedTab);
|
810
|
+
}
|
756
811
|
this.requestUpdate();
|
757
812
|
}
|
758
813
|
|
@@ -777,7 +832,15 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
777
832
|
});
|
778
833
|
}
|
779
834
|
|
780
|
-
_setFocusable(
|
835
|
+
_setFocusable(tab) {
|
836
|
+
const currentFocusable = this._tabs.find(tab => tab.tabIndex === 0);
|
837
|
+
if (currentFocusable) currentFocusable.tabIndex = -1;
|
838
|
+
|
839
|
+
tab.tabIndex = 0;
|
840
|
+
}
|
841
|
+
|
842
|
+
// remove after d2l-tab/d2l-tab-panel backport
|
843
|
+
_setFocusableDefaultSlotBehavior(tabInfo) {
|
781
844
|
const currentFocusable = this._tabInfos.find(ti => ti.activeFocusable);
|
782
845
|
if (currentFocusable) currentFocusable.activeFocusable = false;
|
783
846
|
|
@@ -1011,22 +1074,40 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
1011
1074
|
return newTranslationValue;
|
1012
1075
|
}
|
1013
1076
|
|
1077
|
+
#checkTabPanelMatch() {
|
1078
|
+
// debounce so only runs once when tabs/panels slots changing
|
1079
|
+
if (this.#checkTabPanelMatchRequested) return;
|
1080
|
+
|
1081
|
+
this.#checkTabPanelMatchRequested = true;
|
1082
|
+
setTimeout(() => {
|
1083
|
+
if ((this._tabs && !this.#panels) || (this.#panels && !this._tabs)) {
|
1084
|
+
console.warn('d2l-tabs: tabs and panels are not in sync');
|
1085
|
+
} else if (this._tabs.length !== this.#panels.length) {
|
1086
|
+
console.warn('d2l-tabs: number of tabs and panels does not match');
|
1087
|
+
}
|
1088
|
+
this.#checkTabPanelMatchRequested = false;
|
1089
|
+
}, 0);
|
1090
|
+
}
|
1091
|
+
|
1014
1092
|
#isRTL() {
|
1015
1093
|
return document.documentElement.getAttribute('dir') === 'rtl';
|
1016
1094
|
}
|
1017
1095
|
|
1018
1096
|
#setAriaControls() {
|
1019
1097
|
// debounce so only runs once when tabs/panels slots changing
|
1020
|
-
if (this
|
1098
|
+
if (this.#updateAriaControlsRequested) return;
|
1021
1099
|
|
1022
|
-
this
|
1100
|
+
this.#updateAriaControlsRequested = true;
|
1023
1101
|
setTimeout(() => {
|
1024
1102
|
this._tabs?.forEach((tab) => {
|
1025
1103
|
const panel = this._getPanel(tab.id);
|
1026
|
-
if (!panel)
|
1104
|
+
if (!panel) {
|
1105
|
+
console.warn('d2l-tabs: tab without matching panel');
|
1106
|
+
return;
|
1107
|
+
}
|
1027
1108
|
tab.setAttribute('aria-controls', `${panel.id}`);
|
1028
1109
|
});
|
1029
|
-
this
|
1110
|
+
this.#updateAriaControlsRequested = false;
|
1030
1111
|
}, 0);
|
1031
1112
|
}
|
1032
1113
|
|
@@ -1047,12 +1128,12 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
|
|
1047
1128
|
}
|
1048
1129
|
|
1049
1130
|
async #updateSelectedTab(selectedTab) {
|
1050
|
-
const selectedPanel = this._getPanel(selectedTab.id);
|
1051
1131
|
selectedTab.tabIndex = 0;
|
1052
1132
|
|
1053
1133
|
await this.updateComplete;
|
1054
1134
|
|
1055
|
-
selectedPanel
|
1135
|
+
const selectedPanel = this._getPanel(selectedTab.id);
|
1136
|
+
if (selectedPanel) selectedPanel.selected = true;
|
1056
1137
|
this._tabs.forEach((tab) => {
|
1057
1138
|
if (tab.id !== selectedTab.id) {
|
1058
1139
|
if (tab.selected) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.94.
|
3
|
+
"version": "3.94.3",
|
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",
|