@brightspace-ui/core 3.167.1 → 3.169.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.
@@ -216,6 +216,49 @@
216
216
  </template>
217
217
  </d2l-demo-snippet>
218
218
 
219
+ <h3>Tabs (with hidden)</h3>
220
+
221
+ <d2l-demo-snippet>
222
+ <template>
223
+ <div style="display: flex; gap: 0.5rem; margin-bottom: 0.5rem;">
224
+ <d2l-button-subtle text="Hide Next Tab" primary aria-label="Hide next visible tab" title="Hide next visible tab" id="hide-next-tab-btn"></d2l-button-subtle>
225
+ <d2l-button-subtle text="Show Next Hidden Tab" primary aria-label="Show next hidden tab" title="Show next hidden tab" id="show-next-hidden-tab-btn"></d2l-button-subtle>
226
+ </div>
227
+ <d2l-tabs text="Courses">
228
+ <d2l-tab id="all" text="All" slot="tabs" ></d2l-tab>
229
+ <d2l-tab id="biology" text="Biology" slot="tabs"></d2l-tab>
230
+ <d2l-tab id="chemistry" text="Chemistry" slot="tabs" ></d2l-tab>
231
+ <d2l-tab id="physics" text="Physics" slot="tabs" hidden></d2l-tab>
232
+ <d2l-tab id="math" text="Math" slot="tabs" hidden></d2l-tab>
233
+ <d2l-tab id="earth-sciences" text="Earth Sciences" slot="tabs" hidden></d2l-tab>
234
+ <d2l-tab-panel labelled-by="all" slot="panels" id="all-panel">Tab content for All</d2l-tab-panel>
235
+ <d2l-tab-panel labelled-by="biology" slot="panels" id="biology-panel">Tab content for Biology</d2l-tab-panel>
236
+ <d2l-tab-panel labelled-by="chemistry" slot="panels">Tab content for Chemistry</d2l-tab-panel>
237
+ <d2l-tab-panel labelled-by="physics" slot="panels">Tab content for Physics</d2l-tab-panel>
238
+ <d2l-tab-panel labelled-by="math" slot="panels">Tab content for Math</d2l-tab-panel>
239
+ <d2l-tab-panel labelled-by="earth-sciences" slot="panels">Tab content for Earth Sciences</d2l-tab-panel>
240
+ </d2l-tabs>
241
+ <script>
242
+ const templateRoot = document.currentScript.parentNode;
243
+ const hideBtn = templateRoot.querySelector('#hide-next-tab-btn');
244
+ const showBtn = templateRoot.querySelector('#show-next-hidden-tab-btn');
245
+ const tabsEl = templateRoot.querySelector('d2l-tabs');
246
+
247
+ hideBtn.addEventListener('click', () => {
248
+ const visibleTabs = [...tabsEl.querySelectorAll('d2l-tab:not([hidden])')];
249
+ if (visibleTabs.length === 0) return;
250
+ visibleTabs[0].setAttribute('hidden', '');
251
+ });
252
+
253
+ showBtn.addEventListener('click', () => {
254
+ const hiddenTabs = [...tabsEl.querySelectorAll('d2l-tab[hidden]')];
255
+ if (hiddenTabs.length === 0) return;
256
+ hiddenTabs[0].removeAttribute('hidden');
257
+ });
258
+ </script>
259
+ </template>
260
+ </d2l-demo-snippet>
261
+
219
262
  <h3>Tabs (responsive)</h3>
220
263
 
221
264
  <d2l-demo-snippet>
@@ -12,6 +12,10 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
12
12
 
13
13
  static get properties() {
14
14
  return {
15
+ /**
16
+ * @ignore
17
+ */
18
+ hidden: { type: Boolean, reflect: true },
15
19
  /**
16
20
  * Use to select the tab. Only one tab can be selected at a time.
17
21
  * @type {boolean}
@@ -40,6 +44,9 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
40
44
  position: relative;
41
45
  vertical-align: middle;
42
46
  }
47
+ :host([hidden]) {
48
+ display: none;
49
+ }
43
50
  .d2l-tab-content {
44
51
  margin: 0.5rem;
45
52
  }
@@ -90,12 +97,13 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
90
97
 
91
98
  constructor() {
92
99
  super();
100
+ this.hidden = false;
93
101
  this.role = 'tab';
94
102
  this.selected = false;
95
103
  this.tabIndex = -1;
96
104
 
97
105
  this._clicked = false;
98
- this._noInitialSelectedEvent = getFlag('GAUD-8605-tab-no-initial-selected-event', false);
106
+ this._noInitialSelectedEvent = getFlag('GAUD-8605-tab-no-initial-selected-event', true);
99
107
  }
100
108
 
101
109
  firstUpdated(changedProperties) {
@@ -134,6 +142,12 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
134
142
  ));
135
143
  }
136
144
  }
145
+ if (changedProperties.has('hidden') && changedProperties.get('hidden') !== undefined) {
146
+ /** @ignore */
147
+ this.dispatchEvent(new CustomEvent(
148
+ 'd2l-tab-hidden-change', { bubbles: true }
149
+ ));
150
+ }
137
151
  }
138
152
 
139
153
  /**
@@ -370,6 +370,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
370
370
  ${this.arrowKeysContainer(html`
371
371
  <div class="d2l-tabs-container-list"
372
372
  @d2l-tab-content-change="${this._handleTabContentChange}"
373
+ @d2l-tab-hidden-change="${this.#handleTabHiddenChange}"
373
374
  @d2l-tab-selected="${this._handleTabSelected}"
374
375
  @d2l-tab-deselected="${this.#handleTabDeselected}"
375
376
  @focusout="${this._handleFocusOut}"
@@ -1056,31 +1057,15 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1056
1057
  return this.updateComplete;
1057
1058
  }
1058
1059
 
1060
+ // Legacy structure clean up: if possible base this on visible tabs going forward
1059
1061
  _updateTabListVisibility(panels) {
1060
1062
  if (this._state === 'shown' && panels.length < 2) {
1061
- // don't animate the tabs list visibility if it's the inital render
1062
- if (reduceMotion || !this._initialized) {
1063
- this._state = 'hidden';
1064
- } else if (this.shadowRoot) {
1065
- const layout = this.shadowRoot.querySelector('.d2l-tabs-layout');
1066
- const handleTransitionEnd = (e) => {
1067
- if (e.propertyName !== 'max-height') return;
1068
- layout.removeEventListener('transitionend', handleTransitionEnd);
1069
- this._state = 'hidden';
1070
- };
1071
- layout.addEventListener('transitionend', handleTransitionEnd);
1072
- this._state = 'anim';
1073
- }
1063
+ this.#hideTabsList();
1074
1064
  } else if (this._state === 'hidden' && panels.length > 1) {
1075
- // don't animate the tabs list visibility if it's the inital render
1076
- if (reduceMotion || !this._initialized) {
1077
- this._state = 'shown';
1078
- } else {
1079
- this._state = 'anim';
1080
- requestAnimationFrame(() => {
1081
- this._state = 'shown';
1082
- });
1083
- }
1065
+ this.#showTabsList();
1066
+ } else if (this._state === 'shown' && panels.length > 1) {
1067
+ // check if there are hidden tabs and tab list container should actually be hidden
1068
+ this.#handleTabHiddenChange();
1084
1069
  }
1085
1070
  }
1086
1071
 
@@ -1201,6 +1186,34 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1201
1186
  if (panel) panel.selected = false;
1202
1187
  }
1203
1188
 
1189
+ #handleTabHiddenChange() {
1190
+ if (!this._tabs || this._tabs.length <= 1) return;
1191
+
1192
+ let visibleTabCount = 0;
1193
+ this._tabs.forEach((tab) => {
1194
+ if (!tab.hidden) visibleTabCount++;
1195
+ });
1196
+
1197
+ if (visibleTabCount > 1 && this._state === 'hidden') this.#showTabsList();
1198
+ else if (visibleTabCount <= 1 && this._state === 'shown') this.#hideTabsList();
1199
+ }
1200
+
1201
+ #hideTabsList() {
1202
+ // don't animate the tabs list visibility if it's the inital render
1203
+ if (reduceMotion || !this._initialized) {
1204
+ this._state = 'hidden';
1205
+ } else if (this.shadowRoot) {
1206
+ const layout = this.shadowRoot.querySelector('.d2l-tabs-layout');
1207
+ const handleTransitionEnd = (e) => {
1208
+ if (e.propertyName !== 'max-height') return;
1209
+ layout.removeEventListener('transitionend', handleTransitionEnd);
1210
+ this._state = 'hidden';
1211
+ };
1212
+ layout.addEventListener('transitionend', handleTransitionEnd);
1213
+ this._state = 'anim';
1214
+ }
1215
+ }
1216
+
1204
1217
  #isRTL() {
1205
1218
  return document.documentElement.getAttribute('dir') === 'rtl';
1206
1219
  }
@@ -1223,6 +1236,18 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1223
1236
  }, 0);
1224
1237
  }
1225
1238
 
1239
+ #showTabsList() {
1240
+ // don't animate the tabs list visibility if it's the inital render
1241
+ if (reduceMotion || !this._initialized) {
1242
+ this._state = 'shown';
1243
+ } else {
1244
+ this._state = 'anim';
1245
+ requestAnimationFrame(() => {
1246
+ this._state = 'shown';
1247
+ });
1248
+ }
1249
+ }
1250
+
1226
1251
  #updateScrollPositionLogic(measures, newTranslationValue) {
1227
1252
  const scrollToPromise = this._scrollToPosition(newTranslationValue);
1228
1253
  const scrollVisibilityPromise = this._updateScrollVisibility(measures);
@@ -14010,6 +14010,11 @@
14010
14010
  }
14011
14011
  ],
14012
14012
  "properties": [
14013
+ {
14014
+ "name": "hidden",
14015
+ "type": "boolean",
14016
+ "default": "false"
14017
+ },
14013
14018
  {
14014
14019
  "name": "role",
14015
14020
  "type": "string",
@@ -14226,6 +14231,11 @@
14226
14231
  "description": "ACCESSIBILITY: REQUIRED: The text used for the tab and for labelling the corresponding panel",
14227
14232
  "type": "string"
14228
14233
  },
14234
+ {
14235
+ "name": "hidden",
14236
+ "type": "boolean",
14237
+ "default": "false"
14238
+ },
14229
14239
  {
14230
14240
  "name": "role",
14231
14241
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.167.1",
3
+ "version": "3.169.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",