@brightspace-ui/core 3.248.1 → 3.250.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.
@@ -73,10 +73,10 @@ class PageHeaderButton extends FocusMixin(LitElement) {
73
73
 
74
74
  render() {
75
75
  const { ariaLabel, id, text, tooltip } = this.#getRenderSettings();
76
- const highlightBorder = !this.disabled ? html`<span class="d2l-labs-navigation-highlight-border"></span>` : nothing;
76
+ const highlightBorder = !this.disabled ? html`<span class="d2l-page-header-highlight-border"></span>` : nothing;
77
77
  const icon = html`<d2l-icon icon="${this.icon}"></d2l-icon>`;
78
78
  return html`
79
- <button id="${ifDefined(id)}" ?disabled="${this.disabled}" aria-label="${ifDefined(ariaLabel)}" type="button">
79
+ <button class="d2l-page-header-highlight-button" id="${ifDefined(id)}" ?disabled="${this.disabled}" aria-label="${ifDefined(ariaLabel)}" type="button">
80
80
  ${highlightBorder}
81
81
  ${this.iconPosition === 'start' ? icon : nothing}
82
82
  ${text}
@@ -0,0 +1,167 @@
1
+ import '../alert/alert.js';
2
+ import '../colors/colors.js';
3
+ import '../icons/icon.js';
4
+ import './page-header-custom.js';
5
+ import { bodyCompactStyles, heading3Styles, labelStyles } from '../typography/styles.js';
6
+ import { css, html, LitElement } from 'lit';
7
+ import { highlightBorderStyles, highlightLinkStyles } from './page-header-styles.js';
8
+ import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
9
+ import { overflowEllipsisDeclarations } from '../../helpers/overflow.js';
10
+ import { RequesterMixin } from '../../mixins/provider/provider-mixin.js';
11
+
12
+ class PageHeaderImmersive extends RequesterMixin(LocalizeCoreElement(LitElement)) {
13
+
14
+ static get properties() {
15
+ return {
16
+ backHref: { attribute: 'back-href', type: String },
17
+ backCustomText: { attribute: 'back-custom-text', type: String },
18
+ titleText: { attribute: 'title-text', type: String },
19
+ subtitleText: { attribute: 'subtitle-text', type: String },
20
+ _error: { state: true },
21
+ _hasActions: { state: true }
22
+ };
23
+ }
24
+
25
+ static get styles() {
26
+ return [bodyCompactStyles, heading3Styles, labelStyles, highlightBorderStyles, highlightLinkStyles, css`
27
+ :host {
28
+ display: block;
29
+ }
30
+ :host([hidden]),
31
+ .actions[hidden] {
32
+ display: none;
33
+ }
34
+ .container {
35
+ align-items: stretch;
36
+ display: flex;
37
+ gap: 24px;
38
+ height: 3.1rem;
39
+ }
40
+ .title {
41
+ flex: 0 1 auto;
42
+ min-width: 0;
43
+ width: 100%;
44
+ }
45
+ .back,
46
+ .actions {
47
+ flex: 0 0 auto;
48
+ }
49
+ .title,
50
+ .actions {
51
+ border-inline-start: 1px solid var(--d2l-color-gypsum);
52
+ padding-inline-start: 24px;
53
+ }
54
+ .title h1 {
55
+ display: flex;
56
+ flex-direction: column;
57
+ height: 100%;
58
+ justify-content: center;
59
+ margin: 0;
60
+ }
61
+ .actions {
62
+ align-items: center;
63
+ display: flex;
64
+ gap: 0.6rem;
65
+ }
66
+ .title h1 .d2l-heading-3 {
67
+ margin: 0;
68
+ }
69
+ .back-text-short {
70
+ display: none;
71
+ }
72
+ @media (max-width: 615px) {
73
+ .back-text-long {
74
+ display: none;
75
+ }
76
+ .back-text-short {
77
+ display: inline;
78
+ }
79
+ }
80
+ d2l-alert {
81
+ margin: 10px auto;
82
+ }
83
+ .title-text {
84
+ ${overflowEllipsisDeclarations}
85
+ }
86
+ `];
87
+ }
88
+
89
+ constructor() {
90
+ super();
91
+ this._error = false;
92
+ this._hasActions = false;
93
+ }
94
+
95
+ connectedCallback() {
96
+ super.connectedCallback();
97
+ const configurePageHeader = this.requestInstance('d2l-page-header-configure');
98
+ if (configurePageHeader) {
99
+ configurePageHeader({ sticky: true });
100
+ } else {
101
+ this._error = true;
102
+ }
103
+ }
104
+
105
+ render() {
106
+ if (this._error) return this.#renderError();
107
+ return html`
108
+ <d2l-page-header-custom>
109
+ <div class="container" slot="top">
110
+ ${this.#renderBack()}
111
+ ${this.#renderTitle()}
112
+ <div class="actions" ?hidden="${!this._hasActions}">
113
+ <slot name="actions" @slotchange="${this.#handleActionsSlotChange}"></slot>
114
+ </div>
115
+ </div>
116
+ </d2l-page-header-custom>
117
+ `;
118
+ }
119
+
120
+ #handleActionsSlotChange(e) {
121
+ this._hasActions = e.target.assignedNodes({ flatten: true })?.length > 0;
122
+ }
123
+
124
+ #handleBackClick() {
125
+ this.dispatchEvent(
126
+ new CustomEvent(
127
+ 'd2l-page-header-immersive-back-click',
128
+ { bubbles: false, composed: false }
129
+ )
130
+ );
131
+ }
132
+
133
+ #renderBack() {
134
+ const href = this.backHref || 'javascript:void(0);';
135
+ const commonText = this.localizeCommon('navigation:back:title');
136
+ const longText = this.backCustomText || commonText;
137
+ return html`
138
+ <div class="back d2l-body-compact">
139
+ <a class="d2l-page-header-highlight-link" href="${href}" aria-label="${longText}" @click="${this.#handleBackClick}">
140
+ <span class="d2l-page-header-highlight-border"></span>
141
+ <d2l-icon icon="tier1:chevron-left"></d2l-icon>
142
+ <span class="back-text-long">${longText}</span>
143
+ <span class="back-text-short">${commonText}</span>
144
+ </a>
145
+ </div>
146
+ `;
147
+ }
148
+
149
+ #renderError() {
150
+ return html`
151
+ <d2l-alert type="critical">&lt;d2l-page-header-immersive&gt; must be rendered inside a &lt;d2l-page&gt;'s header slot.</d2l-alert>
152
+ `;
153
+ }
154
+
155
+ #renderTitle() {
156
+ const title = this.titleText ? html`<div class="title-text d2l-heading-3">${this.titleText}</div>` : '';
157
+ const subtitle = this.subtitleText ? html`<div class="title-text d2l-label-text">${this.subtitleText}</div>` : '';
158
+ const heading = (title || subtitle) && html`<h1>${title}${subtitle}</h1>`;
159
+ return html`
160
+ <div class="title">
161
+ <slot name="title">${heading}</slot>
162
+ </div>
163
+ `;
164
+ }
165
+
166
+ }
167
+ customElements.define('d2l-page-header-immersive', PageHeaderImmersive);
@@ -2,7 +2,7 @@ import '../colors/colors.js';
2
2
  import { css } from 'lit';
3
3
 
4
4
  export const highlightBorderStyles = css`
5
- .d2l-labs-navigation-highlight-border {
5
+ .d2l-page-header-highlight-border {
6
6
  background: transparent;
7
7
  border-bottom-left-radius: 4px;
8
8
  border-bottom-right-radius: 4px;
@@ -12,15 +12,15 @@ export const highlightBorderStyles = css`
12
12
  position: absolute;
13
13
  top: 0;
14
14
  }
15
- *:focus > .d2l-labs-navigation-highlight-border,
16
- *:hover > .d2l-labs-navigation-highlight-border,
17
- *[active] > .d2l-labs-navigation-highlight-border {
15
+ *:focus > .d2l-page-header-highlight-border,
16
+ *:hover > .d2l-page-header-highlight-border,
17
+ *[active] > .d2l-page-header-highlight-border {
18
18
  background: var(--d2l-color-celestine);
19
19
  }
20
20
  `;
21
21
 
22
22
  export const highlightButtonStyles = css`
23
- button {
23
+ button.d2l-page-header-highlight-button {
24
24
  align-items: center;
25
25
  background: transparent;
26
26
  border: none;
@@ -41,18 +41,39 @@ export const highlightButtonStyles = css`
41
41
  white-space: nowrap;
42
42
  }
43
43
  /* Firefox includes a hidden border which messes up button dimensions */
44
- button::-moz-focus-inner {
44
+ button.d2l-page-header-highlight-button::-moz-focus-inner {
45
45
  border: 0;
46
46
  }
47
- button:not([disabled]):hover,
48
- button:not([disabled]):focus,
49
- button[active] {
47
+ button.d2l-page-header-highlight-button:not([disabled]):hover,
48
+ button.d2l-page-header-highlight-button:not([disabled]):focus,
49
+ button.d2l-page-header-highlight-button[active] {
50
50
  --d2l-icon-fill-color: var(--d2l-color-celestine);
51
51
  color: var(--d2l-color-celestine);
52
52
  outline: none;
53
53
  }
54
- button[disabled] {
54
+ button.d2l-page-header-highlight-button[disabled] {
55
55
  cursor: default;
56
56
  opacity: 0.5;
57
57
  }
58
58
  `;
59
+
60
+ export const highlightLinkStyles = css`
61
+ a.d2l-page-header-highlight-link {
62
+ align-items: center;
63
+ color: var(--d2l-color-ferrite);
64
+ display: inline-flex;
65
+ gap: 6px;
66
+ height: 100%;
67
+ min-height: 40px;
68
+ position: relative;
69
+ text-decoration: none;
70
+ vertical-align: middle;
71
+ white-space: nowrap;
72
+ }
73
+ a.d2l-page-header-highlight-link:hover,
74
+ a.d2l-page-header-highlight-link:focus {
75
+ --d2l-icon-fill-color: var(--d2l-color-celestine);
76
+ color: var(--d2l-color-celestine);
77
+ outline: none;
78
+ }
79
+ `;
@@ -3,6 +3,7 @@ import '../button/floating-buttons.js';
3
3
  import { css, html, LitElement, nothing } from 'lit';
4
4
  import { classMap } from 'lit/directives/class-map.js';
5
5
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
6
+ import { ProviderMixin } from '../../mixins/provider/provider-mixin.js';
6
7
 
7
8
  /**
8
9
  * Component for laying out a page, with header, optional footer and optional navigation or supporting panels
@@ -12,7 +13,7 @@ import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
12
13
  * @slot supporting - The supporting content of the page (expecting d2l-page-supporting)
13
14
  * @slot footer - The footer content of the page (expecting d2l-page-footer)
14
15
  */
15
- class Page extends LocalizeCoreElement(LitElement) {
16
+ class Page extends ProviderMixin(LocalizeCoreElement(LitElement)) {
16
17
 
17
18
  static properties = {
18
19
  /**
@@ -127,6 +128,9 @@ class Page extends LocalizeCoreElement(LitElement) {
127
128
  }
128
129
  }
129
130
  });
131
+ this.provideInstance('d2l-page-header-configure', (options) => {
132
+ this._headerIsSticky = options.sticky;
133
+ });
130
134
  }
131
135
 
132
136
  disconnectedCallback() {
@@ -162,12 +166,6 @@ class Page extends LocalizeCoreElement(LitElement) {
162
166
 
163
167
  #resizeObserver;
164
168
 
165
- #handleHeaderSlotChange(e) {
166
- const nodes = e.target.assignedNodes();
167
- //this._headerIsSticky = nodes.some(node => node.tagName.toLowerCase() === 'd2l-page-header-immersive');
168
- this._headerIsSticky = nodes.some(node => node.id === 'immersive-nav'); // temp until the official component exists
169
- }
170
-
171
169
  #handleSlotVisibilityChange(e) {
172
170
  const key = e.target.name;
173
171
  const nodes = e.target.assignedNodes();
@@ -200,7 +198,7 @@ class Page extends LocalizeCoreElement(LitElement) {
200
198
  return html`
201
199
  <header class="header">
202
200
  <nav aria-label="${this.localize('components.page.header-nav-label')}">
203
- <slot name="header" @slotchange="${this.#handleHeaderSlotChange}"></slot>
201
+ <slot name="header"></slot>
204
202
  </nav>
205
203
  </header>
206
204
  `;
@@ -10,6 +10,7 @@ const keyCodes = {
10
10
  SPACE: 32
11
11
  };
12
12
 
13
+ // remove file with GAUD-8299-core-tabs-use-new-structure flag clean up
13
14
  class Tab extends SkeletonMixin(LitElement) {
14
15
 
15
16
  static get properties() {
@@ -1,4 +1,5 @@
1
1
  import { css } from 'lit';
2
+ import { getFlag } from '../../helpers/flags.js';
2
3
  import { getUniqueId } from '../../helpers/uniqueId.js';
3
4
 
4
5
  export const TabPanelMixin = superclass => class extends superclass {
@@ -22,14 +23,17 @@ export const TabPanelMixin = superclass => class extends superclass {
22
23
  role: { type: String, reflect: true },
23
24
  /**
24
25
  * DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation.
26
+ * Remove with GAUD-8299-core-tabs-use-new-structure flag clean up.
25
27
  * @type {boolean}
26
28
  */
27
29
  selected: { type: Boolean, reflect: true },
28
30
  /**
29
31
  * DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation.
32
+ * Remove with GAUD-8299-core-tabs-use-new-structure flag clean up.
30
33
  * @type {string}
31
34
  */
32
- text: { type: String }
35
+ text: { type: String },
36
+ _selected: { type: Boolean, attribute: '_selected', reflect: true }
33
37
  };
34
38
  }
35
39
 
@@ -43,9 +47,13 @@ export const TabPanelMixin = superclass => class extends superclass {
43
47
  :host([no-padding]) {
44
48
  margin: 0;
45
49
  }
50
+ /* clean up with GAUD-8299-core-tabs-use-new-structure flag clean up */
46
51
  :host([selected]) {
47
52
  display: block;
48
53
  }
54
+ :host([_selected]) {
55
+ display: block;
56
+ }
49
57
  `;
50
58
  }
51
59
 
@@ -54,7 +62,8 @@ export const TabPanelMixin = superclass => class extends superclass {
54
62
  this.noPadding = false;
55
63
  /** @ignore */
56
64
  this.role = 'tabpanel';
57
- this.selected = false;
65
+ this._selected = false;
66
+ if (!this.#useTabsNewStructure) this.selected = false; // clean up with GAUD-8299-core-tabs-use-new-structure flag clean up
58
67
  }
59
68
 
60
69
  connectedCallback() {
@@ -68,7 +77,12 @@ export const TabPanelMixin = superclass => class extends superclass {
68
77
  changedProperties.forEach((oldVal, prop) => {
69
78
  if (prop === 'labelledBy') {
70
79
  this.setAttribute('aria-labelledby', this.labelledBy);
71
- } else if (prop === 'selected') {
80
+ }
81
+
82
+ // clean up below with GAUD-8299-core-tabs-use-new-structure flag clean up
83
+ if (this.#useTabsNewStructure) return;
84
+
85
+ if (prop === 'selected') {
72
86
  if (this.selected) {
73
87
  requestAnimationFrame(() => {
74
88
  /** DEPRECATED: Dispatched when a tab is selected */
@@ -87,4 +101,6 @@ export const TabPanelMixin = superclass => class extends superclass {
87
101
  });
88
102
  }
89
103
 
104
+ #useTabsNewStructure = getFlag('GAUD-8299-core-tabs-use-new-structure', false);
105
+
90
106
  };
@@ -1,12 +1,13 @@
1
1
  import '../colors/colors.js';
2
2
  import '../icons/icon.js';
3
3
  import './tab-internal.js';
4
- import { css, html, LitElement, unsafeCSS } from 'lit';
4
+ import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
5
5
  import { cssEscape, findComposedAncestor, getOffsetParent, isVisible } from '../../helpers/dom.js';
6
6
  import { getFocusPseudoClass, getFocusRingStyles } from '../../helpers/focus.js';
7
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
+ import { getFlag } from '../../helpers/flags.js';
10
11
  import { getOverflowDeclarations } from '../../helpers/overflow.js';
11
12
  import { ifDefined } from 'lit/directives/if-defined.js';
12
13
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
@@ -229,14 +230,20 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
229
230
  this.maxToShow = -1;
230
231
  this._allowScrollNext = false;
231
232
  this._allowScrollPrevious = false;
232
- this._defaultSlotBehavior = true; // remove after d2l-tab/d2l-tab-panel backport
233
+
234
+ /*
235
+ * Remove this._defaultSlotBehavior and related code with GAUD-8299-core-tabs-use-new-structure flag clean up
236
+ * NOTE: remove the TRUE case of _defaultSlotBehavior
237
+ */
238
+ this._defaultSlotBehavior = !this.#newTabsPanelStructure;
239
+
233
240
  this._loadingCompleteResolve = undefined;
234
241
  this._loadingCompletePromise = new Promise(resolve => this._loadingCompleteResolve = resolve);
235
242
  this._maxWidth = null;
236
243
  this._scrollCollapsed = false;
237
244
  this._state = 'shown';
238
245
  this._tabIds = {};
239
- this._tabInfos = []; // remove after d2l-tab/d2l-tab-panel backport
246
+ if (this._defaultSlotBehavior) this._tabInfos = [];
240
247
  this._translationValue = 0;
241
248
  }
242
249
 
@@ -266,7 +273,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
266
273
 
267
274
  this.arrowKeysOnBeforeFocus = async(tab) => {
268
275
  if (this._defaultSlotBehavior) {
269
- // remove this section after d2l-tab/d2l-tab-panel backport
276
+ // remove this section with GAUD-8299-core-tabs-use-new-structure flag clean up
270
277
  const tabInfo = this._getTabInfo(tab.controlsPanel);
271
278
  this._setFocusableDefaultSlotBehavior(tabInfo);
272
279
 
@@ -370,7 +377,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
370
377
  aria-label="${ifDefined(this.text)}"
371
378
  role="tablist"
372
379
  style="${styleMap(tabsContainerListStyles)}">
373
- ${repeat(this._tabInfos, (tabInfo) => tabInfo.id, (tabInfo) => html`
380
+ ${!this.#newTabsPanelStructure ? repeat(this._tabInfos, (tabInfo) => tabInfo.id, (tabInfo) => html`
374
381
  <d2l-tab-internal aria-selected="${tabInfo.selected ? 'true' : 'false'}"
375
382
  .controlsPanel="${tabInfo.id}"
376
383
  data-state="${tabInfo.state}"
@@ -378,7 +385,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
378
385
  tabindex="${tabInfo.activeFocusable ? 0 : -1}"
379
386
  text="${tabInfo.text}">
380
387
  </d2l-tab-internal>
381
- `)}
388
+ `) : nothing}
382
389
  <slot name="tabs" @slotchange="${this._handleTabsSlotChange}"></slot>
383
390
  </div>
384
391
  `)}
@@ -393,9 +400,9 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
393
400
  <div class="d2l-tabs-container-ext"><slot name="ext"></slot></div>
394
401
  </div>
395
402
  <div class="${classMap(panelContainerClasses)}"
396
- @d2l-tab-panel-selected="${this._handlePanelSelected}"
397
- @d2l-tab-panel-text-changed="${this._handlePanelTextChange}">
398
- <slot @slotchange="${this._handleDefaultSlotChange}"></slot>
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}
399
406
  <slot name="panels" @slotchange="${this._handlePanelsSlotChange}"></slot>
400
407
  </div>
401
408
  `;
@@ -420,6 +427,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
420
427
  }
421
428
 
422
429
  #checkTabPanelMatchRequested;
430
+ #newTabsPanelStructure = getFlag('GAUD-8299-core-tabs-use-new-structure', false);
423
431
  #panels;
424
432
  #updateAriaControlsRequested;
425
433
 
@@ -444,7 +452,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
444
452
  });
445
453
  }
446
454
 
447
- // remove after d2l-tab/d2l-tab-panel backport
455
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
448
456
  _animateTabAdditionDefaultSlotBehavior(tabInfo) {
449
457
  const tab = this.shadowRoot
450
458
  && this.shadowRoot.querySelector(`d2l-tab-internal[controls-panel="${cssEscape(tabInfo.id)}"]`);
@@ -476,7 +484,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
476
484
  });
477
485
  }
478
486
 
479
- // remove after d2l-tab/d2l-tab-panel backport
487
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
480
488
  _animateTabRemovalDefaultSlotBehavior(tabInfo) {
481
489
  const tab = this.shadowRoot &&
482
490
  this.shadowRoot.querySelector(`d2l-tab-internal[controls-panel="${cssEscape(tabInfo.id)}"]`);
@@ -500,7 +508,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
500
508
  return this.#calculateScrollPositionLogic(tabs, selectedTabIndex, measures);
501
509
  }
502
510
 
503
- // remove after d2l-tab/d2l-tab-panel backport
511
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
504
512
  _calculateScrollPositionDefaultSlotBehavior(selectedTabInfo, measures) {
505
513
  const selectedTabIndex = this._tabInfos.indexOf(selectedTabInfo);
506
514
  return this.#calculateScrollPositionLogic(this._tabInfos, selectedTabIndex, measures);
@@ -520,7 +528,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
520
528
  selectedTab.focus();
521
529
  }
522
530
 
523
- // remove after d2l-tab/d2l-tab-panel backport
531
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
524
532
  async _focusSelectedDefaultSlotBehavior() {
525
533
  const selectedTab = this.shadowRoot && this.shadowRoot.querySelector('d2l-tab-internal[aria-selected="true"]');
526
534
  if (!selectedTab) return;
@@ -557,7 +565,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
557
565
  return this.#panels.find(panel => panel.labelledBy === id);
558
566
  }
559
567
 
560
- // remove after d2l-tab/d2l-tab-panel backport
568
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
561
569
  _getPanelDefaultSlotBehavior(id) {
562
570
  if (!this.shadowRoot) return;
563
571
  // use simple selector for slot (Edge)
@@ -570,17 +578,18 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
570
578
  }
571
579
  }
572
580
 
573
- // remove after d2l-tab/d2l-tab-panel backport
581
+ // rremove with GAUD-8299-core-tabs-use-new-structure flag clean up
574
582
  _getPanelsDefaultSlotBehavior(slot) {
575
583
  if (!slot) return;
576
584
  return slot.assignedElements({ flatten: true }).filter((node) => node.role === 'tabpanel');
577
585
  }
578
586
 
579
- // remove after d2l-tab/d2l-tab-panel backport
587
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
580
588
  _getTabInfo(id) {
581
589
  return this._tabInfos.find((t) => t.id === id);
582
590
  }
583
591
 
592
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
584
593
  async _handleDefaultSlotChange(e) {
585
594
  if (!this._defaultSlotBehavior) return;
586
595
 
@@ -669,7 +678,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
669
678
  this._resetFocusables();
670
679
  }
671
680
 
672
- // remove after d2l-tab/d2l-tab-panel backport
681
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
673
682
  _handlePanelSelected(e) {
674
683
  if (!this._defaultSlotBehavior) return;
675
684
 
@@ -690,7 +699,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
690
699
  this.#setAriaControls();
691
700
  }
692
701
 
693
- // remove after d2l-tab/d2l-tab-panel backport
702
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
694
703
  async _handlePanelTextChange(e) {
695
704
  const tabInfo = this._getTabInfo(e.target.id);
696
705
  // event could be from nested tabs
@@ -803,7 +812,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
803
812
  this._updateScrollPosition(selectedTab);
804
813
  }
805
814
 
806
- // remove after d2l-tab/d2l-tab-panel backport
815
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
807
816
  async _handleTabSelectedDefaultSlotBehavior(e) {
808
817
  e.stopPropagation();
809
818
 
@@ -940,7 +949,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
940
949
  tab.tabIndex = 0;
941
950
  }
942
951
 
943
- // remove after d2l-tab/d2l-tab-panel backport
952
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
944
953
  _setFocusableDefaultSlotBehavior(tabInfo) {
945
954
  const currentFocusable = this._tabInfos.find(ti => ti.activeFocusable);
946
955
  if (currentFocusable) currentFocusable.activeFocusable = false;
@@ -1023,7 +1032,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1023
1032
  return this.#updateScrollPositionLogic(measures, newTranslationValue);
1024
1033
  }
1025
1034
 
1026
- // remove after d2l-tab/d2l-tab-panel backport
1035
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1027
1036
  _updateScrollPositionDefaultSlotBehavior(selectedTabInfo) {
1028
1037
  const measures = this._getMeasures();
1029
1038
  const newTranslationValue = this._calculateScrollPositionDefaultSlotBehavior(selectedTabInfo, measures);
@@ -1050,13 +1059,26 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1050
1059
  return this.updateComplete;
1051
1060
  }
1052
1061
 
1053
- // Legacy structure clean up: if possible base this on visible tabs going forward
1054
- _updateTabListVisibility(panels) {
1055
- if (this._state === 'shown' && panels.length < 2) {
1062
+ _updateTabListVisibility(tabs) {
1063
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1064
+ if (!this.#newTabsPanelStructure) {
1065
+ if (this._state === 'shown' && tabs.length < 2) {
1066
+ this.#hideTabsList();
1067
+ } else if (this._state === 'hidden' && tabs.length > 1) {
1068
+ this.#showTabsList();
1069
+ } else if (this._state === 'shown' && tabs.length > 1) {
1070
+ // check if there are hidden tabs and tab list container should actually be hidden
1071
+ this.#handleTabHiddenChange();
1072
+ }
1073
+ return;
1074
+ }
1075
+
1076
+ const visibleCount = tabs.filter(tab => !tab.hidden).length;
1077
+ if (this._state === 'shown' && visibleCount < 2) {
1056
1078
  this.#hideTabsList();
1057
- } else if (this._state === 'hidden' && panels.length > 1) {
1079
+ } else if (this._state === 'hidden' && visibleCount > 1) {
1058
1080
  this.#showTabsList();
1059
- } else if (this._state === 'shown' && panels.length > 1) {
1081
+ } else if (this._state === 'shown' && visibleCount > 1) {
1060
1082
  // check if there are hidden tabs and tab list container should actually be hidden
1061
1083
  this.#handleTabHiddenChange();
1062
1084
  }
@@ -1069,7 +1091,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1069
1091
  return this.#updateTabsContainerWidthLogic();
1070
1092
  }
1071
1093
 
1072
- // remove after d2l-tab/d2l-tab-panel backport
1094
+ // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1073
1095
  _updateTabsContainerWidthDefaultSlotBehavior(selectedTabInfo) {
1074
1096
  if (!this.maxToShow || this.maxToShow <= 0 || this.maxToShow >= this._tabInfos.length) return;
1075
1097
  if (this._tabInfos.indexOf(selectedTabInfo) > this.maxToShow - 1) return;
@@ -1176,7 +1198,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1176
1198
 
1177
1199
  #handleTabDeselected(e) {
1178
1200
  const panel = this._getPanel(e.target.id);
1179
- if (panel) panel.selected = false;
1201
+ if (panel) {
1202
+ if (this.#newTabsPanelStructure) panel._selected = false;
1203
+ else panel.selected = false; // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1204
+ }
1180
1205
  }
1181
1206
 
1182
1207
  #handleTabHiddenChange() {
@@ -1264,14 +1289,20 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
1264
1289
  selectedTab.tabIndex = 0;
1265
1290
 
1266
1291
  const selectedPanel = this._getPanel(selectedTab.id);
1267
- if (selectedPanel) selectedPanel.selected = true;
1292
+ if (selectedPanel) {
1293
+ if (this.#newTabsPanelStructure) selectedPanel._selected = true;
1294
+ else selectedPanel.selected = true; // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1295
+ }
1268
1296
  this._tabs.forEach((tab) => {
1269
1297
  if (tab.id !== selectedTab.id) {
1270
1298
  if (tab.selected) {
1271
1299
  tab.selected = false;
1272
1300
  const panel = this._getPanel(tab.id);
1273
1301
  // panel may not exist if it's being removed
1274
- if (panel) panel.selected = false;
1302
+ if (panel) {
1303
+ if (this.#newTabsPanelStructure) panel._selected = false;
1304
+ else panel.selected = false; // remove with GAUD-8299-core-tabs-use-new-structure flag clean up
1305
+ }
1275
1306
  }
1276
1307
  if (tab.tabIndex === 0) tab.tabIndex = -1;
1277
1308
  }
@@ -12266,7 +12266,6 @@
12266
12266
  {
12267
12267
  "name": "d2l-page-demo",
12268
12268
  "path": "./components/page/demo/page-component.js",
12269
- "description": "Component for d2l-page demos and tests",
12270
12269
  "properties": [
12271
12270
  {
12272
12271
  "name": "properties",
@@ -12276,7 +12275,7 @@
12276
12275
  {
12277
12276
  "name": "styles",
12278
12277
  "type": "CSSResult[]",
12279
- "default": "[\"navStyles\",\"selectStyles\",\"tableStyles\",null]"
12278
+ "default": "[\"selectStyles\",\"tableStyles\",null]"
12280
12279
  },
12281
12280
  {
12282
12281
  "name": "demoMode",
@@ -12325,6 +12324,17 @@
12325
12324
  }
12326
12325
  ]
12327
12326
  },
12327
+ {
12328
+ "name": "d2l-page-header-full-demo",
12329
+ "path": "./components/page/demo/page-header-full.js",
12330
+ "properties": [
12331
+ {
12332
+ "name": "styles",
12333
+ "type": "CSSResult",
12334
+ "default": "\"css`\\n\\t\\t.full-nav-header {\\n\\t\\t\\talign-items: center;\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\theight: 90px;\\n\\t\\t}\\n\\t\\t.full-nav-header-left {\\n\\t\\t\\talign-items: center;\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\tflex: 0 1 auto;\\n\\t\\t\\tgap: 5px;\\n\\t\\t\\theight: 100%;\\n\\t\\t}\\n\\t\\t.full-nav-header-spacer {\\n\\t\\t\\tflex: 1 1 auto;\\n\\t\\t\\tmin-width: 30px;\\n\\t\\t}\\n\\t\\t.full-nav-header-right {\\n\\t\\t\\talign-items: center;\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\tflex: 0 0 auto;\\n\\t\\t\\theight: 100%;\\n\\t\\t}\\n\\t\\t.full-nav-header-right d2l-page-header-button {\\n\\t\\t\\tmargin-inline: 15px;\\n\\t\\t}\\n\\t\\t.full-nav-logo {\\n\\t\\t\\tbackground-color: var(--d2l-color-celestine);\\n\\t\\t\\tborder-radius: 4px;\\n\\t\\t\\tcolor: white;\\n\\t\\t\\tfont-size: 0.8rem;\\n\\t\\t\\tfont-weight: 700;\\n\\t\\t\\tpadding: 8px 14px;\\n\\t\\t}\\n\\t\\t.full-nav-footer-inner {\\n\\t\\t\\talign-items: center;\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\tflex-wrap: wrap;\\n\\t\\t\\tgap: 20px;\\n\\t\\t}\\n\\t\\t.full-nav-footer-link {\\n\\t\\t\\tborder-bottom: 4px solid transparent;\\n\\t\\t\\tcolor: var(--d2l-color-ferrite);\\n\\t\\t\\tdisplay: inline-block;\\n\\t\\t\\tpadding: 8px 0;\\n\\t\\t\\ttext-decoration: none;\\n\\t\\t}\\n\\t\\t.full-nav-footer-link:hover,\\n\\t\\t.full-nav-footer-link:focus-visible {\\n\\t\\t\\tborder-bottom-color: var(--d2l-color-celestine);\\n\\t\\t\\tcolor: var(--d2l-color-celestine);\\n\\t\\t}\\n\\t`\""
12335
+ }
12336
+ ]
12337
+ },
12328
12338
  {
12329
12339
  "name": "d2l-page-footer",
12330
12340
  "path": "./components/page/page-footer.js",
@@ -12469,6 +12479,55 @@
12469
12479
  }
12470
12480
  ]
12471
12481
  },
12482
+ {
12483
+ "name": "d2l-page-header-immersive",
12484
+ "path": "./components/page/page-header-immersive.js",
12485
+ "attributes": [
12486
+ {
12487
+ "name": "back-href",
12488
+ "type": "string"
12489
+ },
12490
+ {
12491
+ "name": "back-custom-text",
12492
+ "type": "string"
12493
+ },
12494
+ {
12495
+ "name": "title-text",
12496
+ "type": "string"
12497
+ },
12498
+ {
12499
+ "name": "subtitle-text",
12500
+ "type": "string"
12501
+ }
12502
+ ],
12503
+ "properties": [
12504
+ {
12505
+ "name": "backHref",
12506
+ "attribute": "back-href",
12507
+ "type": "string"
12508
+ },
12509
+ {
12510
+ "name": "backCustomText",
12511
+ "attribute": "back-custom-text",
12512
+ "type": "string"
12513
+ },
12514
+ {
12515
+ "name": "titleText",
12516
+ "attribute": "title-text",
12517
+ "type": "string"
12518
+ },
12519
+ {
12520
+ "name": "subtitleText",
12521
+ "attribute": "subtitle-text",
12522
+ "type": "string"
12523
+ }
12524
+ ],
12525
+ "events": [
12526
+ {
12527
+ "name": "d2l-page-header-immersive-back-click"
12528
+ }
12529
+ ]
12530
+ },
12472
12531
  {
12473
12532
  "name": "d2l-page-header-separator",
12474
12533
  "path": "./components/page/page-header-separator.js",
@@ -15331,9 +15390,14 @@
15331
15390
  "description": "REQUIRED: Id of the tab that labels this panel",
15332
15391
  "type": "string"
15333
15392
  },
15393
+ {
15394
+ "name": "selected",
15395
+ "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.",
15396
+ "type": "boolean"
15397
+ },
15334
15398
  {
15335
15399
  "name": "text",
15336
- "description": "DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation.",
15400
+ "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.",
15337
15401
  "type": "string"
15338
15402
  },
15339
15403
  {
@@ -15341,12 +15405,6 @@
15341
15405
  "description": "Opt out of default padding/whitespace around the panel",
15342
15406
  "type": "boolean",
15343
15407
  "default": "false"
15344
- },
15345
- {
15346
- "name": "selected",
15347
- "description": "DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation.",
15348
- "type": "boolean",
15349
- "default": "false"
15350
15408
  }
15351
15409
  ],
15352
15410
  "properties": [
@@ -15356,10 +15414,16 @@
15356
15414
  "description": "REQUIRED: Id of the tab that labels this panel",
15357
15415
  "type": "string"
15358
15416
  },
15417
+ {
15418
+ "name": "selected",
15419
+ "attribute": "selected",
15420
+ "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.",
15421
+ "type": "boolean"
15422
+ },
15359
15423
  {
15360
15424
  "name": "text",
15361
15425
  "attribute": "text",
15362
- "description": "DEPRECATED: The text used for the tab, as well as labelling the panel. Required if not using d2l-tab/d2l-tab-panel implementation.",
15426
+ "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.",
15363
15427
  "type": "string"
15364
15428
  },
15365
15429
  {
@@ -15368,13 +15432,6 @@
15368
15432
  "description": "Opt out of default padding/whitespace around the panel",
15369
15433
  "type": "boolean",
15370
15434
  "default": "false"
15371
- },
15372
- {
15373
- "name": "selected",
15374
- "attribute": "selected",
15375
- "description": "DEPRECATED: Use to select the tab. Do NOT set if using the d2l-tab/d2l-tab-panel implementation.",
15376
- "type": "boolean",
15377
- "default": "false"
15378
15435
  }
15379
15436
  ],
15380
15437
  "events": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.248.1",
3
+ "version": "3.250.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",
@@ -66,7 +66,7 @@
66
66
  "rollup-plugin-copy": "^3",
67
67
  "rollup-plugin-delete": "^3",
68
68
  "sass": "^1",
69
- "sinon": "^21",
69
+ "sinon": "^22",
70
70
  "stylelint": "^17",
71
71
  "web-component-analyzer": "^2"
72
72
  },