@brightspace-ui/core 3.315.0 → 3.317.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.
@@ -72,6 +72,11 @@ class PageDivider extends FocusMixin(PropertyRequiredMixin(LitElement)) {
72
72
  * @type {number}
73
73
  */
74
74
  currentSize: { type: Number, attribute: 'current-size' },
75
+ /**
76
+ * Whether to force-hide the directional arrows
77
+ * @type {boolean}
78
+ */
79
+ hideArrows: { type: Boolean, attribute: 'hide-arrows' },
75
80
  /**
76
81
  * REQUIRED: label for the divider
77
82
  * @type {string}
@@ -228,6 +233,7 @@ class PageDivider extends FocusMixin(PropertyRequiredMixin(LitElement)) {
228
233
  this.collapsed = false;
229
234
  this.collapsedSize = 0;
230
235
  this.currentSize = 0;
236
+ this.hideArrows = false;
231
237
  this.label = '';
232
238
  this.maxSize = 0;
233
239
  this.minSize = 0;
@@ -258,7 +264,7 @@ class PageDivider extends FocusMixin(PropertyRequiredMixin(LitElement)) {
258
264
 
259
265
  return html`
260
266
  <div class="${classMap(dividerClasses)}" @click="${this.#handleClick}" @pointerdown="${this.#handlePointerDown}">
261
- ${this.panelType === 'panel' ? html`
267
+ ${this.panelType === 'panel' && !this.hideArrows ? html`
262
268
  <div class="divider-arrow start" data-position="start" ?hidden="${!showStartArrow}">
263
269
  <d2l-icon-custom size="tier1">${ICON_ARROW_COLLAPSE_LEFT}</d2l-icon-custom>
264
270
  </div>
@@ -27,6 +27,8 @@ const MOBILE_MODE_BREAKPOINT = 767;
27
27
  const overlayModeQuery = window.matchMedia(`(max-width: ${OVERLAY_MODE_BREAKPOINT}px)`);
28
28
  const mobileModeQuery = window.matchMedia(`(max-width: ${MOBILE_MODE_BREAKPOINT}px)`);
29
29
 
30
+ export const HIDE_ARROWS_BREAKPOINT = 400;
31
+
30
32
  class PanelStateController {
31
33
  constructor(host, panelConfigs) {
32
34
  this.#host = host;
@@ -594,6 +596,7 @@ class Page extends ProviderMixin(LocalizeCoreElement(LitElement)) {
594
596
  max-size="${this._panelState.getMaxSize(panelKey)}"
595
597
  min-size="${this._panelState.getMinSize(panelKey)}"
596
598
  panel-position="${ifDefined(panelPosition)}"
599
+ ?hide-arrows="${this._contentWidth < HIDE_ARROWS_BREAKPOINT}"
597
600
  @d2l-page-divider-resize="${this.#handleDividerResize}"
598
601
  @d2l-page-divider-resize-live="${this.#handleDividerResizeLive}"
599
602
  @d2l-page-divider-toggle="${this.#handleDividerToggle}"
@@ -257,11 +257,6 @@ Selecting a tab in the tab bar causes the related tab panel to be displayed. Tab
257
257
  |--|--|--|
258
258
  | `labelled-by` | String, required | Id of the tab that labels this panel |
259
259
  | `no-padding` | Boolean | Used to opt out of default padding/whitespace around the panel |
260
- | `text` | String | DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation. |
261
- | `selected` | Boolean | DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation. |
262
-
263
- ### Events
264
- - `d2l-tab-panel-selected`: DEPRECATED: Dispatched when a tab is selected
265
260
  <!-- docs: end hidden content -->
266
261
 
267
262
  ## Accessibility
@@ -1,6 +1,5 @@
1
1
  import { css } from 'lit';
2
2
  import { getUniqueId } from '../../helpers/uniqueId.js';
3
- import { getUseNewTabsStructureFlag } from './tabs.js';
4
3
 
5
4
  export const TabPanelMixin = superclass => class extends superclass {
6
5
 
@@ -20,18 +19,6 @@ export const TabPanelMixin = superclass => class extends superclass {
20
19
  */
21
20
  // eslint-disable-next-line lit/no-native-attributes
22
21
  role: { type: String, reflect: true },
23
- /**
24
- * DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation.
25
- * Remove with GAUD-8299-core-tabs-use-new-structure flag clean up.
26
- * @type {boolean}
27
- */
28
- selected: { type: Boolean, reflect: true },
29
- /**
30
- * DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation.
31
- * Remove with GAUD-8299-core-tabs-use-new-structure flag clean up.
32
- * @type {string}
33
- */
34
- text: { type: String },
35
22
  _selected: { type: Boolean, attribute: '_selected', reflect: true }
36
23
  };
37
24
 
@@ -44,10 +31,6 @@ export const TabPanelMixin = superclass => class extends superclass {
44
31
  :host([no-padding]) {
45
32
  margin: 0;
46
33
  }
47
- /* clean up with GAUD-8299-core-tabs-use-new-structure flag clean up */
48
- :host([selected]) {
49
- display: block;
50
- }
51
34
  :host([_selected]) {
52
35
  display: block;
53
36
  }
@@ -59,7 +42,6 @@ export const TabPanelMixin = superclass => class extends superclass {
59
42
  /** @ignore */
60
43
  this.role = 'tabpanel';
61
44
  this._selected = false;
62
- if (!this.#useTabsNewStructure) this.selected = false; // clean up with GAUD-8299-core-tabs-use-new-structure flag clean up
63
45
  }
64
46
 
65
47
  connectedCallback() {
@@ -74,29 +56,7 @@ export const TabPanelMixin = superclass => class extends superclass {
74
56
  if (prop === 'labelledBy') {
75
57
  this.setAttribute('aria-labelledby', this.labelledBy);
76
58
  }
77
-
78
- // clean up below with GAUD-8299-core-tabs-use-new-structure flag clean up
79
- if (this.#useTabsNewStructure) return;
80
-
81
- if (prop === 'selected') {
82
- if (this.selected) {
83
- requestAnimationFrame(() => {
84
- /** DEPRECATED: Dispatched when a tab is selected */
85
- this.dispatchEvent(new CustomEvent(
86
- 'd2l-tab-panel-selected', { bubbles: true, composed: true }
87
- ));
88
- });
89
- }
90
- } else if (prop === 'text') {
91
- this.setAttribute('aria-label', this.text);
92
- /** DEPRECATED: Dispatched when the text attribute is changed */
93
- this.dispatchEvent(new CustomEvent(
94
- 'd2l-tab-panel-text-changed', { bubbles: true, composed: true, detail: { text: this.text } }
95
- ));
96
- }
97
59
  });
98
60
  }
99
61
 
100
- #useTabsNewStructure = getUseNewTabsStructureFlag();
101
-
102
62
  };
@@ -1,24 +1,17 @@
1
1
  import '../colors/colors.js';
2
2
  import '../icons/icon.js';
3
- import './tab-internal.js';
4
- import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
3
+ import { css, html, LitElement, unsafeCSS } from 'lit';
5
4
  import { findComposedAncestor, getOffsetParent, isVisible } from '../../helpers/dom.js';
6
5
  import { getFocusPseudoClass, getFocusRingStyles } from '../../helpers/focus.js';
7
6
  import { ArrowKeysMixin } from '../../mixins/arrow-keys/arrow-keys-mixin.js';
8
7
  import { bodyCompactStyles } from '../typography/styles.js';
9
8
  import { classMap } from 'lit/directives/class-map.js';
10
- import { getFlag } from '../../helpers/flags.js';
11
9
  import { getOverflowDeclarations } from '../../helpers/overflow.js';
12
10
  import { ifDefined } from 'lit/directives/if-defined.js';
13
11
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
14
- import { repeat } from 'lit/directives/repeat.js';
15
12
  import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
16
13
  import { styleMap } from 'lit/directives/style-map.js';
17
14
 
18
- export function getUseNewTabsStructureFlag() {
19
- return getFlag('GAUD-8299-core-tabs-use-new-structure', true);
20
- }
21
-
22
15
  const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
23
16
 
24
17
  const scrollButtonWidth = 56;
@@ -30,7 +23,6 @@ function getOffsetLeft(tab, tabRect) {
30
23
 
31
24
  /**
32
25
  * A component for tabbed content. It supports the "d2l-tab" component and "TabMixin" consumers for tabs, the "d2l-tab-panel" component for the tab content, renders tabs responsively, and provides virtual scrolling for large tab lists.
33
- * @slot - DEPRECATED: Contains the tab panels (e.g., "d2l-tab-panel" components)
34
26
  * @slot ext - Additional content (e.g., a button) positioned at right
35
27
  * @slot tabs - Contains the tabs (e.g., "d2l-tab" components or custom components that use `TabMixin`)
36
28
  * @slot panels - Contains the tab panels (e.g., "d2l-tab-panel" components)
@@ -50,11 +42,9 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
50
42
  text: { type: String },
51
43
  _allowScrollNext: { type: Boolean },
52
44
  _allowScrollPrevious: { type: Boolean },
53
- _defaultSlotBehavior: { state: true },
54
45
  _maxWidth: { type: Number },
55
46
  _scrollCollapsed: { type: Boolean },
56
47
  _state: { type: String },
57
- _tabInfos: { type: Array },
58
48
  _translationValue: {}
59
49
  };
60
50
 
@@ -169,12 +159,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
169
159
  transition: margin-top 200ms ease-out;
170
160
  }
171
161
 
172
- d2l-tab-internal, ::slotted([role="tab"]) {
162
+ ::slotted([role="tab"]) {
173
163
  -webkit-transition: max-width 200ms ease-out, opacity 200ms ease-out, transform 200ms ease-out;
174
164
  transition: max-width 200ms ease-out, opacity 200ms ease-out, transform 200ms ease-out;
175
165
  }
176
- d2l-tab-internal[data-state="adding"],
177
- d2l-tab-internal[data-state="removing"],
178
166
  ::slotted([role="tab"][data-state="adding"]),
179
167
  ::slotted([role="tab"][data-state="removing"]) {
180
168
  max-width: 0;
@@ -200,7 +188,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
200
188
  -webkit-transition: none;
201
189
  transition: none;
202
190
  }
203
- d2l-tab-internal, ::slotted([role="tab"]) {
191
+ ::slotted([role="tab"]) {
204
192
  -webkit-transition: none;
205
193
  transition: none;
206
194
  }
@@ -229,13 +217,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
229
217
  this.maxToShow = -1;
230
218
  this._allowScrollNext = false;
231
219
  this._allowScrollPrevious = false;
232
-
233
- /*
234
- * Remove this._defaultSlotBehavior and related code with GAUD-8299-core-tabs-use-new-structure flag clean up
235
- * NOTE: remove the TRUE case of _defaultSlotBehavior
236
- */
237
- this._defaultSlotBehavior = !this.#newTabsPanelStructure;
238
-
239
220
  this._loadingCompleteResolve = undefined;
240
221
  this._loadingCompletePromise = new Promise(resolve => this._loadingCompleteResolve = resolve);
241
222
  this._maxWidth = null;
@@ -243,7 +224,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
243
224
  this._state = 'shown';
244
225
  this._tabIds = {};
245
226
  this._tabs = [];
246
- if (this._defaultSlotBehavior) this._tabInfos = [];
247
227
  this._translationValue = 0;
248
228
  }
249
229
 
@@ -268,61 +248,32 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
268
248
  super.firstUpdated(changedProperties);
269
249
 
270
250
  this.arrowKeysFocusablesProvider = async() => {
271
- return this._defaultSlotBehavior ? [...this.shadowRoot.querySelectorAll('d2l-tab-internal')] : this._tabs;
251
+ return this._tabs;
272
252
  };
273
253
 
274
254
  this.arrowKeysOnBeforeFocus = async(tab) => {
275
- if (this._defaultSlotBehavior) {
276
- // remove this section with GAUD-8299-core-tabs-use-new-structure flag clean up
277
- const tabInfo = this._getTabInfo(tab.controlsPanel);
278
- this._setFocusableDefaultSlotBehavior(tabInfo);
255
+ this._setFocusable(tab);
279
256
 
280
- this.requestUpdate();
281
- await this.updateComplete;
257
+ this.requestUpdate();
258
+ await this.updateComplete;
282
259
 
283
- if (!this._scrollCollapsed) {
284
- return this._updateScrollPositionDefaultSlotBehavior(tabInfo);
285
- } else {
286
- const measures = this._getMeasures();
287
- const newTranslationValue = this._calculateScrollPositionDefaultSlotBehavior(tabInfo, measures);
288
-
289
- if (!this.#isRTL()) {
290
- if (newTranslationValue >= 0) return;
291
- } else {
292
- if (newTranslationValue <= 0) return;
293
- }
294
-
295
- const expanded = await this._tryExpandTabsContainer(measures);
296
- if (expanded) {
297
- return;
298
- } else {
299
- return this._updateScrollPositionDefaultSlotBehavior(tabInfo);
300
- }
301
- }
260
+ if (!this._scrollCollapsed) {
261
+ return this._updateScrollPosition(tab);
302
262
  } else {
303
- this._setFocusable(tab);
263
+ const measures = this._getMeasures();
264
+ const newTranslationValue = this._calculateScrollPosition(tab, measures);
304
265
 
305
- this.requestUpdate();
306
- await this.updateComplete;
266
+ if (!this.#isRTL()) {
267
+ if (newTranslationValue >= 0) return;
268
+ } else {
269
+ if (newTranslationValue <= 0) return;
270
+ }
307
271
 
308
- if (!this._scrollCollapsed) {
309
- return this._updateScrollPosition(tab);
272
+ const expanded = await this._tryExpandTabsContainer(measures);
273
+ if (expanded) {
274
+ return;
310
275
  } else {
311
- const measures = this._getMeasures();
312
- const newTranslationValue = this._calculateScrollPosition(tab, measures);
313
-
314
- if (!this.#isRTL()) {
315
- if (newTranslationValue >= 0) return;
316
- } else {
317
- if (newTranslationValue <= 0) return;
318
- }
319
-
320
- const expanded = await this._tryExpandTabsContainer(measures);
321
- if (expanded) {
322
- return;
323
- } else {
324
- return this._updateScrollPosition(tab);
325
- }
276
+ return this._updateScrollPosition(tab);
326
277
  }
327
278
  }
328
279
  };
@@ -377,15 +328,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
377
328
  aria-label="${ifDefined(this.text)}"
378
329
  role="tablist"
379
330
  style="${styleMap(tabsContainerListStyles)}">
380
- ${!this.#newTabsPanelStructure ? repeat(this._tabInfos, (tabInfo) => tabInfo.id, (tabInfo) => html`
381
- <d2l-tab-internal aria-selected="${tabInfo.selected ? 'true' : 'false'}"
382
- .controlsPanel="${tabInfo.id}"
383
- data-state="${tabInfo.state}"
384
- ?skeleton="${this.skeleton}"
385
- tabindex="${tabInfo.activeFocusable ? 0 : -1}"
386
- text="${tabInfo.text}">
387
- </d2l-tab-internal>
388
- `) : nothing}
389
331
  <slot name="tabs" @slotchange="${this._handleTabsSlotChange}"></slot>
390
332
  </div>
391
333
  `)}
@@ -399,10 +341,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
399
341
  </div>
400
342
  <div class="d2l-tabs-container-ext"><slot name="ext"></slot></div>
401
343
  </div>
402
- <div class="${classMap(panelContainerClasses)}"
403
- @d2l-tab-panel-selected="${ifDefined(!this.#newTabsPanelStructure ? this._handlePanelSelected : undefined)}"
404
- @d2l-tab-panel-text-changed="${ifDefined(!this.#newTabsPanelStructure ? this._handlePanelTextChange : undefined)}">
405
- ${!this.#newTabsPanelStructure ? html`<slot @slotchange="${this._handleDefaultSlotChange}"></slot>` : nothing}
344
+ <div class="${classMap(panelContainerClasses)}">
406
345
  <slot name="panels" @slotchange="${this._handlePanelsSlotChange}"></slot>
407
346
  </div>
408
347
  `;
@@ -427,7 +366,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
427
366
  }
428
367
 
429
368
  #checkTabPanelMatchRequested;
430
- #newTabsPanelStructure = getUseNewTabsStructureFlag();
431
369
  #panels;
432
370
  #updateAriaControlsRequested;
433
371
 
@@ -452,24 +390,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
452
390
  });
453
391
  }
454
392
 
455
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
456
- _animateTabAdditionDefaultSlotBehavior(tabInfo) {
457
- const tab = this.shadowRoot
458
- && this.shadowRoot.querySelector(`d2l-tab-internal[controls-panel="${CSS.escape(tabInfo.id)}"]`);
459
- if (!tab) Promise.resolve();
460
-
461
- return new Promise((resolve) => {
462
- const handleTransitionEnd = (e) => {
463
- if (e.propertyName !== 'max-width') return;
464
- tab.removeEventListener('transitionend', handleTransitionEnd);
465
- resolve();
466
- };
467
- tab.addEventListener('transitionend', handleTransitionEnd);
468
- tabInfo.state = '';
469
- this.requestUpdate();
470
- });
471
- }
472
-
473
393
  _animateTabRemoval(tab) {
474
394
  if (!tab || reduceMotion) return Promise.resolve();
475
395
 
@@ -484,42 +404,13 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
484
404
  });
485
405
  }
486
406
 
487
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
488
- _animateTabRemovalDefaultSlotBehavior(tabInfo) {
489
- const tab = this.shadowRoot &&
490
- this.shadowRoot.querySelector(`d2l-tab-internal[controls-panel="${CSS.escape(tabInfo.id)}"]`);
491
- if (!tab) Promise.resolve();
492
-
493
- return new Promise((resolve) => {
494
- const handleTransitionEnd = (e) => {
495
- if (e.propertyName !== 'max-width') return;
496
- tab.removeEventListener('transitionend', handleTransitionEnd);
497
- this._tabInfos.splice(this._tabInfos.findIndex(info => info.id === tabInfo.id), 1);
498
- this.requestUpdate();
499
- resolve();
500
- };
501
- tab.addEventListener('transitionend', handleTransitionEnd);
502
- });
503
- }
504
-
505
407
  _calculateScrollPosition(selectedTab, measures) {
506
408
  const tabs = this._tabs;
507
409
  const selectedTabIndex = tabs.indexOf(selectedTab);
508
410
  return this.#calculateScrollPositionLogic(tabs, selectedTabIndex, measures);
509
411
  }
510
412
 
511
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
512
- _calculateScrollPositionDefaultSlotBehavior(selectedTabInfo, measures) {
513
- const selectedTabIndex = this._tabInfos.indexOf(selectedTabInfo);
514
- return this.#calculateScrollPositionLogic(this._tabInfos, selectedTabIndex, measures);
515
- }
516
-
517
413
  async _focusSelected() {
518
- if (this._defaultSlotBehavior) {
519
- this._focusSelectedDefaultSlotBehavior();
520
- return;
521
- }
522
-
523
414
  const selectedTab = this._tabs.find(ti => ti.selected);
524
415
  if (!selectedTab) return;
525
416
 
@@ -528,17 +419,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
528
419
  selectedTab.focus();
529
420
  }
530
421
 
531
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
532
- async _focusSelectedDefaultSlotBehavior() {
533
- const selectedTab = this.shadowRoot && this.shadowRoot.querySelector('d2l-tab-internal[aria-selected="true"]');
534
- if (!selectedTab) return;
535
-
536
- const selectedTabInfo = this._getTabInfo(selectedTab.controlsPanel);
537
- await this._updateScrollPositionDefaultSlotBehavior(selectedTabInfo);
538
-
539
- selectedTab.focus();
540
- }
541
-
542
422
  _getComputedBackgroundColor() {
543
423
  let bgColor = null;
544
424
 
@@ -559,158 +439,21 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
559
439
  }
560
440
 
561
441
  _getPanel(id) {
562
- if (this._defaultSlotBehavior) return this._getPanelDefaultSlotBehavior(id);
563
-
564
442
  if (!this.#panels) return;
565
443
  return this.#panels.find(panel => panel.labelledBy === id);
566
444
  }
567
445
 
568
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
569
- _getPanelDefaultSlotBehavior(id) {
570
- if (!this.shadowRoot) return;
571
- // use simple selector for slot (Edge)
572
- const slot = this.shadowRoot.querySelector('.d2l-panels-container').querySelector('slot');
573
- const panels = this._getPanelsDefaultSlotBehavior(slot);
574
- for (let i = 0; i < panels.length; i++) {
575
- if (panels[i].nodeType === Node.ELEMENT_NODE && panels[i].role === 'tabpanel' && panels[i].id === id) {
576
- return panels[i];
577
- }
578
- }
579
- }
580
-
581
- // rremove with GAUD-8299-core-tabs-use-new-structure flag clean up
582
- _getPanelsDefaultSlotBehavior(slot) {
583
- if (!slot) return;
584
- return slot.assignedElements({ flatten: true }).filter((node) => node.role === 'tabpanel');
585
- }
586
-
587
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
588
- _getTabInfo(id) {
589
- return this._tabInfos.find((t) => t.id === id);
590
- }
591
-
592
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
593
- async _handleDefaultSlotChange(e) {
594
- if (!this._defaultSlotBehavior) return;
595
-
596
- const panels = this._getPanelsDefaultSlotBehavior(e.target);
597
-
598
- // handle case where there are less than two tabs initially
599
- this._updateTabListVisibility(panels);
600
-
601
- if (!this._initialized && panels.length === 0) return;
602
-
603
- let selectedTabInfo = null;
604
-
605
- const newTabInfos = panels.map((panel) => {
606
- let state = '';
607
- if (this._initialized && !reduceMotion && panels.length !== this._tabInfos.length) {
608
- // if it's a new tab, update state to animate addition
609
- if (this._tabInfos.findIndex(info => info.id === panel.id) === -1) {
610
- state = 'adding';
611
- }
612
- }
613
- const tabInfo = {
614
- id: panel.id,
615
- text: panel.text,
616
- selected: panel.selected,
617
- state: state
618
- };
619
- if (tabInfo.selected) {
620
- selectedTabInfo = tabInfo;
621
- this._setFocusableDefaultSlotBehavior(tabInfo);
622
- }
623
- return tabInfo;
624
- });
625
-
626
- if (this._initialized && !reduceMotion && this._tabInfos.length !== newTabInfos.length) {
627
- this._tabInfos.forEach((info, index) => {
628
- // if a tab was removed, include old info to animate it away
629
- if (newTabInfos.findIndex(newInfo => newInfo.id === info.id) === -1) {
630
- info.state = 'removing';
631
- info.selected = false;
632
- newTabInfos.splice(index, 0, info);
633
- }
634
- });
635
- }
636
- this._tabInfos = newTabInfos;
637
-
638
- if (this._tabInfos.length > 0 && !selectedTabInfo) {
639
- selectedTabInfo = this._tabInfos.find(tabInfo => tabInfo.state !== 'removing');
640
- if (selectedTabInfo) {
641
- selectedTabInfo.activeFocusable = true;
642
- selectedTabInfo.selected = true;
643
- }
644
- }
645
-
646
- await this.updateComplete;
647
-
648
- const animPromises = [];
649
- if (!this._initialized && this._tabInfos.length > 0) {
650
-
651
- this._initialized = true;
652
- await this._updateTabsContainerWidthDefaultSlotBehavior(selectedTabInfo);
653
-
654
- } else {
655
-
656
- if (this._tabInfos.length > 1) {
657
- this._tabInfos.forEach((info) => {
658
- if (info.state === 'adding') animPromises.push(this._animateTabAdditionDefaultSlotBehavior(info));
659
- else if (info.state === 'removing') animPromises.push(this._animateTabRemovalDefaultSlotBehavior(info));
660
- });
661
- }
662
-
663
- // required for animation
664
- this._updateMeasures();
665
- }
666
-
667
- if (selectedTabInfo) {
668
- Promise.all(animPromises).then(() => {
669
- this._updateMeasures();
670
- return this._updateScrollPositionDefaultSlotBehavior(selectedTabInfo);
671
- });
672
- }
673
-
674
- }
675
-
676
446
  _handleFocusOut(e) {
677
447
  if (e.relatedTarget && e.relatedTarget.role === 'tab') return;
678
448
  this._resetFocusables();
679
449
  }
680
450
 
681
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
682
- _handlePanelSelected(e) {
683
- if (!this._defaultSlotBehavior) return;
684
-
685
- const tabInfo = this._getTabInfo(e.target.id);
686
- // event could be from nested tabs
687
- if (!tabInfo) return;
688
-
689
- this._setFocusableDefaultSlotBehavior(tabInfo);
690
- tabInfo.selected = true;
691
- this.requestUpdate();
692
- }
693
-
694
451
  _handlePanelsSlotChange(e) {
695
- if (this._defaultSlotBehavior) return;
696
-
697
452
  this.#panels = e.target.assignedElements({ flatten: true }).filter((node) => node.role === 'tabpanel');
698
453
  this.#checkTabPanelMatch();
699
454
  this.#setAriaControls();
700
455
  }
701
456
 
702
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
703
- async _handlePanelTextChange(e) {
704
- const tabInfo = this._getTabInfo(e.target.id);
705
- // event could be from nested tabs
706
- if (!tabInfo) return;
707
- tabInfo.text = e.target.text;
708
- this.requestUpdate();
709
- await this.updateComplete;
710
- this._updateMeasures();
711
- await this._updateScrollVisibility(this._getMeasures());
712
- }
713
-
714
457
  _handleResize(entries) {
715
458
  const measures = this._getMeasures();
716
459
  if (entries.length === 1 && entries[0].contentRect.width === measures.tabsContainerListRect.width) return;
@@ -801,48 +544,13 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
801
544
  }
802
545
 
803
546
  async _handleTabSelected(e) {
804
- if (this._defaultSlotBehavior) {
805
- this._handleTabSelectedDefaultSlotBehavior(e);
806
- return;
807
- }
808
-
809
547
  const selectedTab = e.target;
810
548
  this.#updateSelectedTab(selectedTab);
811
549
  await this.updateComplete;
812
550
  this._updateScrollPosition(selectedTab);
813
551
  }
814
552
 
815
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
816
- async _handleTabSelectedDefaultSlotBehavior(e) {
817
- e.stopPropagation();
818
-
819
- const selectedTab = e.target;
820
- const selectedPanel = this._getPanel(selectedTab.controlsPanel);
821
- const selectedTabInfo = this._getTabInfo(selectedTab.controlsPanel);
822
- selectedTabInfo.activeFocusable = true;
823
-
824
- await this.updateComplete;
825
- this._updateScrollPositionDefaultSlotBehavior(selectedTabInfo);
826
-
827
- selectedPanel.selected = true;
828
- this._tabInfos.forEach((tabInfo) => {
829
- if (tabInfo.id !== selectedTab.controlsPanel) {
830
- if (tabInfo.selected) {
831
- tabInfo.selected = false;
832
- const panel = this._getPanel(tabInfo.id);
833
- // panel may not exist if it's being removed
834
- if (panel) panel.selected = false;
835
- }
836
- if (tabInfo.activeFocusable) tabInfo.activeFocusable = false;
837
- }
838
- });
839
-
840
- this.requestUpdate();
841
- }
842
-
843
553
  async _handleTabsSlotChange(e) {
844
- this._defaultSlotBehavior = false;
845
-
846
554
  this._tabs = e.target.assignedElements({ flatten: true }).filter((node) => node.role === 'tab');
847
555
 
848
556
  // handle case where there are less than two tabs initially
@@ -912,13 +620,8 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
912
620
  }
913
621
 
914
622
  _resetFocusables() {
915
- if (this._defaultSlotBehavior) {
916
- const selectedTab = this._tabInfos.find(ti => ti.selected);
917
- if (selectedTab) this._setFocusableDefaultSlotBehavior(selectedTab);
918
- } else {
919
- const selectedTab = this._tabs.find(ti => ti.selected);
920
- if (selectedTab) this._setFocusable(selectedTab);
921
- }
623
+ const selectedTab = this._tabs.find(ti => ti.selected);
624
+ if (selectedTab) this._setFocusable(selectedTab);
922
625
  this.requestUpdate();
923
626
  }
924
627
 
@@ -950,14 +653,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
950
653
  tab.tabIndex = 0;
951
654
  }
952
655
 
953
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
954
- _setFocusableDefaultSlotBehavior(tabInfo) {
955
- const currentFocusable = this._tabInfos.find(ti => ti.activeFocusable);
956
- if (currentFocusable) currentFocusable.activeFocusable = false;
957
-
958
- tabInfo.activeFocusable = true;
959
- }
960
-
961
656
  async _tryExpandTabsContainer(measures) {
962
657
 
963
658
  if (!this._scrollCollapsed) return false;
@@ -1005,11 +700,11 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1005
700
  _updateMeasures() {
1006
701
  let totalTabsWidth = 0;
1007
702
  if (!this.shadowRoot) return;
1008
- const tabs = this._defaultSlotBehavior ? [...this.shadowRoot.querySelectorAll('d2l-tab-internal')] : this._tabs;
703
+ const tabs = this._tabs;
1009
704
 
1010
705
  const tabRects = tabs.map((tab) => {
1011
706
  const tabRect = tab.getBoundingClientRect();
1012
- const offsetLeft = this._defaultSlotBehavior ? tab.offsetLeft : getOffsetLeft(tab, tabRect);
707
+ const offsetLeft = getOffsetLeft(tab, tabRect);
1013
708
 
1014
709
  const measures = {
1015
710
  rect: tabRect,
@@ -1033,13 +728,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1033
728
  return this.#updateScrollPositionLogic(measures, newTranslationValue);
1034
729
  }
1035
730
 
1036
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1037
- _updateScrollPositionDefaultSlotBehavior(selectedTabInfo) {
1038
- const measures = this._getMeasures();
1039
- const newTranslationValue = this._calculateScrollPositionDefaultSlotBehavior(selectedTabInfo, measures);
1040
- return this.#updateScrollPositionLogic(measures, newTranslationValue);
1041
- }
1042
-
1043
731
  _updateScrollVisibility(measures) {
1044
732
 
1045
733
  const lastTabMeasures = measures.tabRects[measures.tabRects.length - 1];
@@ -1061,19 +749,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1061
749
  }
1062
750
 
1063
751
  _updateTabListVisibility(tabs) {
1064
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1065
- if (!this.#newTabsPanelStructure) {
1066
- if (this._state === 'shown' && tabs.length < 2) {
1067
- this.#hideTabsList();
1068
- } else if (this._state === 'hidden' && tabs.length > 1) {
1069
- this.#showTabsList();
1070
- } else if (this._state === 'shown' && tabs.length > 1) {
1071
- // check if there are hidden tabs and tab list container should actually be hidden
1072
- this.#handleTabHiddenChange();
1073
- }
1074
- return;
1075
- }
1076
-
1077
752
  const visibleCount = tabs.filter(tab => !tab.hidden).length;
1078
753
  if (this._state === 'shown' && visibleCount < 2) {
1079
754
  this.#hideTabsList();
@@ -1092,13 +767,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1092
767
  return this.#updateTabsContainerWidthLogic();
1093
768
  }
1094
769
 
1095
- // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1096
- _updateTabsContainerWidthDefaultSlotBehavior(selectedTabInfo) {
1097
- if (!this.maxToShow || this.maxToShow <= 0 || this.maxToShow >= this._tabInfos.length) return;
1098
- if (this._tabInfos.indexOf(selectedTabInfo) > this.maxToShow - 1) return;
1099
- return this.#updateTabsContainerWidthLogic();
1100
- }
1101
-
1102
770
  #calculateScrollPositionLogic(tabsDataStructure, selectedTabIndex, measures) {
1103
771
  if (!measures.tabRects[selectedTabIndex]) return 0;
1104
772
 
@@ -1199,10 +867,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1199
867
 
1200
868
  #handleTabDeselected(e) {
1201
869
  const panel = this._getPanel(e.target.id);
1202
- if (panel) {
1203
- if (this.#newTabsPanelStructure) panel._selected = false;
1204
- else panel.selected = false; // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1205
- }
870
+ if (panel) panel._selected = false;
1206
871
  }
1207
872
 
1208
873
  #handleTabHiddenChange() {
@@ -1290,20 +955,14 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1290
955
  selectedTab.tabIndex = 0;
1291
956
 
1292
957
  const selectedPanel = this._getPanel(selectedTab.id);
1293
- if (selectedPanel) {
1294
- if (this.#newTabsPanelStructure) selectedPanel._selected = true;
1295
- else selectedPanel.selected = true; // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1296
- }
958
+ if (selectedPanel) selectedPanel._selected = true;
1297
959
  this._tabs.forEach((tab) => {
1298
960
  if (tab.id !== selectedTab.id) {
1299
961
  if (tab.selected) {
1300
962
  tab.selected = false;
1301
963
  const panel = this._getPanel(tab.id);
1302
964
  // panel may not exist if it's being removed
1303
- if (panel) {
1304
- if (this.#newTabsPanelStructure) panel._selected = false;
1305
- else panel.selected = false; // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1306
- }
965
+ if (panel) panel._selected = false;
1307
966
  }
1308
967
  if (tab.tabIndex === 0) tab.tabIndex = -1;
1309
968
  }
@@ -13366,6 +13366,12 @@
13366
13366
  "type": "number",
13367
13367
  "default": "0"
13368
13368
  },
13369
+ {
13370
+ "name": "hide-arrows",
13371
+ "description": "Whether to force-hide the directional arrows",
13372
+ "type": "boolean",
13373
+ "default": "false"
13374
+ },
13369
13375
  {
13370
13376
  "name": "label",
13371
13377
  "description": "REQUIRED: label for the divider",
@@ -13428,6 +13434,13 @@
13428
13434
  "type": "number",
13429
13435
  "default": "0"
13430
13436
  },
13437
+ {
13438
+ "name": "hideArrows",
13439
+ "attribute": "hide-arrows",
13440
+ "description": "Whether to force-hide the directional arrows",
13441
+ "type": "boolean",
13442
+ "default": "false"
13443
+ },
13431
13444
  {
13432
13445
  "name": "label",
13433
13446
  "attribute": "label",
@@ -16752,80 +16765,6 @@
16752
16765
  "name": "d2l-tabs-array",
16753
16766
  "path": "./components/tabs/demo/tabs-array.js"
16754
16767
  },
16755
- {
16756
- "name": "d2l-tab-internal",
16757
- "path": "./components/tabs/tab-internal.js",
16758
- "attributes": [
16759
- {
16760
- "name": "controls-panel",
16761
- "type": "string"
16762
- },
16763
- {
16764
- "name": "text",
16765
- "type": "string"
16766
- },
16767
- {
16768
- "name": "aria-selected",
16769
- "type": "string",
16770
- "default": "\"false\""
16771
- },
16772
- {
16773
- "name": "role",
16774
- "type": "string",
16775
- "default": "\"tab\""
16776
- },
16777
- {
16778
- "name": "skeleton",
16779
- "description": "Render the component as a [skeleton loader](https://github.com/BrightspaceUI/core/tree/main/components/skeleton).",
16780
- "type": "boolean"
16781
- }
16782
- ],
16783
- "properties": [
16784
- {
16785
- "name": "controlsPanel",
16786
- "attribute": "controls-panel",
16787
- "type": "string"
16788
- },
16789
- {
16790
- "name": "text",
16791
- "attribute": "text",
16792
- "type": "string"
16793
- },
16794
- {
16795
- "name": "styles",
16796
- "type": "array",
16797
- "default": "[\"styles\",null]"
16798
- },
16799
- {
16800
- "name": "ariaSelected",
16801
- "attribute": "aria-selected",
16802
- "type": "string",
16803
- "default": "\"false\""
16804
- },
16805
- {
16806
- "name": "role",
16807
- "attribute": "role",
16808
- "type": "string",
16809
- "default": "\"tab\""
16810
- },
16811
- {
16812
- "name": "tabIndex",
16813
- "type": "number",
16814
- "default": "-1"
16815
- },
16816
- {
16817
- "name": "skeleton",
16818
- "attribute": "skeleton",
16819
- "description": "Render the component as a [skeleton loader](https://github.com/BrightspaceUI/core/tree/main/components/skeleton).",
16820
- "type": "boolean"
16821
- }
16822
- ],
16823
- "events": [
16824
- {
16825
- "name": "d2l-tab-selected"
16826
- }
16827
- ]
16828
- },
16829
16768
  {
16830
16769
  "name": "d2l-tab-panel",
16831
16770
  "path": "./components/tabs/tab-panel.js",
@@ -16836,16 +16775,6 @@
16836
16775
  "description": "REQUIRED: Id of the tab that labels this panel",
16837
16776
  "type": "string"
16838
16777
  },
16839
- {
16840
- "name": "selected",
16841
- "description": "DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation.\nRemove with GAUD-8299-core-tabs-use-new-structure flag clean up.",
16842
- "type": "boolean"
16843
- },
16844
- {
16845
- "name": "text",
16846
- "description": "DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation.\nRemove with GAUD-8299-core-tabs-use-new-structure flag clean up.",
16847
- "type": "string"
16848
- },
16849
16778
  {
16850
16779
  "name": "no-padding",
16851
16780
  "description": "Opt out of default padding/whitespace around the panel",
@@ -16860,21 +16789,9 @@
16860
16789
  "description": "REQUIRED: Id of the tab that labels this panel",
16861
16790
  "type": "string"
16862
16791
  },
16863
- {
16864
- "name": "selected",
16865
- "attribute": "selected",
16866
- "description": "DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation.\nRemove with GAUD-8299-core-tabs-use-new-structure flag clean up.",
16867
- "type": "boolean"
16868
- },
16869
- {
16870
- "name": "text",
16871
- "attribute": "text",
16872
- "description": "DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation.\nRemove with GAUD-8299-core-tabs-use-new-structure flag clean up.",
16873
- "type": "string"
16874
- },
16875
16792
  {
16876
16793
  "name": "styles",
16877
- "default": "\"css`\\n\\t\\t:host {\\n\\t\\t\\tbox-sizing: border-box;\\n\\t\\t\\tdisplay: none;\\n\\t\\t\\tmargin: 1.2rem 0 0 0;\\n\\t\\t}\\n\\t\\t:host([no-padding]) {\\n\\t\\t\\tmargin: 0;\\n\\t\\t}\\n\\t\\t/* clean up with GAUD-8299-core-tabs-use-new-structure flag clean up */\\n\\t\\t:host([selected]) {\\n\\t\\t\\tdisplay: block;\\n\\t\\t}\\n\\t\\t:host([_selected]) {\\n\\t\\t\\tdisplay: block;\\n\\t\\t}\\n\\t`\""
16794
+ "default": "\"css`\\n\\t\\t:host {\\n\\t\\t\\tbox-sizing: border-box;\\n\\t\\t\\tdisplay: none;\\n\\t\\t\\tmargin: 1.2rem 0 0 0;\\n\\t\\t}\\n\\t\\t:host([no-padding]) {\\n\\t\\t\\tmargin: 0;\\n\\t\\t}\\n\\t\\t:host([_selected]) {\\n\\t\\t\\tdisplay: block;\\n\\t\\t}\\n\\t`\""
16878
16795
  },
16879
16796
  {
16880
16797
  "name": "noPadding",
@@ -16884,16 +16801,6 @@
16884
16801
  "default": "false"
16885
16802
  }
16886
16803
  ],
16887
- "events": [
16888
- {
16889
- "name": "d2l-tab-panel-selected",
16890
- "description": "DEPRECATED: Dispatched when a tab is selected"
16891
- },
16892
- {
16893
- "name": "d2l-tab-panel-text-changed",
16894
- "description": "DEPRECATED: Dispatched when the text attribute is changed"
16895
- }
16896
- ],
16897
16804
  "slots": [
16898
16805
  {
16899
16806
  "name": "",
@@ -17047,10 +16954,6 @@
17047
16954
  }
17048
16955
  ],
17049
16956
  "slots": [
17050
- {
17051
- "name": "",
17052
- "description": "DEPRECATED: Contains the tab panels (e.g., \"d2l-tab-panel\" components)"
17053
- },
17054
16957
  {
17055
16958
  "name": "ext",
17056
16959
  "description": "Additional content (e.g., a button) positioned at right"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.315.0",
3
+ "version": "3.317.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",
@@ -1,144 +0,0 @@
1
- import '../colors/colors.js';
2
- import { css, html, LitElement } from 'lit';
3
- import { classMap } from 'lit/directives/class-map.js';
4
- import { getFocusRingStyles } from '../../helpers/focus.js';
5
- import { overflowEllipsisDeclarations } from '../../helpers/overflow.js';
6
- import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
7
-
8
- const keyCodes = {
9
- ENTER: 13,
10
- SPACE: 32
11
- };
12
-
13
- // remove file with GAUD-8299-core-tabs-use-new-structure flag clean up
14
- class Tab extends SkeletonMixin(LitElement) {
15
-
16
- static properties = {
17
- ariaSelected: { type: String, reflect: true, attribute: 'aria-selected' },
18
- controlsPanel: { type: String, reflect: true, attribute: 'controls-panel' },
19
- // eslint-disable-next-line lit/no-native-attributes
20
- role: { type: String, reflect: true },
21
- text: { type: String }
22
- };
23
-
24
- static styles = [super.styles, css`
25
- :host {
26
- box-sizing: border-box;
27
- display: inline-block;
28
- max-width: 200px;
29
- outline: none;
30
- position: relative;
31
- vertical-align: middle;
32
- }
33
- .d2l-tab-text {
34
- --d2l-focus-ring-offset: 0;
35
- margin: 0.5rem;
36
- padding: 0.1rem;
37
- ${overflowEllipsisDeclarations}
38
- }
39
- :host([skeleton]) .d2l-tab-text.d2l-skeletize::before {
40
- bottom: 0.15rem;
41
- top: 0.15rem;
42
- }
43
- :host(:first-child) .d2l-tab-text {
44
- margin-inline-start: 0;
45
- }
46
- .d2l-tab-selected-indicator {
47
- border-top: 4px solid var(--d2l-theme-brand-color-primary-default);
48
- border-top-left-radius: 4px;
49
- border-top-right-radius: 4px;
50
- bottom: 0;
51
- display: none;
52
- margin: 1px 0.6rem 0 0.6rem;
53
- position: absolute;
54
- -webkit-transition: box-shadow 0.2s;
55
- transition: box-shadow 0.2s;
56
- width: calc(100% - 1.2rem);
57
- }
58
- :host([skeleton]) .d2l-tab-selected-indicator {
59
- position: absolute; /* make sure skeleton styles do not override this */
60
- }
61
- .d2l-tab-text-skeletize-override {
62
- min-width: 50px;
63
- }
64
- :host(:first-child) .d2l-tab-selected-indicator {
65
- margin-inline-start: 0;
66
- width: calc(100% - 0.6rem);
67
- }
68
- ${getFocusRingStyles(pseudoClass => `:host(:${pseudoClass}) > .d2l-tab-text`, { extraStyles: css`border-radius: 0.3rem; color: var(--d2l-theme-text-color-interactive-default);` })}
69
- :host([aria-selected="true"]:focus) {
70
- text-decoration: none;
71
- }
72
- :host(:hover) {
73
- color: var(--d2l-theme-text-color-interactive-default);
74
- cursor: pointer;
75
- }
76
- :host([aria-selected="true"]:hover) {
77
- color: inherit;
78
- cursor: default;
79
- }
80
- :host([aria-selected="true"]) .d2l-tab-selected-indicator {
81
- display: block;
82
- }
83
-
84
- @media (prefers-reduced-motion: reduce) {
85
- .d2l-tab-selected-indicator {
86
- -webkit-transition: none;
87
- transition: none;
88
- }
89
- }
90
- `];
91
-
92
- constructor() {
93
- super();
94
- this.ariaSelected = 'false';
95
- this.role = 'tab';
96
- this.tabIndex = -1;
97
- }
98
-
99
- firstUpdated(changedProperties) {
100
- super.firstUpdated(changedProperties);
101
- this.addEventListener('click', () => {
102
- this.ariaSelected = 'true';
103
- });
104
- this.addEventListener('keydown', (e) => {
105
- if (e.keyCode !== keyCodes.SPACE) return;
106
- e.stopPropagation();
107
- e.preventDefault();
108
- });
109
- this.addEventListener('keyup', (e) => {
110
- if (e.keyCode !== keyCodes.ENTER && e.keyCode !== keyCodes.SPACE) return;
111
- this.ariaSelected = 'true';
112
- });
113
- }
114
-
115
- render() {
116
- const overrideSkeletonText = this.skeleton && (!this.text || this.text.length === 0);
117
- const textClasses = {
118
- 'd2l-tab-text': true,
119
- 'd2l-skeletize': true,
120
- 'd2l-tab-text-skeletize-override': overrideSkeletonText
121
- };
122
-
123
- return html`
124
- <div class="${classMap(textClasses)}">${overrideSkeletonText ? html`&nbsp;` : this.text}</div>
125
- <div class="d2l-tab-selected-indicator d2l-skeletize-container"></div>
126
- `;
127
- }
128
-
129
- update(changedProperties) {
130
- super.update(changedProperties);
131
- changedProperties.forEach((oldVal, prop) => {
132
- if (prop === 'ariaSelected' && this.ariaSelected === 'true') {
133
- this.dispatchEvent(new CustomEvent(
134
- 'd2l-tab-selected', { bubbles: true, composed: true }
135
- ));
136
- } else if (prop === 'text') {
137
- this.title = this.text;
138
- }
139
- });
140
- }
141
-
142
- }
143
-
144
- customElements.define('d2l-tab-internal', Tab);