@brightspace-ui/core 3.91.0 → 3.93.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.
@@ -1,14 +1,9 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
-
4
3
  <head>
5
4
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
6
5
  <meta charset="UTF-8">
7
6
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
8
- <script>
9
- const urlParams = new URLSearchParams(window.location.search);
10
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: () => (urlParams.get('position') === 'fixed') } } } } };
11
- </script>
12
7
  <script type="module">
13
8
  import '../../demo/demo-page.js';
14
9
  import '../../button/button.js';
@@ -19,19 +14,18 @@
19
14
  import '../../table/demo/table-test.js';
20
15
  </script>
21
16
  </head>
22
-
23
17
  <body unresolved>
24
18
 
25
- <d2l-demo-page page-title="d2l-dropdown">
19
+ <d2l-demo-page page-title="d2l-dropdown (positioning)">
26
20
 
27
21
  <h2>Dropdown (in a scrollable container)</h2>
28
22
  <d2l-demo-snippet>
29
23
  <template>
30
24
  <div style="height: 250px; overflow: scroll;">
31
25
  <p>Gabion warp American Main gunwalls cutlass gally cable gibbet jib keel. Trysail chantey swing the lead hempen halter hang the jib chase Jack Tar furl galleon scurvy. Brig splice the main brace provost pink rutters tender heave to Shiver me timbers belaying pin Brethren of the Coast.</p>
32
- <d2l-dropdown prefer-fixed-positioning>
26
+ <d2l-dropdown>
33
27
  <d2l-button class="d2l-dropdown-opener">Open it!</d2l-button>
34
- <d2l-dropdown-content max-width="400" prefer-fixed-positioning>
28
+ <d2l-dropdown-content max-width="400">
35
29
  <a href="https://youtu.be/9ze87zQFSak">Google</a>
36
30
  <p>Shrouds hulk ye run a rig pink wherry hornswaggle overhaul spike splice the main brace. Barbary Coast salmagundi Nelsons folly lanyard Sea Legs topgallant Sink me crow's nest scuttle red ensign. Handsomely swab wench hang the jib square-rigged scuppers spyglass holystone Yellow Jack splice the main brace.</p>
37
31
  <a href="http://www.desire2learn.com">D2L</a>
@@ -56,13 +50,13 @@
56
50
 
57
51
  <d2l-demo-snippet>
58
52
  <template>
59
- <d2l-dropdown prefer-fixed-positioning>
53
+ <d2l-dropdown>
60
54
  <d2l-button class="d2l-dropdown-opener">Open it!</d2l-button>
61
- <d2l-dropdown-content max-width="400" prefer-fixed-positioning>
55
+ <d2l-dropdown-content max-width="400">
62
56
  <p>Shrouds hulk ye run a rig pink wherry hornswaggle overhaul spike splice the main brace. Barbary Coast salmagundi Nelsons folly lanyard Sea Legs topgallant Sink me crow's nest scuttle red ensign.</p>
63
- <d2l-dropdown prefer-fixed-positioning>
57
+ <d2l-dropdown>
64
58
  <d2l-button-subtle class="d2l-dropdown-opener">Open Nested!</d2l-button-subtle>
65
- <d2l-dropdown-content max-width="600" align="start" prefer-fixed-positioning>
59
+ <d2l-dropdown-content max-width="600" align="start">
66
60
  <a href="https://youtu.be/9ze87zQFSak">Google</a>
67
61
  <p>Shrouds hulk ye run a rig pink wherry hornswaggle overhaul spike splice the main brace. Barbary Coast salmagundi Nelsons folly lanyard Sea Legs topgallant Sink me crow's nest scuttle red ensign. Handsomely swab wench hang the jib square-rigged scuppers spyglass holystone Yellow Jack splice the main brace.</p>
68
62
  <a href="http://www.desire2learn.com">D2L</a>
@@ -82,9 +76,9 @@
82
76
  <d2l-dialog id="dialog1" title-text="Dialog Title">
83
77
  <div>
84
78
  <p>Bilge tack furl dance the hempen jig fathom weigh anchor mizzen Blimey Jack Ketch flogging. Lee galleon avast schooner long clothes scuppers pinnace bucko deadlights gibbet. Nipper brigantine Buccaneer Gold Road matey gangway booty tender killick Brethren of the Coast.</p>
85
- <d2l-dropdown prefer-fixed-positioning>
79
+ <d2l-dropdown>
86
80
  <d2l-button class="d2l-dropdown-opener">Open it!</d2l-button>
87
- <d2l-dropdown-content max-width="400" prefer-fixed-positioning>
81
+ <d2l-dropdown-content max-width="400">
88
82
  <a href="https://youtu.be/9ze87zQFSak">Google</a>
89
83
  <p>Shrouds hulk ye run a rig pink wherry hornswaggle overhaul spike splice the main brace. Barbary Coast salmagundi Nelsons folly lanyard Sea Legs topgallant Sink me crow's nest scuttle red ensign. Handsomely swab wench hang the jib square-rigged scuppers spyglass holystone Yellow Jack splice the main brace.</p>
90
84
  <a href="http://www.desire2learn.com">D2L</a>
@@ -111,9 +105,9 @@
111
105
  <template>
112
106
  <div>
113
107
  <div id="mutations-above"></div>
114
- <d2l-dropdown prefer-fixed-positioning>
108
+ <d2l-dropdown>
115
109
  <d2l-button class="d2l-dropdown-opener">Open it!</d2l-button>
116
- <d2l-dropdown-content max-width="400" prefer-fixed-positioning>
110
+ <d2l-dropdown-content max-width="400">
117
111
  <d2l-button-subtle id="mutations-add-above">Add to Above</d2l-button-subtle>
118
112
  </d2l-dropdown-content>
119
113
  </d2l-dropdown>
@@ -129,9 +123,5 @@
129
123
  </template>
130
124
  </d2l-demo-snippet>
131
125
 
132
- <script>
133
- document.querySelector('d2l-demo-page').pageTitle = `d2l-dropdown (${ window.D2L.LP.Web.UI.Flags.Flag('GAUD-131-dropdown-fixed-positioning', false) ? 'fixed' : 'relative' })`;
134
- </script>
135
126
  </body>
136
-
137
127
  </html>
@@ -189,14 +189,6 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
189
189
  reflect: true,
190
190
  attribute: 'opened-above'
191
191
  },
192
- /**
193
- * Temporary.
194
- * @ignore
195
- */
196
- preferFixedPositioning: {
197
- type: Boolean,
198
- attribute: 'prefer-fixed-positioning'
199
- },
200
192
  /**
201
193
  * Optionally render a d2l-focus-trap around the dropdown content
202
194
  * @type {boolean}
@@ -225,11 +217,6 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
225
217
  attribute: 'dropdown-content',
226
218
  reflect: true
227
219
  },
228
- _fixedPositioning: {
229
- type: Boolean,
230
- attribute: '_fixed-positioning',
231
- reflect: true
232
- },
233
220
  _useMobileStyling: {
234
221
  type: Boolean,
235
222
  attribute: 'data-mobile',
@@ -370,12 +357,6 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
370
357
  });
371
358
  }
372
359
 
373
- willUpdate(changedProperties) {
374
- if (this._fixedPositioning === undefined || changedProperties.has('preferFixedPositioning')) {
375
- this._fixedPositioning = (window.D2L?.LP?.Web?.UI?.Flags.Flag('GAUD-131-dropdown-fixed-positioning', false) && this.preferFixedPositioning);
376
- }
377
- }
378
-
379
360
  close() {
380
361
  const hide = () => {
381
362
  this._closing = false;
@@ -460,7 +441,6 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
460
441
  }
461
442
 
462
443
  __addRepositionHandlers() {
463
- if (!this._fixedPositioning) return;
464
444
 
465
445
  const isScrollable = (node, prop) => {
466
446
  const value = window.getComputedStyle(node, null).getPropertyValue(prop);
@@ -722,16 +702,11 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
722
702
  /* don't let dropdown content horizontally overflow viewport */
723
703
  this._width = null;
724
704
 
725
- const openerPosition = window.getComputedStyle(opener, null).getPropertyValue('position'); // todo: cleanup when switched to fixed positioning
726
705
  const boundingContainer = getBoundingAncestor(target.parentNode);
727
- const boundingContainerRect = boundingContainer.getBoundingClientRect(); // todo: cleanup when switched to fixed positioning
728
706
  const scrollHeight = boundingContainer.scrollHeight;
729
707
 
730
708
  await this.updateComplete;
731
709
 
732
- // position check in case consuming app (LMS) has overriden position to make content absolute wrt document
733
- const bounded = (!this._fixedPositioning && openerPosition === 'relative' && boundingContainer !== document.documentElement);
734
-
735
710
  const adjustPosition = async() => {
736
711
 
737
712
  const targetRect = target.getBoundingClientRect();
@@ -745,45 +720,21 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
745
720
  width: contentRect.width
746
721
  };
747
722
 
748
- let spaceAround;
749
- let spaceAroundScroll;
750
- if (bounded) {
751
-
752
- spaceAround = this._constrainSpaceAround({
753
- // allow for target offset + outer margin
754
- above: targetRect.top - boundingContainerRect.top - this._verticalOffset - outerMarginTopBottom,
755
- // allow for target offset + outer margin
756
- below: boundingContainerRect.bottom - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
757
- // allow for outer margin
758
- left: targetRect.left - boundingContainerRect.left - 20,
759
- // allow for outer margin
760
- right: boundingContainerRect.right - targetRect.right - 20
761
- }, spaceRequired, targetRect);
762
-
763
- spaceAroundScroll = this._constrainSpaceAround({
764
- above: targetRect.top - boundingContainerRect.top + boundingContainer.scrollTop,
765
- below: scrollHeight - targetRect.bottom + boundingContainerRect.top - boundingContainer.scrollTop
766
- }, spaceRequired, targetRect);
767
-
768
- } else {
769
-
770
- spaceAround = this._constrainSpaceAround({
771
- // allow for target offset + outer margin
772
- above: targetRect.top - this._verticalOffset - outerMarginTopBottom,
773
- // allow for target offset + outer margin
774
- below: window.innerHeight - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
775
- // allow for outer margin
776
- left: targetRect.left - 20,
777
- // allow for outer margin
778
- right: document.documentElement.clientWidth - targetRect.right - 15
779
- }, spaceRequired, targetRect);
780
-
781
- spaceAroundScroll = this._constrainSpaceAround({
782
- above: targetRect.top + document.documentElement.scrollTop,
783
- below: scrollHeight - targetRect.bottom - document.documentElement.scrollTop
784
- }, spaceRequired, targetRect);
785
-
786
- }
723
+ const spaceAround = this._constrainSpaceAround({
724
+ // allow for target offset + outer margin
725
+ above: targetRect.top - this._verticalOffset - outerMarginTopBottom,
726
+ // allow for target offset + outer margin
727
+ below: window.innerHeight - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
728
+ // allow for outer margin
729
+ left: targetRect.left - 20,
730
+ // allow for outer margin
731
+ right: document.documentElement.clientWidth - targetRect.right - 15
732
+ }, spaceRequired, targetRect);
733
+
734
+ const spaceAroundScroll = this._constrainSpaceAround({
735
+ above: targetRect.top + document.documentElement.scrollTop,
736
+ below: scrollHeight - targetRect.bottom - document.documentElement.scrollTop
737
+ }, spaceRequired, targetRect);
787
738
 
788
739
  if (options.updateAboveBelow) {
789
740
  this.openedAbove = this._getOpenedAbove(spaceAround, spaceAroundScroll, spaceRequired);
@@ -813,7 +764,7 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
813
764
  };
814
765
 
815
766
  const scrollWidth = Math.max(header.scrollWidth, content.scrollWidth, footer.scrollWidth);
816
- const availableWidth = (bounded ? boundingContainerRect.width - 60 : window.innerWidth - 40);
767
+ const availableWidth = window.innerWidth - 40;
817
768
  this._width = (availableWidth > scrollWidth ? scrollWidth : availableWidth) ;
818
769
 
819
770
  await this.updateComplete;
@@ -822,8 +773,6 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
822
773
  }
823
774
 
824
775
  __removeRepositionHandlers() {
825
- if (!this._fixedPositioning) return;
826
-
827
776
  this._scrollablesObserved?.forEach(node => {
828
777
  node.removeEventListener('scroll', this.__reposition);
829
778
  });
@@ -1112,7 +1061,6 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
1112
1061
 
1113
1062
  _getPointerPosition(targetRect) {
1114
1063
  const position = {};
1115
- if (!this._fixedPositioning) return position;
1116
1064
 
1117
1065
  const pointer = this.__getPointer();
1118
1066
  if (!pointer) return position;
@@ -1146,28 +1094,20 @@ export const DropdownContentMixin = superclass => class extends LocalizeCoreElem
1146
1094
  const position = {};
1147
1095
  const isRTL = this.getAttribute('dir') === 'rtl';
1148
1096
  const positionXAdjustment = this._getPositionXAdjustment(spaceAround, targetRect, contentRect);
1149
- if (this._fixedPositioning) {
1150
- if (positionXAdjustment !== null) {
1151
- if (!isRTL) {
1152
- position.left = targetRect.left + positionXAdjustment;
1153
- } else {
1154
- position.right = window.innerWidth - targetRect.left - targetRect.width + positionXAdjustment;
1155
- }
1156
- }
1157
- if (this.openedAbove) {
1158
- position.bottom = window.innerHeight - targetRect.top + this._verticalOffset;
1097
+
1098
+ if (positionXAdjustment !== null) {
1099
+ if (!isRTL) {
1100
+ position.left = targetRect.left + positionXAdjustment;
1159
1101
  } else {
1160
- position.top = targetRect.top + targetRect.height + this._verticalOffset;
1102
+ position.right = window.innerWidth - targetRect.left - targetRect.width + positionXAdjustment;
1161
1103
  }
1104
+ }
1105
+ if (this.openedAbove) {
1106
+ position.bottom = window.innerHeight - targetRect.top + this._verticalOffset;
1162
1107
  } else {
1163
- if (positionXAdjustment !== null) {
1164
- if (!isRTL) {
1165
- position.left = positionXAdjustment;
1166
- } else {
1167
- position.right = positionXAdjustment;
1168
- }
1169
- }
1108
+ position.top = targetRect.top + targetRect.height + this._verticalOffset;
1170
1109
  }
1110
+
1171
1111
  return position;
1172
1112
  }
1173
1113
 
@@ -3,7 +3,6 @@ import { _offscreenStyleDeclarations } from '../offscreen/offscreen.js';
3
3
  import { css } from 'lit';
4
4
 
5
5
  const pointerLength = 16;
6
- const pointerRotatedLength = Math.SQRT2 * parseFloat(pointerLength);
7
6
 
8
7
  export const dropdownContentStyles = css`
9
8
 
@@ -18,16 +17,12 @@ export const dropdownContentStyles = css`
18
17
  color: var(--d2l-dropdown-foreground-color);
19
18
  display: none;
20
19
  left: 0;
21
- position: absolute;
20
+ position: fixed;
22
21
  text-align: left;
23
- top: calc(100% + var(--d2l-dropdown-verticaloffset, 16px));
22
+ top: 0;
24
23
  width: 100%;
25
24
  z-index: 998; /* position on top of floating buttons */
26
25
  }
27
- :host([_fixed-positioning]) {
28
- position: fixed;
29
- top: 0;
30
- }
31
26
 
32
27
  :host([theme="dark"]) {
33
28
  --d2l-dropdown-above-animation-name: d2l-dropdown-above-animation-dark;
@@ -46,7 +41,7 @@ export const dropdownContentStyles = css`
46
41
 
47
42
  :host([opened-above]) {
48
43
  animation: var(--d2l-dropdown-above-animation-name) 300ms ease;
49
- bottom: calc(100% + var(--d2l-dropdown-verticaloffset, 16px));
44
+ bottom: 0;
50
45
  top: auto;
51
46
  }
52
47
 
@@ -57,39 +52,16 @@ export const dropdownContentStyles = css`
57
52
 
58
53
  :host([data-mobile][opened-above]:not([mobile-tray])) {
59
54
  animation: var(--d2l-dropdown-above-animation-name) 300ms ease;
60
- bottom: calc(100% + var(--d2l-dropdown-verticaloffset, 16px));
61
- top: auto;
62
- }
63
-
64
- :host([_fixed-positioning][opened-above]),
65
- :host([_fixed-positioning][data-mobile][opened-above]:not([mobile-tray])) {
66
55
  bottom: 0;
56
+ top: auto;
67
57
  }
68
58
 
69
59
  .d2l-dropdown-content-pointer {
70
60
  clip: rect(-5px, 21px, 8px, -7px);
71
61
  display: inline-block;
72
- left: calc(50% - 7px); /* todo: cleanup when switched to fixed positioning */
73
62
  position: absolute;
74
- top: -7px; /* todo: cleanup when switched to fixed positioning */
75
63
  z-index: 1;
76
64
  }
77
- :host([_fixed-positioning][dir="rtl"]) .d2l-dropdown-content-pointer {
78
- left: auto;
79
- }
80
-
81
- :host([align="start"]) .d2l-dropdown-content-pointer,
82
- :host([align="end"][dir="rtl"]) .d2l-dropdown-content-pointer {
83
- /* todo: cleanup when switched to fixed positioning */
84
- left: min(calc(1rem + ${(pointerRotatedLength - pointerLength) / 2}px), calc(50% - ${pointerLength / 2}px)); /* 1rem corresponds to .d2l-dropdown-content-container padding */
85
- right: auto;
86
- }
87
- :host([align="end"]) .d2l-dropdown-content-pointer,
88
- :host([align="start"][dir="rtl"]) .d2l-dropdown-content-pointer {
89
- /* todo: cleanup when switched to fixed positioning */
90
- left: auto;
91
- right: min(calc(1rem + ${(pointerRotatedLength - pointerLength) / 2}px), calc(50% - ${pointerLength / 2}px)); /* 1rem corresponds to .d2l-dropdown-content-container padding */
92
- }
93
65
 
94
66
  .d2l-dropdown-content-pointer > div {
95
67
  background-color: var(--d2l-dropdown-background-color);
@@ -103,13 +75,10 @@ export const dropdownContentStyles = css`
103
75
  }
104
76
 
105
77
  :host([opened-above]) .d2l-dropdown-content-pointer {
106
- bottom: -8px;
78
+ bottom: auto;
107
79
  clip: rect(9px, 21px, 22px, -3px);
108
80
  top: auto;
109
81
  }
110
- :host([_fixed-positioning][opened-above]) .d2l-dropdown-content-pointer {
111
- bottom: auto;
112
- }
113
82
 
114
83
  :host([opened-above]) .d2l-dropdown-content-pointer > div {
115
84
  box-shadow: 4px 4px 12px -5px rgba(32, 33, 34, 0.2); /* ferrite */
@@ -51,19 +51,6 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
51
51
  type: Boolean,
52
52
  attribute: 'open-on-hover'
53
53
  },
54
- /**
55
- * Temporary.
56
- * @ignore
57
- */
58
- preferFixedPositioning: {
59
- type: Boolean,
60
- attribute: 'prefer-fixed-positioning'
61
- },
62
- _fixedPositioning: {
63
- type: Boolean,
64
- attribute: '_fixed-positioning',
65
- reflect: true,
66
- },
67
54
  _isHovering: { type: Boolean },
68
55
  _isOpenedViaClick: { type: Boolean },
69
56
  _isFading: { type: Boolean }
@@ -98,7 +85,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
98
85
  this.addEventListener('mouseenter', this.__onMouseEnter);
99
86
  this.addEventListener('mouseleave', this.__onMouseLeave);
100
87
 
101
- if (this._fixedPositioning && this.dropdownOpened) {
88
+ if (this.dropdownOpened) {
102
89
  intersectionObserver.observe(this);
103
90
  }
104
91
  if (this.openOnHover) {
@@ -114,9 +101,8 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
114
101
  this.removeEventListener('mouseenter', this.__onMouseEnter);
115
102
  this.removeEventListener('mouseleave', this.__onMouseLeave);
116
103
 
117
- if (this._fixedPositioning) {
118
- intersectionObserver.unobserve(this);
119
- }
104
+ intersectionObserver.unobserve(this);
105
+
120
106
  if (this.openOnHover) {
121
107
  document.body.removeEventListener('mouseup', this._onOutsideClick);
122
108
  }
@@ -148,12 +134,6 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
148
134
  }
149
135
  }
150
136
 
151
- willUpdate(changedProperties) {
152
- if (this._fixedPositioning === undefined || changedProperties.has('preferFixedPositioning')) {
153
- this._fixedPositioning = (window.D2L?.LP?.Web?.UI?.Flags.Flag('GAUD-131-dropdown-fixed-positioning', false) && this.preferFixedPositioning);
154
- }
155
- }
156
-
157
137
  /* used by open-on-hover option */
158
138
  async closeDropdown(fadeOut) {
159
139
  this.dropdownOpened = false;
@@ -219,9 +199,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
219
199
  }
220
200
 
221
201
  __onClosed() {
222
- if (this._fixedPositioning) {
223
- intersectionObserver.unobserve(this);
224
- }
202
+ intersectionObserver.unobserve(this);
225
203
 
226
204
  const opener = this.getOpenerElement();
227
205
  if (!opener) {
@@ -303,9 +281,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
303
281
  opener.setAttribute('active', 'true');
304
282
  this._isFading = false;
305
283
 
306
- if (this._fixedPositioning) {
307
- intersectionObserver.observe(this);
308
- }
284
+ intersectionObserver.observe(this);
309
285
  }
310
286
 
311
287
  __onOpenerMouseUp(e) {
@@ -5,9 +5,6 @@ export const dropdownOpenerStyles = css`
5
5
  display: inline-block;
6
6
  outline: none;
7
7
  overflow: visible;
8
- position: relative;
9
- }
10
- :host([_fixed-positioning]) {
11
8
  position: static;
12
9
  }
13
10
  :host([hidden]) {
@@ -15,9 +15,6 @@
15
15
  import './filter-search-demo.js';
16
16
  import './filter-load-more-demo.js';
17
17
  </script>
18
- <script>
19
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: () => true } } } } }; // TODO: remove with GAUD-131-dropdown-fixed-positioning flag clean up
20
- </script>
21
18
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1.0">
22
19
  <meta charset="UTF-8">
23
20
  </head>
@@ -144,7 +144,6 @@ class FilterDimensionSetDateTimeRangeValue extends LocalizeCoreElement(LitElemen
144
144
  inclusive-date-range
145
145
  label="${this.localize('components.filter-dimension-set-date-time-range-value.text')}"
146
146
  label-hidden
147
- prefer-fixed-positioning
148
147
  start-value="${ifDefined(this.startValue ? getLocalDateTimeFromUTCDateTime(this.startValue) : undefined)}"
149
148
  ></d2l-input-date-range>`
150
149
  : html`<d2l-input-date-time-range
@@ -153,7 +152,6 @@ class FilterDimensionSetDateTimeRangeValue extends LocalizeCoreElement(LitElemen
153
152
  end-value="${ifDefined(this.endValue)}"
154
153
  label="${this.localize('components.filter-dimension-set-date-time-range-value.text')}"
155
154
  label-hidden
156
- prefer-fixed-positioning
157
155
  start-value="${ifDefined(this.startValue)}"
158
156
  ></d2l-input-date-time-range>
159
157
  `;
@@ -219,7 +219,6 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
219
219
  /* Needed to "undo" the menu-item style for multiple dimensions */
220
220
  d2l-hierarchical-view {
221
221
  cursor: auto;
222
- overflow: auto; /* remove with GAUD-131-dropdown-fixed-positioning flag clean up */
223
222
  }
224
223
 
225
224
  d2l-loading-spinner {
@@ -287,7 +286,6 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
287
286
  no-padding-header
288
287
  no-padding
289
288
  ?opened="${this.opened}"
290
- prefer-fixed-positioning
291
289
  ?trap-focus="${!this._isDimensionEmpty(this._dimensions[0])}">
292
290
  ${header}
293
291
  ${dimensions}
@@ -301,7 +299,6 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
301
299
  mobile-breakpoint="768"
302
300
  no-padding-header
303
301
  ?opened="${this.opened}"
304
- prefer-fixed-positioning
305
302
  trap-focus>
306
303
  ${header}
307
304
  <d2l-menu label="${this.localize('components.filter.filters')}">
@@ -326,8 +323,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
326
323
  @d2l-dropdown-open="${this._handleDropdownOpen}"
327
324
  @d2l-dropdown-position="${this._stopPropagation}"
328
325
  class="vdiff-target"
329
- ?disabled="${this.disabled}"
330
- prefer-fixed-positioning>
326
+ ?disabled="${this.disabled}">
331
327
  <d2l-button-subtle
332
328
  class="d2l-dropdown-opener"
333
329
  description="${description}"
@@ -93,11 +93,6 @@ class InputDateRange extends InteractiveMixin(FocusMixin(SkeletonMixin(FormEleme
93
93
  * @type {string}
94
94
  */
95
95
  minValue: { attribute: 'min-value', reflect: true, type: String },
96
- /**
97
- * Temporary.
98
- * @ignore
99
- */
100
- preferFixedPositioning: { type: Boolean, attribute: 'prefer-fixed-positioning' },
101
96
  /**
102
97
  * Indicates that values are required
103
98
  * @type {boolean}
@@ -203,7 +198,6 @@ class InputDateRange extends InteractiveMixin(FocusMixin(SkeletonMixin(FormEleme
203
198
  max-value="${ifDefined(this.maxValue)}"
204
199
  min-value="${ifDefined(this.minValue)}"
205
200
  ?opened="${this.startOpened}"
206
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
207
201
  ?required="${this.required}"
208
202
  ?skeleton="${this.skeleton}"
209
203
  slot="left"
@@ -222,7 +216,6 @@ class InputDateRange extends InteractiveMixin(FocusMixin(SkeletonMixin(FormEleme
222
216
  max-value="${ifDefined(this.maxValue)}"
223
217
  min-value="${ifDefined(this.minValue)}"
224
218
  ?opened="${this.endOpened}"
225
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
226
219
  ?required="${this.required}"
227
220
  ?skeleton="${this.skeleton}"
228
221
  slot="right"
@@ -131,11 +131,6 @@ class InputDateTimeRange extends InteractiveMixin(FocusMixin(SkeletonMixin(FormE
131
131
  * @type {string}
132
132
  */
133
133
  minValue: { attribute: 'min-value', reflect: true, type: String },
134
- /**
135
- * Temporary.
136
- * @ignore
137
- */
138
- preferFixedPositioning: { type: Boolean, attribute: 'prefer-fixed-positioning' },
139
134
  /**
140
135
  * Indicates that values are required
141
136
  * @type {boolean}
@@ -254,7 +249,6 @@ class InputDateTimeRange extends InteractiveMixin(FocusMixin(SkeletonMixin(FormE
254
249
  max-value="${ifDefined(this.maxValue)}"
255
250
  min-value="${ifDefined(this.minValue)}"
256
251
  ?opened="${this.startOpened}"
257
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
258
252
  ?required="${this.required}"
259
253
  ?skeleton="${this.skeleton}"
260
254
  time-default-value="startOfDay"
@@ -277,7 +271,6 @@ class InputDateTimeRange extends InteractiveMixin(FocusMixin(SkeletonMixin(FormE
277
271
  max-value="${ifDefined(this.maxValue)}"
278
272
  min-value="${ifDefined(this.minValue)}"
279
273
  ?opened="${this.endOpened}"
280
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
281
274
  ?required="${this.required}"
282
275
  ?skeleton="${this.skeleton}"
283
276
  time-default-value="endOfDay"
@@ -76,11 +76,6 @@ class InputDateTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMi
76
76
  * @type {boolean}
77
77
  */
78
78
  opened: { type: Boolean },
79
- /**
80
- * Temporary.
81
- * @ignore
82
- */
83
- preferFixedPositioning: { type: Boolean, attribute: 'prefer-fixed-positioning' },
84
79
  /**
85
80
  * Indicates that a value is required
86
81
  * @type {boolean}
@@ -253,7 +248,6 @@ class InputDateTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMi
253
248
  label-hidden
254
249
  .labelRequired="${false}"
255
250
  max-height="430"
256
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
257
251
  ?required="${this.required}"
258
252
  ?skeleton="${this.skeleton}"
259
253
  .value="${parsedValue}">
@@ -283,7 +277,6 @@ class InputDateTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMi
283
277
  max-value="${ifDefined(this._maxValueLocalized)}"
284
278
  min-value="${ifDefined(this._minValueLocalized)}"
285
279
  ?opened="${dateOpened}"
286
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
287
280
  ?required="${this.required}"
288
281
  ?skeleton="${this.skeleton}"
289
282
  style="${styleMap(dateStyle)}"
@@ -68,11 +68,6 @@ class InputDate extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
68
68
  * @type {boolean}
69
69
  */
70
70
  opened: { type: Boolean, reflect: true },
71
- /**
72
- * Temporary.
73
- * @ignore
74
- */
75
- preferFixedPositioning: { type: Boolean, attribute: 'prefer-fixed-positioning' },
76
71
  /**
77
72
  * Indicates that a value is required
78
73
  * @type {boolean}
@@ -264,8 +259,7 @@ class InputDate extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
264
259
  trap-focus
265
260
  no-auto-focus
266
261
  mobile-tray="bottom"
267
- no-padding
268
- ?prefer-fixed-positioning="${this.preferFixedPositioning}">
262
+ no-padding>
269
263
  <d2l-calendar
270
264
  @d2l-calendar-selected="${this._handleDateSelected}"
271
265
  label="${ifDefined(this.label)}"
@@ -285,7 +279,7 @@ class InputDate extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
285
279
  <div>${shortDateFormat}</div>
286
280
  </div>
287
281
  ${tooltip}
288
- <d2l-dropdown ?disabled="${this.disabled || this.skeleton}" no-auto-open ?prefer-fixed-positioning="${this.preferFixedPositioning}">
282
+ <d2l-dropdown ?disabled="${this.disabled || this.skeleton}" no-auto-open>
289
283
  <d2l-input-text
290
284
  ?novalidate="${this.noValidate}"
291
285
  aria-invalid="${this.invalid ? 'true' : 'false'}"
@@ -95,11 +95,6 @@ class InputTimeRange extends FocusMixin(SkeletonMixin(FormElementMixin(RtlMixin(
95
95
  * @type {boolean}
96
96
  */
97
97
  labelHidden: { attribute: 'label-hidden', reflect: true, type: Boolean },
98
- /**
99
- * Temporary.
100
- * @ignore
101
- */
102
- preferFixedPositioning: { type: Boolean, attribute: 'prefer-fixed-positioning' },
103
98
  /**
104
99
  * Indicates that values are required
105
100
  * @type {boolean}
@@ -253,7 +248,6 @@ class InputTimeRange extends FocusMixin(SkeletonMixin(FormElementMixin(RtlMixin(
253
248
  label="${startLabel}"
254
249
  ?label-hidden="${this.childLabelsHidden}"
255
250
  ?opened="${this.startOpened}"
256
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
257
251
  ?required="${this.required}"
258
252
  ?skeleton="${this.skeleton}"
259
253
  slot="left"
@@ -272,7 +266,6 @@ class InputTimeRange extends FocusMixin(SkeletonMixin(FormElementMixin(RtlMixin(
272
266
  label="${endLabel}"
273
267
  ?label-hidden="${this.childLabelsHidden}"
274
268
  ?opened="${this.endOpened}"
275
- ?prefer-fixed-positioning="${this.preferFixedPositioning}"
276
269
  ?required="${this.required}"
277
270
  ?skeleton="${this.skeleton}"
278
271
  slot="right"
@@ -154,11 +154,6 @@ class InputTime extends InputInlineHelpMixin(FocusMixin(LabelledMixin(SkeletonMi
154
154
  * @type {boolean}
155
155
  */
156
156
  opened: { type: Boolean },
157
- /**
158
- * Temporary.
159
- * @ignore
160
- */
161
- preferFixedPositioning: { type: Boolean, attribute: 'prefer-fixed-positioning' },
162
157
  /**
163
158
  * Indicates that a value is required
164
159
  * @type {boolean}
@@ -342,7 +337,7 @@ class InputTime extends InputInlineHelpMixin(FocusMixin(LabelledMixin(SkeletonMi
342
337
  class="${this.label && !this.labelHidden && !this.labelledBy ? 'd2l-input-label d2l-skeletize' : 'd2l-offscreen'}"
343
338
  for="${this._dropdownId}-input"
344
339
  id="${this._dropdownId}-label">${this.label}</label>
345
- <d2l-dropdown class="d2l-skeletize" ?disabled="${disabled}" ?prefer-fixed-positioning="${this.preferFixedPositioning}">
340
+ <d2l-dropdown class="d2l-skeletize" ?disabled="${disabled}">
346
341
  <input
347
342
  aria-invalid="${this.invalid ? 'true' : 'false'}"
348
343
  aria-controls="${this._dropdownId}"
@@ -366,8 +361,7 @@ class InputTime extends InputInlineHelpMixin(FocusMixin(LabelledMixin(SkeletonMi
366
361
  no-padding-footer
367
362
  max-height="${ifDefined(this.maxHeight)}"
368
363
  min-width="195"
369
- ?opened="${opened}"
370
- ?prefer-fixed-positioning="${this.preferFixedPositioning}">
364
+ ?opened="${opened}">
371
365
  <d2l-menu
372
366
  aria-labelledby="${this._dropdownId}-label"
373
367
  class="d2l-input-time-menu"
@@ -20,9 +20,6 @@ const pointerLength = 16;
20
20
  const pointerRotatedLength = Math.SQRT2 * parseFloat(pointerLength);
21
21
  const isSupported = ('popover' in HTMLElement.prototype);
22
22
 
23
- // eslint-disable-next-line no-console
24
- console.log('Popover', isSupported);
25
-
26
23
  export const PopoverMixin = superclass => class extends superclass {
27
24
 
28
25
  static get properties() {
@@ -8,9 +8,6 @@
8
8
  import '../../demo/demo-page.js';
9
9
  import './table-test.js';
10
10
  </script>
11
- <script>
12
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: () => true } } } } }; // TODO: remove with GAUD-131-dropdown-fixed-positioning flag clean up
13
- </script>
14
11
  </head>
15
12
  <body unresolved>
16
13
 
@@ -184,9 +184,9 @@ export class TableColSortButton extends LocalizeCoreElement(FocusMixin(LitElemen
184
184
  <slot></slot>${iconView}
185
185
  </button><span id="${this._describedById}" hidden>${buttonDescription}</span>${sortedView}`;
186
186
  if (this._hasDropdownItems) {
187
- return html`<d2l-dropdown prefer-fixed-positioning>
187
+ return html`<d2l-dropdown>
188
188
  ${button}
189
- <d2l-dropdown-menu no-pointer align="start" vertical-offset="0" prefer-fixed-positioning>
189
+ <d2l-dropdown-menu no-pointer align="start" vertical-offset="4">
190
190
  <d2l-menu @d2l-table-col-sort-button-item-change="${this._handleTablColSortButtonItemChange}">
191
191
  <slot name="items" @slotchange="${this._handleSlotChange}"></slot>
192
192
  </d2l-menu>
@@ -11,6 +11,7 @@
11
11
  import '../../dropdown/dropdown-menu.js';
12
12
  import '../../menu/menu.js';
13
13
  import '../../menu/menu-item.js';
14
+ import '../tab.js';
14
15
  import '../tabs.js';
15
16
  import '../tab-panel.js';
16
17
  </script>
@@ -35,35 +36,17 @@
35
36
  </d2l-demo-snippet>
36
37
 
37
38
  <h2>Tabs (paired d2l-tab with d2l-panel)</h2>
39
+ <div>This format is still a WIP. Please do not use yet.</div>
38
40
 
39
41
  <d2l-demo-snippet>
40
- <div>This format is not yet functional. Please do not use yet.</div>
41
42
  <template>
42
43
  <d2l-tabs>
43
44
  <d2l-tab id="all" text="All" slot="tabs"></d2l-tab>
44
45
  <d2l-tab id="biology" text="Biology" slot="tabs"></d2l-tab>
45
46
  <d2l-tab id="chemistry" text="Chemistry" slot="tabs"></d2l-tab>
46
- <d2l-tab id="earth" text="Earth &amp; Planetary Sciences" slot="tabs"></d2l-tab>
47
- <d2l-tab id="physics" text="Physics" slot="tabs"></d2l-tab>
48
- <d2l-tab id="math" text="Math" slot="tabs"></d2l-tab>
49
47
  <d2l-tab-panel labelled-by="all" slot="panels">Tab content for All</d2l-tab-panel>
50
48
  <d2l-tab-panel labelled-by="biology" slot="panels">Tab content for Biology</d2l-tab-panel>
51
49
  <d2l-tab-panel labelled-by="chemistry" slot="panels">Tab content for Chemistry</d2l-tab-panel>
52
- <d2l-tab-panel labelled-by="earth" slot="panels">Tab content for Earth &amp; Planetary Sciences</d2l-tab-panel>
53
- <d2l-tab-panel labelled-by="physics" slot="panels">Tab content for physics</d2l-tab-panel>
54
- <d2l-tab-panel labelled-by="math" slot="panels">Tab content for math</d2l-tab-panel>
55
- <d2l-dropdown-button-subtle slot="ext" text="Explore Topics">
56
- <d2l-dropdown-menu>
57
- <d2l-menu label="Astronomy">
58
- <d2l-menu-item text="Introduction"></d2l-menu-item>
59
- <d2l-menu-item text="Searching for the Heavens "></d2l-menu-item>
60
- <d2l-menu-item text="The Solar System"></d2l-menu-item>
61
- <d2l-menu-item text="Stars &amp; Galaxies"></d2l-menu-item>
62
- <d2l-menu-item text="The Night Sky"></d2l-menu-item>
63
- <d2l-menu-item text="The Universe"></d2l-menu-item>
64
- </d2l-menu>
65
- </d2l-dropdown-menu>
66
- </d2l-dropdown-button-subtle>
67
50
  </d2l-tabs>
68
51
  </template>
69
52
  </d2l-demo-snippet>
@@ -12,6 +12,8 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
12
12
  static get properties() {
13
13
  return {
14
14
  selected: { type: Boolean, reflect: true },
15
+ // eslint-disable-next-line lit/no-native-attributes
16
+ role: { type: String, reflect: true }
15
17
  };
16
18
  }
17
19
 
@@ -62,10 +64,8 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
62
64
 
63
65
  constructor() {
64
66
  super();
65
- this.ariaSelected = false;
66
67
  this.role = 'tab';
67
68
  this.selected = false;
68
- this.tabIndex = -1;
69
69
  }
70
70
 
71
71
  connectedCallback() {
@@ -22,7 +22,6 @@ const scrollButtonWidth = 56;
22
22
  * A component for tabbed content. It supports the "d2l-tab-panel" component for the content, renders tabs responsively, and provides virtual scrolling for large tab lists.
23
23
  * @slot - Contains the tab panels (e.g., "d2l-tab-panel" components)
24
24
  * @slot ext - Additional content (e.g., a button) positioned at right
25
- * @fires d2l-tabs-initialized - Dispatched when the component is initialized
26
25
  */
27
26
  class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))) {
28
27
 
@@ -35,6 +34,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
35
34
  maxToShow: { type: Number, attribute: 'max-to-show' },
36
35
  _allowScrollNext: { type: Boolean },
37
36
  _allowScrollPrevious: { type: Boolean },
37
+ _defaultSlotBehavior: { state: true },
38
38
  _maxWidth: { type: Number },
39
39
  _scrollCollapsed: { type: Boolean },
40
40
  _state: { type: String },
@@ -199,12 +199,13 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
199
199
  this.maxToShow = -1;
200
200
  this._allowScrollNext = false;
201
201
  this._allowScrollPrevious = false;
202
+ this._defaultSlotBehavior = true; // remove after d2l-tab/d2l-tab-panel backport
202
203
  this._loadingCompleteResolve = undefined;
203
204
  this._loadingCompletePromise = new Promise(resolve => this._loadingCompleteResolve = resolve);
204
205
  this._maxWidth = null;
205
206
  this._scrollCollapsed = false;
206
207
  this._state = 'shown';
207
- this._tabInfos = [];
208
+ this._tabInfos = []; // remove after d2l-tab/d2l-tab-panel backport
208
209
  this._translationValue = 0;
209
210
  }
210
211
 
@@ -315,6 +316,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
315
316
  text="${tabInfo.text}">
316
317
  </d2l-tab-internal>
317
318
  `)}
319
+ <slot name="tabs" @slotchange="${this._handleTabsSlotChange}"></slot>
318
320
  </div>
319
321
  `)}
320
322
  <div class="d2l-tabs-scroll-next-container">
@@ -330,7 +332,8 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
330
332
  <div class="${classMap(panelContainerClasses)}"
331
333
  @d2l-tab-panel-selected="${this._handlePanelSelected}"
332
334
  @d2l-tab-panel-text-changed="${this._handlePanelTextChange}">
333
- <slot @slotchange="${this._handlePanelsSlotChange}"></slot>
335
+ <slot @slotchange="${this._handleDefaultSlotChange}"></slot>
336
+ <slot name="panels"></slot>
334
337
  </div>
335
338
  `;
336
339
  }
@@ -340,7 +343,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
340
343
  }
341
344
 
342
345
  async getLoadingComplete() {
343
- return this._loadingCompletePromise;
346
+ return this._defaultSlotBehavior ? this._loadingCompletePromise : true;
344
347
  }
345
348
 
346
349
  getTabListRect() {
@@ -495,6 +498,16 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
495
498
  }
496
499
 
497
500
  _getPanel(id) {
501
+ if (this._defaultSlotBehavior) return this._getPanelDefaultSlotBehavior(id);
502
+
503
+ if (!this.shadowRoot) return;
504
+ const slot = this.shadowRoot.querySelector('slot[name="panels"]');
505
+ const panels = this._getPanels(slot);
506
+ return panels.find(panel => panel.labelledBy === id);
507
+ }
508
+
509
+ // remove after d2l-tab/d2l-tab-panel backport
510
+ _getPanelDefaultSlotBehavior(id) {
498
511
  if (!this.shadowRoot) return;
499
512
  // use simple selector for slot (Edge)
500
513
  const slot = this.shadowRoot.querySelector('.d2l-panels-container').querySelector('slot');
@@ -508,30 +521,16 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
508
521
 
509
522
  _getPanels(slot) {
510
523
  if (!slot) return;
511
- return slot.assignedNodes({ flatten: true })
512
- .filter((node) => node.nodeType === Node.ELEMENT_NODE && node.role === 'tabpanel');
524
+ return slot.assignedElements({ flatten: true }).filter((node) => node.role === 'tabpanel');
513
525
  }
514
526
 
527
+ // remove after d2l-tab/d2l-tab-panel backport
515
528
  _getTabInfo(id) {
516
529
  return this._tabInfos.find((t) => t.id === id);
517
530
  }
518
531
 
519
- _handleFocusOut(e) {
520
- if (e.relatedTarget && e.relatedTarget.role === 'tab') return;
521
- this._resetFocusables();
522
- }
523
-
524
- _handlePanelSelected(e) {
525
- const tabInfo = this._getTabInfo(e.target.id);
526
- // event could be from nested tabs
527
- if (!tabInfo) return;
528
-
529
- this._setFocusable(tabInfo);
530
- tabInfo.selected = true;
531
- this.requestUpdate();
532
- }
533
-
534
- async _handlePanelsSlotChange(e) {
532
+ async _handleDefaultSlotChange(e) {
533
+ if (!this._defaultSlotBehavior) return;
535
534
 
536
535
  const panels = this._getPanels(e.target);
537
536
 
@@ -611,10 +610,24 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
611
610
  });
612
611
  }
613
612
 
614
- this.dispatchEvent(new CustomEvent(
615
- 'd2l-tabs-initialized', { bubbles: true, composed: true }
616
- ));
613
+ }
617
614
 
615
+ _handleFocusOut(e) {
616
+ if (e.relatedTarget && e.relatedTarget.role === 'tab') return;
617
+ this._resetFocusables();
618
+ }
619
+
620
+ // remove after d2l-tab/d2l-tab-panel backport
621
+ _handlePanelSelected(e) {
622
+ if (!this._defaultSlotBehavior) return;
623
+
624
+ const tabInfo = this._getTabInfo(e.target.id);
625
+ // event could be from nested tabs
626
+ if (!tabInfo) return;
627
+
628
+ this._setFocusable(tabInfo);
629
+ tabInfo.selected = true;
630
+ this.requestUpdate();
618
631
  }
619
632
 
620
633
  async _handlePanelTextChange(e) {
@@ -713,6 +726,35 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
713
726
  }
714
727
 
715
728
  async _handleTabSelected(e) {
729
+ if (this._defaultSlotBehavior) {
730
+ this._handleTabSelectedDefaultSlotBehavior(e);
731
+ return;
732
+ }
733
+
734
+ const selectedTab = e.target;
735
+ const selectedPanel = this._getPanel(e.target.id);
736
+ selectedTab.tabIndex = 0;
737
+
738
+ await this.updateComplete;
739
+
740
+ selectedPanel.selected = true;
741
+ this._tabs.forEach((tab) => {
742
+ if (tab.id !== selectedTab.id) {
743
+ if (tab.selected) {
744
+ tab.selected = false;
745
+ const panel = this._getPanel(tab.id);
746
+ // panel may not exist if it's being removed
747
+ if (panel) panel.selected = false;
748
+ }
749
+ if (tab.tabIndex === 0) tab.tabIndex = -1;
750
+ }
751
+ });
752
+
753
+ this.requestUpdate();
754
+ }
755
+
756
+ // remove after d2l-tab/d2l-tab-panel backport
757
+ async _handleTabSelectedDefaultSlotBehavior(e) {
716
758
  e.stopPropagation();
717
759
 
718
760
  const selectedTab = e.target;
@@ -739,6 +781,38 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))
739
781
  this.requestUpdate();
740
782
  }
741
783
 
784
+ async _handleTabsSlotChange(e) {
785
+ this._defaultSlotBehavior = false;
786
+
787
+ this._tabs = e.target.assignedElements({ flatten: true }).filter((node) => node.role === 'tab');
788
+
789
+ // handle case where there are less than two tabs initially
790
+ this._updateTabListVisibility(this._tabs);
791
+
792
+ if (!this._initialized && this._tabs.length === 0) return;
793
+
794
+ let selectedTab;
795
+ if (this._tabs.length > 0) {
796
+ selectedTab = this._tabs.find((tab) => tab.state !== 'removing');
797
+ if (selectedTab) {
798
+ selectedTab.selected = true;
799
+ selectedTab.tabIndex = 0;
800
+ }
801
+ }
802
+
803
+ await this.updateComplete;
804
+
805
+ if (!this._initialized && this._tabs.length > 0) {
806
+ this._initialized = true;
807
+ }
808
+
809
+ if (selectedTab) {
810
+ // set corresponding panel to selected
811
+ const selectedPanel = this._getPanel(selectedTab.id);
812
+ if (selectedPanel) selectedPanel.selected = true;
813
+ }
814
+ }
815
+
742
816
  _isPositionInLeftScrollArea(position) {
743
817
  return position > 0 && position < scrollButtonWidth;
744
818
  }
@@ -12838,6 +12838,11 @@
12838
12838
  "description": "ACCESSIBILITY: REQUIRED: The text used for the tab, as well as labelling the panel.",
12839
12839
  "type": "string"
12840
12840
  },
12841
+ {
12842
+ "name": "role",
12843
+ "type": "string",
12844
+ "default": "\"tab\""
12845
+ },
12841
12846
  {
12842
12847
  "name": "selected",
12843
12848
  "type": "boolean",
@@ -12856,13 +12861,9 @@
12856
12861
  "description": "ACCESSIBILITY: REQUIRED: The text used for the tab, as well as labelling the panel.",
12857
12862
  "type": "string"
12858
12863
  },
12859
- {
12860
- "name": "ariaSelected",
12861
- "type": "boolean",
12862
- "default": "false"
12863
- },
12864
12864
  {
12865
12865
  "name": "role",
12866
+ "attribute": "role",
12866
12867
  "type": "string",
12867
12868
  "default": "\"tab\""
12868
12869
  },
@@ -12872,11 +12873,6 @@
12872
12873
  "type": "boolean",
12873
12874
  "default": "false"
12874
12875
  },
12875
- {
12876
- "name": "tabIndex",
12877
- "type": "number",
12878
- "default": "-1"
12879
- },
12880
12876
  {
12881
12877
  "name": "skeleton",
12882
12878
  "attribute": "skeleton",
@@ -12935,12 +12931,6 @@
12935
12931
  "type": "boolean"
12936
12932
  }
12937
12933
  ],
12938
- "events": [
12939
- {
12940
- "name": "d2l-tabs-initialized",
12941
- "description": "Dispatched when the component is initialized"
12942
- }
12943
- ],
12944
12934
  "slots": [
12945
12935
  {
12946
12936
  "name": "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.91.0",
3
+ "version": "3.93.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",