@brightspace-ui/core 3.269.4 → 3.269.5

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.
@@ -163,10 +163,6 @@ class AlertToast extends LitElement {
163
163
  this._state = states.CLOSED;
164
164
  this._totalSiblingHeightBelow = 0;
165
165
 
166
- this._closeTimerStop = this._closeTimerStop.bind(this);
167
- this._handlePageResize = this._handlePageResize.bind(this);
168
- this._handleSiblingCloseTimerStart = this._handleSiblingCloseTimerStart.bind(this);
169
- this._handleSiblingResize = this._handleSiblingResize.bind(this);
170
166
  this._resizeObserver = null;
171
167
  }
172
168
 
@@ -185,11 +181,11 @@ class AlertToast extends LitElement {
185
181
 
186
182
  async connectedCallback() {
187
183
  super.connectedCallback();
188
- document.body.addEventListener('d2l-alert-toast-close', this._handleSiblingResize);
189
- document.body.addEventListener('d2l-alert-toast-resize', this._handleSiblingResize);
190
- document.body.addEventListener('d2l-alert-toast-timer-start', this._handleSiblingCloseTimerStart);
191
- document.body.addEventListener('d2l-alert-toast-timer-stop', this._closeTimerStop);
192
- if (mediaQueryList.addEventListener) mediaQueryList.addEventListener('change', this._handlePageResize);
184
+ document.body.addEventListener('d2l-alert-toast-close', this.#handleSiblingResize);
185
+ document.body.addEventListener('d2l-alert-toast-resize', this.#handleSiblingResize);
186
+ document.body.addEventListener('d2l-alert-toast-timer-start', this.#handleSiblingCloseTimerStart);
187
+ document.body.addEventListener('d2l-alert-toast-timer-stop', this.#closeTimerStop);
188
+ if (mediaQueryList.addEventListener) mediaQueryList.addEventListener('change', this.#handlePageResize);
193
189
 
194
190
  await this.updateComplete;
195
191
  this._resizeObserver = new ResizeObserver((e) => requestAnimationFrame(() => this._handleResize(e)));
@@ -198,12 +194,12 @@ class AlertToast extends LitElement {
198
194
 
199
195
  disconnectedCallback() {
200
196
  super.disconnectedCallback();
201
- document.body.removeEventListener('d2l-alert-toast-close', this._handleSiblingResize);
202
- document.body.removeEventListener('d2l-alert-toast-resize', this._handleSiblingResize);
203
- document.body.removeEventListener('d2l-alert-toast-timer-start', this._handleSiblingCloseTimerStart);
204
- document.body.removeEventListener('d2l-alert-toast-timer-stop', this._closeTimerStop);
197
+ document.body.removeEventListener('d2l-alert-toast-close', this.#handleSiblingResize);
198
+ document.body.removeEventListener('d2l-alert-toast-resize', this.#handleSiblingResize);
199
+ document.body.removeEventListener('d2l-alert-toast-timer-start', this.#handleSiblingCloseTimerStart);
200
+ document.body.removeEventListener('d2l-alert-toast-timer-stop', this.#closeTimerStop);
205
201
  if (this._resizeObserver) this._resizeObserver.disconnect();
206
- if (mediaQueryList.removeEventListener) mediaQueryList.removeEventListener('change', this._handlePageResize);
202
+ if (mediaQueryList.removeEventListener) mediaQueryList.removeEventListener('change', this.#handlePageResize);
207
203
 
208
204
  if (this._hasMouse) ALERT_HAS_HOVER = false;
209
205
  if (this._hasFocus) ALERT_HAS_FOCUS = false;
@@ -274,6 +270,39 @@ class AlertToast extends LitElement {
274
270
  }
275
271
  }
276
272
 
273
+ #closeTimerStop = () => {
274
+ if (!this.open) return;
275
+ clearTimeout(this._setTimeoutId);
276
+ };
277
+
278
+ #handlePageResize = (e) => {
279
+ this._smallWidth = e.matches;
280
+ };
281
+
282
+ #handleSiblingCloseTimerStart = () => {
283
+ if (!this.open) return;
284
+ this._closeTimerStart();
285
+ };
286
+
287
+ #handleSiblingResize = (e) => {
288
+ if (e?.composedPath()[0] === this || !this.open) return;
289
+
290
+ if (!e.detail.opening) {
291
+ const containerBottom = this._innerContainer.getBoundingClientRect().bottom;
292
+ const siblingContainerBottom = e.detail.bottom;
293
+ if (siblingContainerBottom < containerBottom) return; // resized alert is above this alert, no need to adjust bottom spacing
294
+ }
295
+
296
+ this._totalSiblingHeightBelow += e.detail.heightDifference;
297
+ if (e.detail.opening) {
298
+ this._numAlertsBelow += 1;
299
+ if (!activeReduceMotion) this._state = states.SLIDING;
300
+ } else if (e.detail.closing) {
301
+ this._numAlertsBelow -= 1;
302
+ if (!activeReduceMotion) this._state = states.SLIDING;
303
+ }
304
+ };
305
+
277
306
  _closeTimerStart() {
278
307
  clearTimeout(this._setTimeoutId);
279
308
  if (!this.noAutoClose && !ALERT_HAS_FOCUS && !ALERT_HAS_HOVER) {
@@ -284,20 +313,11 @@ class AlertToast extends LitElement {
284
313
  }
285
314
  }
286
315
 
287
- _closeTimerStop() {
288
- if (!this.open) return;
289
- clearTimeout(this._setTimeoutId);
290
- }
291
-
292
316
  _handleButtonPress(e) {
293
317
  e.stopPropagation();
294
318
  this.dispatchEvent(new CustomEvent('d2l-alert-toast-button-press'));
295
319
  }
296
320
 
297
- _handlePageResize(e) {
298
- this._smallWidth = e.matches;
299
- }
300
-
301
321
  _handleResize() {
302
322
  const boundingClientRect = this._innerContainer.getBoundingClientRect();
303
323
  const newHeight = boundingClientRect.height;
@@ -318,30 +338,6 @@ class AlertToast extends LitElement {
318
338
  ));
319
339
  }
320
340
 
321
- _handleSiblingCloseTimerStart() {
322
- if (!this.open) return;
323
- this._closeTimerStart();
324
- }
325
-
326
- _handleSiblingResize(e) {
327
- if (e?.composedPath()[0] === this || !this.open) return;
328
-
329
- if (!e.detail.opening) {
330
- const containerBottom = this._innerContainer.getBoundingClientRect().bottom;
331
- const siblingContainerBottom = e.detail.bottom;
332
- if (siblingContainerBottom < containerBottom) return; // resized alert is above this alert, no need to adjust bottom spacing
333
- }
334
-
335
- this._totalSiblingHeightBelow += e.detail.heightDifference;
336
- if (e.detail.opening) {
337
- this._numAlertsBelow += 1;
338
- if (!activeReduceMotion) this._state = states.SLIDING;
339
- } else if (e.detail.closing) {
340
- this._numAlertsBelow -= 1;
341
- if (!activeReduceMotion) this._state = states.SLIDING;
342
- }
343
- }
344
-
345
341
  _onBlur() {
346
342
  ALERT_HAS_FOCUS = false;
347
343
  this._hasFocus = false;
@@ -361,7 +357,7 @@ class AlertToast extends LitElement {
361
357
  _onFocus() {
362
358
  ALERT_HAS_FOCUS = true;
363
359
  this._hasFocus = true;
364
- this._closeTimerStop();
360
+ this.#closeTimerStop();
365
361
  /** @ignore */
366
362
  this.dispatchEvent(new CustomEvent('d2l-alert-toast-timer-stop', { bubbles: true, composed: false }));
367
363
  }
@@ -369,7 +365,7 @@ class AlertToast extends LitElement {
369
365
  _onMouseEnter() {
370
366
  ALERT_HAS_HOVER = true;
371
367
  this._hasMouse = true;
372
- this._closeTimerStop();
368
+ this.#closeTimerStop();
373
369
  /** @ignore */
374
370
  this.dispatchEvent(new CustomEvent('d2l-alert-toast-timer-stop', { bubbles: true, composed: false }));
375
371
  }
@@ -458,7 +454,7 @@ class AlertToast extends LitElement {
458
454
  if (newlyOpened || newlyOpenedReduceMotion) {
459
455
  this._closeTimerStart();
460
456
  } else if (newState !== states.SLIDING && newState !== states.OPEN) {
461
- this._closeTimerStop();
457
+ this.#closeTimerStop();
462
458
  }
463
459
  }
464
460
  }
@@ -227,15 +227,13 @@ class Card extends LitElement {
227
227
  this._footerHidden = true;
228
228
  this._hover = false;
229
229
  this._tooltipShowing = false;
230
- this._onBadgeResize = this._onBadgeResize.bind(this);
231
- this._onFooterResize = this._onFooterResize.bind(this);
232
230
  }
233
231
 
234
232
  firstUpdated(changedProperties) {
235
233
  super.firstUpdated(changedProperties);
236
- const badgeObserver = new ResizeObserver(this._onBadgeResize);
234
+ const badgeObserver = new ResizeObserver(this.#onBadgeResize);
237
235
  badgeObserver.observe(this.shadowRoot.querySelector('.d2l-card-badge'));
238
- const footerObserver = new ResizeObserver(this._onFooterResize);
236
+ const footerObserver = new ResizeObserver(this.#onFooterResize);
239
237
  footerObserver.observe(this.shadowRoot.querySelector('.d2l-card-footer'));
240
238
 
241
239
  if (this._focusOnFirstRender) {
@@ -307,11 +305,19 @@ class Card extends LitElement {
307
305
  else super.focus();
308
306
  }
309
307
 
310
- _onBadgeResize(entries) {
308
+ #onBadgeResize = (entries) => {
311
309
  if (!entries || entries.length === 0) return;
312
310
  const entry = entries[0];
313
311
  requestAnimationFrame(() => this._badgeMarginTop = `${-0.5 * entry.contentRect.height}px`);
314
- }
312
+ };
313
+
314
+ #onFooterResize = (entries) => {
315
+ if (!entries || entries.length === 0) return;
316
+ const entry = entries[0];
317
+ // firefox has a rounding error when calculating the height of the contentRect
318
+ // with `box-sizing: border-box;` so check for numbers which are close to 0 as well
319
+ requestAnimationFrame(() => this._footerHidden = (entry.contentRect.height < 1));
320
+ };
315
321
 
316
322
  _onDropdownClose() {
317
323
  this._dropdownActionOpen = false;
@@ -321,14 +327,6 @@ class Card extends LitElement {
321
327
  this._dropdownActionOpen = true;
322
328
  }
323
329
 
324
- _onFooterResize(entries) {
325
- if (!entries || entries.length === 0) return;
326
- const entry = entries[0];
327
- // firefox has a rounding error when calculating the height of the contentRect
328
- // with `box-sizing: border-box;` so check for numbers which are close to 0 as well
329
- requestAnimationFrame(() => this._footerHidden = (entry.contentRect.height < 1));
330
- }
331
-
332
330
  _onLinkBlur() {
333
331
  this._active = false;
334
332
  }
@@ -79,7 +79,6 @@ export const DialogMixin = superclass => class extends superclass {
79
79
  this._autoSize = true;
80
80
  this._dialogId = getUniqueId();
81
81
  this._fullscreenWithin = 0;
82
- this._handleMvcDialogOpen = this._handleMvcDialogOpen.bind(this);
83
82
  this._inIframe = false;
84
83
  this._isDialogMixin = true;
85
84
  this._isFullHeight = false;
@@ -93,21 +92,19 @@ export const DialogMixin = superclass => class extends superclass {
93
92
  this._scroll = false;
94
93
  this._state = null;
95
94
  this._top = 0;
96
- this._updateOverflow = this._updateOverflow.bind(this);
97
- this._updateSize = this._updateSize.bind(this);
98
95
  this._width = 0;
99
96
  }
100
97
 
101
98
  async connectedCallback() {
102
99
  super.connectedCallback();
103
100
  if (this._useNative) {
104
- window.addEventListener('d2l-mvc-dialog-open', this._handleMvcDialogOpen);
101
+ window.addEventListener('d2l-mvc-dialog-open', this.#handleMvcDialogOpen);
105
102
  }
106
103
  }
107
104
 
108
105
  disconnectedCallback() {
109
106
  super.disconnectedCallback();
110
- window.removeEventListener('d2l-mvc-dialog-open', this._handleMvcDialogOpen);
107
+ window.removeEventListener('d2l-mvc-dialog-open', this.#handleMvcDialogOpen);
111
108
 
112
109
  // If the dialog is disconnected before the close animation finishes
113
110
  if (this.opened && closeDialogWhenDisconnectedFlag) {
@@ -158,7 +155,7 @@ export const DialogMixin = superclass => class extends superclass {
158
155
  resize() {
159
156
  return new Promise(resolve => {
160
157
  setTimeout(async() => {
161
- await this._updateSize();
158
+ await this.#updateSize();
162
159
  resolve();
163
160
  }, 0);
164
161
  });
@@ -172,10 +169,56 @@ export const DialogMixin = superclass => class extends superclass {
172
169
 
173
170
  #useNativeInitialized = false;
174
171
 
172
+ #handleMvcDialogOpen = () => {
173
+ // native dialogs on top layer will be stacked on non-native dialogs regardless of z-index
174
+ // so we need to opt out of native dialogs if a non-native nested dialog is launched
175
+ this._useNative = false;
176
+ };
177
+
178
+ #updateOverflow = () => {
179
+ if (!this.shadowRoot) return;
180
+ const content = this.shadowRoot.querySelector('.d2l-dialog-content');
181
+ // On Windows, browser zoom can cause scrollTop to be a fraction
182
+ const bottomOverflow = content.scrollHeight - (Math.ceil(content.scrollTop) + content.clientHeight);
183
+ this._overflowTop = (content.scrollTop > 0);
184
+ this._overflowBottom = (bottomOverflow > 0);
185
+ };
186
+
187
+ #updateSize = async() => {
188
+ if (this._autoSize) {
189
+ if (this._ifrauContextInfo) {
190
+ if (this._ifrauContextInfo.top > defaultMargin.top) {
191
+ this._top = 0;
192
+ this._margin.top = 0;
193
+ } else if (this._ifrauContextInfo.top < 0) {
194
+ this._top = defaultMargin.top - this._ifrauContextInfo.top;
195
+ this._margin.top = defaultMargin.top;
196
+ } else {
197
+ this._top = defaultMargin.top - this._ifrauContextInfo.top;
198
+ this._margin.top = defaultMargin.top - this._ifrauContextInfo.top;
199
+ }
200
+ }
201
+ this._width = this._getWidth();
202
+ this._left = this._getLeft();
203
+ await this.updateComplete;
204
+ this._height = this._getHeight();
205
+ await this.updateComplete;
206
+ } else {
207
+ this._width = 0;
208
+ }
209
+ await new Promise(resolve => {
210
+ requestAnimationFrame(async() => {
211
+ this.#updateOverflow();
212
+ await this.updateComplete;
213
+ resolve();
214
+ });
215
+ });
216
+ };
217
+
175
218
  _addHandlers() {
176
- window.addEventListener('resize', this._updateSize);
219
+ window.addEventListener('resize', this.#updateSize);
177
220
  this.addEventListener('touchstart', this._handleTouchStart);
178
- if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dialog-content').addEventListener('scroll', this._updateOverflow);
221
+ if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dialog-content').addEventListener('scroll', this.#updateOverflow);
179
222
  }
180
223
 
181
224
  _close(action) {
@@ -379,12 +422,6 @@ export const DialogMixin = superclass => class extends superclass {
379
422
  }
380
423
  }
381
424
 
382
- _handleMvcDialogOpen() {
383
- // native dialogs on top layer will be stacked on non-native dialogs regardless of z-index
384
- // so we need to opt out of native dialogs if a non-native nested dialog is launched
385
- this._useNative = false;
386
- }
387
-
388
425
  _handleTouchStart(e) {
389
426
  // elements external to the dialog such as primary-secondary template should not be reacting
390
427
  // to touchstart events originating inside the dialog or backdrop
@@ -450,7 +487,7 @@ export const DialogMixin = superclass => class extends superclass {
450
487
  this._scroll = true;
451
488
  }, 0);
452
489
 
453
- await this._updateSize();
490
+ await this.#updateSize();
454
491
  if (!this._useNative) this._state = 'showing';
455
492
  await this.updateComplete;
456
493
 
@@ -470,7 +507,7 @@ export const DialogMixin = superclass => class extends superclass {
470
507
  requestAnimationFrame(() => this._updateFocusableContentElemPresent());
471
508
 
472
509
  await this.waitForUpdateComplete();
473
- await this._updateSize();
510
+ await this.#updateSize();
474
511
  /** Dispatched when the dialog is opened */
475
512
  this.dispatchEvent(new CustomEvent(
476
513
  'd2l-dialog-open', { bubbles: true, composed: true }
@@ -481,9 +518,9 @@ export const DialogMixin = superclass => class extends superclass {
481
518
  }
482
519
 
483
520
  _removeHandlers() {
484
- window.removeEventListener('resize', this._updateSize);
521
+ window.removeEventListener('resize', this.#updateSize);
485
522
  this.removeEventListener('touchstart', this._handleTouchStart);
486
- this.shadowRoot?.querySelector('.d2l-dialog-content')?.removeEventListener('scroll', this._updateOverflow);
523
+ this.shadowRoot?.querySelector('.d2l-dialog-content')?.removeEventListener('scroll', this.#updateOverflow);
487
524
  }
488
525
 
489
526
  _render(inner, info, iframeTopOverride) {
@@ -564,44 +601,4 @@ export const DialogMixin = superclass => class extends superclass {
564
601
  return elementToFocus;
565
602
  }
566
603
 
567
- _updateOverflow() {
568
- if (!this.shadowRoot) return;
569
- const content = this.shadowRoot.querySelector('.d2l-dialog-content');
570
- // On Windows, browser zoom can cause scrollTop to be a fraction
571
- const bottomOverflow = content.scrollHeight - (Math.ceil(content.scrollTop) + content.clientHeight);
572
- this._overflowTop = (content.scrollTop > 0);
573
- this._overflowBottom = (bottomOverflow > 0);
574
- }
575
-
576
- async _updateSize() {
577
- if (this._autoSize) {
578
- if (this._ifrauContextInfo) {
579
- if (this._ifrauContextInfo.top > defaultMargin.top) {
580
- this._top = 0;
581
- this._margin.top = 0;
582
- } else if (this._ifrauContextInfo.top < 0) {
583
- this._top = defaultMargin.top - this._ifrauContextInfo.top;
584
- this._margin.top = defaultMargin.top;
585
- } else {
586
- this._top = defaultMargin.top - this._ifrauContextInfo.top;
587
- this._margin.top = defaultMargin.top - this._ifrauContextInfo.top;
588
- }
589
- }
590
- this._width = this._getWidth();
591
- this._left = this._getLeft();
592
- await this.updateComplete;
593
- this._height = this._getHeight();
594
- await this.updateComplete;
595
- } else {
596
- this._width = 0;
597
- }
598
- await new Promise(resolve => {
599
- requestAnimationFrame(async() => {
600
- this._updateOverflow();
601
- await this.updateComplete;
602
- resolve();
603
- });
604
- });
605
- }
606
-
607
604
  };
@@ -102,7 +102,6 @@ class Dialog extends PropertyRequiredMixin(LocalizeCoreElement(AsyncContainerMix
102
102
  this.preferNative = false;
103
103
  this.width = 600;
104
104
  this._criticalLabelId = getUniqueId();
105
- this._handleResize = this._handleResize.bind(this);
106
105
  this._titleId = getUniqueId();
107
106
  this._textId = getUniqueId();
108
107
  }
@@ -113,17 +112,17 @@ class Dialog extends PropertyRequiredMixin(LocalizeCoreElement(AsyncContainerMix
113
112
 
114
113
  connectedCallback() {
115
114
  super.connectedCallback();
116
- if (mediaQueryList.addEventListener) mediaQueryList.addEventListener('change', this._handleResize);
115
+ if (mediaQueryList.addEventListener) mediaQueryList.addEventListener('change', this.#handleResize);
117
116
  }
118
117
 
119
118
  disconnectedCallback() {
120
- if (mediaQueryList.removeEventListener) mediaQueryList.removeEventListener('change', this._handleResize);
119
+ if (mediaQueryList.removeEventListener) mediaQueryList.removeEventListener('change', this.#handleResize);
121
120
  super.disconnectedCallback();
122
121
  }
123
122
 
124
123
  firstUpdated(changedProperties) {
125
124
  super.firstUpdated(changedProperties);
126
- this._handleResize();
125
+ this.#handleResize();
127
126
  }
128
127
 
129
128
  render() {
@@ -202,6 +201,11 @@ class Dialog extends PropertyRequiredMixin(LocalizeCoreElement(AsyncContainerMix
202
201
  }
203
202
  }
204
203
 
204
+ #handleResize = () => {
205
+ this._autoSize = !mediaQueryList.matches;
206
+ this.resize();
207
+ };
208
+
205
209
  _abort() {
206
210
  this._close('abort');
207
211
  }
@@ -211,11 +215,6 @@ class Dialog extends PropertyRequiredMixin(LocalizeCoreElement(AsyncContainerMix
211
215
  this._hasFooterContent = (footerContent && footerContent.length > 0);
212
216
  }
213
217
 
214
- _handleResize() {
215
- this._autoSize = !mediaQueryList.matches;
216
- this.resize();
217
- }
218
-
219
218
  _handleSlotChange() {
220
219
  requestAnimationFrame(() => this._updateFocusableContentElemPresent());
221
220
  }
@@ -62,7 +62,6 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
62
62
  this._isHovering = false;
63
63
  this._isFading = false;
64
64
 
65
- this._onOutsideClick = this._onOutsideClick.bind(this);
66
65
  this._contentRendered = null;
67
66
  this._openerRendered = null;
68
67
  }
@@ -77,7 +76,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
77
76
  this.addEventListener('mouseleave', this.__onMouseLeave);
78
77
 
79
78
  if (this.openOnHover) {
80
- document.body.addEventListener('mouseup', this._onOutsideClick);
79
+ document.body.addEventListener('mouseup', this.#onOutsideClick);
81
80
  }
82
81
  }
83
82
 
@@ -90,7 +89,7 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
90
89
  this.removeEventListener('mouseleave', this.__onMouseLeave);
91
90
 
92
91
  if (this.openOnHover) {
93
- document.body.removeEventListener('mouseup', this._onOutsideClick);
92
+ document.body.removeEventListener('mouseup', this.#onOutsideClick);
94
93
  }
95
94
  }
96
95
 
@@ -167,6 +166,22 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
167
166
  this.dropdownOpened = !this.dropdownOpened;
168
167
  }
169
168
 
169
+ /* used by open-on-hover option */
170
+ #onOutsideClick = (e) => {
171
+ if (!this.dropdownOpened) return;
172
+ const dropdownContent = this.__getContentElement();
173
+ const isWithinDropdown = isComposedAncestor(dropdownContent, e.composedPath()[0]);
174
+ const isWithinOpener = isComposedAncestor(this.getOpenerElement(), e.composedPath()[0]);
175
+
176
+ const isBackdropClick = isWithinDropdown
177
+ && dropdownContent._mobile
178
+ && e.composedPath().find(node => node.nodeName === 'D2L-BACKDROP');
179
+
180
+ if (!isWithinOpener && (!isWithinDropdown || isBackdropClick)) {
181
+ this.closeDropdown();
182
+ }
183
+ };
184
+
170
185
  __dispatchOpenerClickEvent() {
171
186
  /** Dispatched when the opener is clicked, useful for when no-auto-open is enabled */
172
187
  this.dispatchEvent(new CustomEvent(
@@ -289,22 +304,6 @@ export const DropdownOpenerMixin = superclass => class extends superclass {
289
304
  this._isFading = false;
290
305
  }
291
306
 
292
- /* used by open-on-hover option */
293
- _onOutsideClick(e) {
294
- if (!this.dropdownOpened) return;
295
- const dropdownContent = this.__getContentElement();
296
- const isWithinDropdown = isComposedAncestor(dropdownContent, e.composedPath()[0]);
297
- const isWithinOpener = isComposedAncestor(this.getOpenerElement(), e.composedPath()[0]);
298
-
299
- const isBackdropClick = isWithinDropdown
300
- && dropdownContent._mobile
301
- && e.composedPath().find(node => node.nodeName === 'D2L-BACKDROP');
302
-
303
- if (!isWithinOpener && (!isWithinDropdown || isBackdropClick)) {
304
- this.closeDropdown();
305
- }
306
- }
307
-
308
307
  _setOpenerElementAttribute(val, setActive = false, hasPopup) {
309
308
  const opener = this.getOpenerElement();
310
309
  if (!opener) return false;
@@ -33,9 +33,6 @@ class FocusTrap extends FocusMixin(LitElement) {
33
33
  constructor() {
34
34
  super();
35
35
  this.trap = false;
36
- this._handleBodyFocus = this._handleBodyFocus.bind(this);
37
- this._handleLegacyPromptOpen = this._handleLegacyPromptOpen.bind(this);
38
- this._handleLegacyPromptClose = this._handleLegacyPromptClose.bind(this);
39
36
  this._legacyPromptIds = new Set();
40
37
  }
41
38
 
@@ -45,16 +42,16 @@ class FocusTrap extends FocusMixin(LitElement) {
45
42
 
46
43
  connectedCallback() {
47
44
  super.connectedCallback();
48
- document.body.addEventListener('focus', this._handleBodyFocus, true);
49
- document.body.addEventListener('d2l-legacy-prompt-open', this._handleLegacyPromptOpen);
50
- document.body.addEventListener('d2l-legacy-prompt-close', this._handleLegacyPromptClose);
45
+ document.body.addEventListener('focus', this.#handleBodyFocus, true);
46
+ document.body.addEventListener('d2l-legacy-prompt-open', this.#handleLegacyPromptOpen);
47
+ document.body.addEventListener('d2l-legacy-prompt-close', this.#handleLegacyPromptClose);
51
48
  }
52
49
 
53
50
  disconnectedCallback() {
54
51
  super.disconnectedCallback();
55
- document.body.removeEventListener('focus', this._handleBodyFocus, true);
56
- document.body.removeEventListener('d2l-legacy-prompt-open', this._handleLegacyPromptOpen);
57
- document.body.removeEventListener('d2l-legacy-prompt-close', this._handleLegacyPromptClose);
52
+ document.body.removeEventListener('focus', this.#handleBodyFocus, true);
53
+ document.body.removeEventListener('d2l-legacy-prompt-open', this.#handleLegacyPromptOpen);
54
+ document.body.removeEventListener('d2l-legacy-prompt-close', this.#handleLegacyPromptClose);
58
55
  }
59
56
 
60
57
  render() {
@@ -83,6 +80,25 @@ class FocusTrap extends FocusMixin(LitElement) {
83
80
  '.equatio-toolbar-shadow-root-container'
84
81
  ].join(', ');
85
82
 
83
+ #handleBodyFocus = (e) => {
84
+ const lastTrap = traps[traps.length - 1];
85
+ if (!this.trap || this._legacyPromptIds.size > 0 || lastTrap !== this) return;
86
+ const container = this._getContainer();
87
+ const target = e.composedPath()[0];
88
+ if (isComposedAncestor(container, target) || FocusTrap.#isExempt(target)) return;
89
+ this._focusFirst();
90
+ };
91
+
92
+ #handleLegacyPromptClose = (e) => {
93
+ this._legacyPromptIds.delete(e.detail.id);
94
+ this.requestUpdate();
95
+ };
96
+
97
+ #handleLegacyPromptOpen = (e) => {
98
+ this._legacyPromptIds.add(e.detail.id);
99
+ this.requestUpdate();
100
+ };
101
+
86
102
  _focusFirst() {
87
103
  const focusable = this.shadowRoot &&
88
104
  getNextFocusable(this.shadowRoot.querySelector('.d2l-focus-trap-start'));
@@ -94,15 +110,6 @@ class FocusTrap extends FocusMixin(LitElement) {
94
110
  return this.shadowRoot && this.shadowRoot.querySelector('.d2l-focus-trap-start').parentNode;
95
111
  }
96
112
 
97
- _handleBodyFocus(e) {
98
- const lastTrap = traps[traps.length - 1];
99
- if (!this.trap || this._legacyPromptIds.size > 0 || lastTrap !== this) return;
100
- const container = this._getContainer();
101
- const target = e.composedPath()[0];
102
- if (isComposedAncestor(container, target) || FocusTrap.#isExempt(target)) return;
103
- this._focusFirst();
104
- }
105
-
106
113
  _handleEndFocusIn(e) {
107
114
  const container = this._getContainer();
108
115
  if (this.shadowRoot && (isComposedAncestor(container, e.relatedTarget) || FocusTrap.#isExempt(e.relatedTarget))) {
@@ -116,16 +123,6 @@ class FocusTrap extends FocusMixin(LitElement) {
116
123
  this._focusFirst();
117
124
  }
118
125
 
119
- _handleLegacyPromptClose(e) {
120
- this._legacyPromptIds.delete(e.detail.id);
121
- this.requestUpdate();
122
- }
123
-
124
- _handleLegacyPromptOpen(e) {
125
- this._legacyPromptIds.add(e.detail.id);
126
- this.requestUpdate();
127
- }
128
-
129
126
  _handleStartFocusIn(e) {
130
127
  const container = this._getContainer();
131
128
  if (this.shadowRoot && (isComposedAncestor(container, e.relatedTarget) || FocusTrap.#isExempt(e.relatedTarget))) {
@@ -113,8 +113,6 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
113
113
 
114
114
  constructor() {
115
115
  super();
116
- this._validationCustomConnected = this._validationCustomConnected.bind(this);
117
- this._onFormElementErrorsChange = this._onFormElementErrorsChange.bind(this);
118
116
 
119
117
  this._firstUpdateResolve = null;
120
118
  this._firstUpdatePromise = new Promise((resolve) => {
@@ -160,14 +158,14 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
160
158
 
161
159
  connectedCallback() {
162
160
  super.connectedCallback();
163
- this.shadowRoot.addEventListener('d2l-validation-custom-connected', this._validationCustomConnected);
164
- this.shadowRoot.addEventListener('d2l-form-element-errors-change', this._onFormElementErrorsChange);
161
+ this.shadowRoot.addEventListener('d2l-validation-custom-connected', this.#validationCustomConnected);
162
+ this.shadowRoot.addEventListener('d2l-form-element-errors-change', this.#onFormElementErrorsChange);
165
163
  }
166
164
 
167
165
  disconnectedCallback() {
168
166
  super.disconnectedCallback();
169
- this.shadowRoot.removeEventListener('d2l-validation-custom-connected', this._validationCustomConnected);
170
- this.shadowRoot.removeEventListener('d2l-form-element-errors-change', this._onFormElementErrorsChange);
167
+ this.shadowRoot.removeEventListener('d2l-validation-custom-connected', this.#validationCustomConnected);
168
+ this.shadowRoot.removeEventListener('d2l-form-element-errors-change', this.#onFormElementErrorsChange);
171
169
  }
172
170
 
173
171
  firstUpdated(changedProperties) {
@@ -261,7 +259,7 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
261
259
  this._validationCustoms.delete(custom);
262
260
  }
263
261
 
264
- _onFormElementErrorsChange(e) {
262
+ #onFormElementErrorsChange = (e) => {
265
263
  e.stopPropagation();
266
264
  const errors = e.detail.errors;
267
265
  if (errors.length === 0) {
@@ -273,9 +271,9 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
273
271
  this.childErrors.set(e.target, errors);
274
272
  this.requestUpdate('childErrors');
275
273
  }
276
- }
274
+ };
277
275
 
278
- _validationCustomConnected(e) {
276
+ #validationCustomConnected = (e) => {
279
277
  e.stopPropagation();
280
278
  const custom = e.composedPath()[0];
281
279
  this.validationCustomConnected(custom);
@@ -285,6 +283,6 @@ export const FormElementMixin = superclass => class extends LocalizeCoreElement(
285
283
  this.validationCustomDisconnected(custom);
286
284
  };
287
285
  custom.addEventListener('d2l-validation-custom-disconnected', onDisconnect);
288
- }
286
+ };
289
287
 
290
288
  };
@@ -4,7 +4,6 @@ import '../link/link.js';
4
4
  import { css, html, LitElement } from 'lit';
5
5
  import { findFormElements, flattenMap, getFormElementData, isCustomFormElement, isNativeFormElement } from './form-helper.js';
6
6
  import { findComposedAncestor } from '../../helpers/dom.js';
7
- import { getComposedActiveElement } from '../../helpers/focus.js';
8
7
  import { getUniqueId } from '../../helpers/uniqueId.js';
9
8
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
10
9
  import { localizeFormElement } from './form-element-localize-helper.js';
@@ -66,9 +65,6 @@ class Form extends LocalizeCoreElement(LitElement) {
66
65
  this._tooltips = new Map();
67
66
  this._validationCustoms = new Set();
68
67
 
69
- this._onUnload = this._onUnload.bind(this);
70
- this._onNativeSubmit = this._onNativeSubmit.bind(this);
71
-
72
68
  /** @ignore */
73
69
  this.addEventListener('d2l-form-connect', this._onFormConnect);
74
70
  this.addEventListener('d2l-form-errors-change', this._onErrorsChange);
@@ -84,14 +80,14 @@ class Form extends LocalizeCoreElement(LitElement) {
84
80
 
85
81
  connectedCallback() {
86
82
  super.connectedCallback();
87
- window.addEventListener('beforeunload', this._onUnload);
83
+ window.addEventListener('beforeunload', this.#onUnload);
88
84
  /** @ignore */
89
85
  this._isSubForm = !this.dispatchEvent(new CustomEvent('d2l-form-connect', { bubbles: true, composed: true, cancelable: true }));
90
86
  }
91
87
 
92
88
  disconnectedCallback() {
93
89
  super.disconnectedCallback();
94
- window.removeEventListener('beforeunload', this._onUnload);
90
+ window.removeEventListener('beforeunload', this.#onUnload);
95
91
  /** @ignore */
96
92
  this.dispatchEvent(new CustomEvent('d2l-form-disconnect'));
97
93
  this._isSubForm = false;
@@ -193,6 +189,13 @@ class Form extends LocalizeCoreElement(LitElement) {
193
189
  return flattenedErrorMap;
194
190
  }
195
191
 
192
+ #onUnload = (e) => {
193
+ if (this.trackChanges && this._dirty) {
194
+ e.preventDefault();
195
+ e.returnValue = false;
196
+ }
197
+ };
198
+
196
199
  _displayInvalid(ele, message) {
197
200
  let tooltip = this._tooltips.get(ele);
198
201
  if (!tooltip) {
@@ -296,20 +299,6 @@ class Form extends LocalizeCoreElement(LitElement) {
296
299
  this._updateErrors(ele, errors);
297
300
  }
298
301
 
299
- _onNativeSubmit(e) {
300
- e.preventDefault();
301
- e.stopPropagation();
302
- const submitter = e.submitter || getComposedActiveElement();
303
- this.requestSubmit(submitter);
304
- }
305
-
306
- _onUnload(e) {
307
- if (this.trackChanges && this._dirty) {
308
- e.preventDefault();
309
- e.returnValue = false;
310
- }
311
- }
312
-
313
302
  _setupDialogValidationReset() {
314
303
  const dialogAncestor = findComposedAncestor(
315
304
  this,
@@ -302,8 +302,6 @@ class InputText extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(La
302
302
  this._lastSlotWidth = 0;
303
303
  this._prevValue = '';
304
304
 
305
- this._handleBlur = this._handleBlur.bind(this);
306
- this._handleFocus = this._handleFocus.bind(this);
307
305
  this._perfMonitor = new PerfMonitor(this);
308
306
  }
309
307
 
@@ -369,8 +367,8 @@ class InputText extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(La
369
367
  if (this._intersectionObserver) this._intersectionObserver.disconnect();
370
368
  const container = this.shadowRoot && this.shadowRoot.querySelector('.d2l-input-text-container');
371
369
  if (!container) return;
372
- container.removeEventListener('blur', this._handleBlur, true);
373
- container.removeEventListener('focus', this._handleFocus, true);
370
+ container.removeEventListener('blur', this.#handleBlur, true);
371
+ container.removeEventListener('focus', this.#handleFocus, true);
374
372
  }
375
373
 
376
374
  firstUpdated(changedProperties) {
@@ -380,8 +378,8 @@ class InputText extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(La
380
378
 
381
379
  const container = this.shadowRoot && this.shadowRoot.querySelector('.d2l-input-text-container');
382
380
  if (!container) return;
383
- container.addEventListener('blur', this._handleBlur, true);
384
- container.addEventListener('focus', this._handleFocus, true);
381
+ container.addEventListener('blur', this.#handleBlur, true);
382
+ container.addEventListener('focus', this.#handleFocus, true);
385
383
 
386
384
  // if initially hidden then update layout when it becomes visible
387
385
  if (typeof(IntersectionObserver) === 'function') {
@@ -534,6 +532,24 @@ class InputText extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(La
534
532
  });
535
533
  }
536
534
 
535
+ #handleBlur = async(e) => {
536
+ this._focused = false;
537
+ this.requestValidate(true);
538
+
539
+ /**
540
+ * This is needed only for Legacy-Edge
541
+ * the _handleChange function is NOT triggered, therefore we have to detect the blur and handle it ourselves.
542
+ */
543
+ const browserType = window.navigator.userAgent;
544
+ if (this._prevValue !== e.target.value && (browserType.indexOf('Edge') > -1)) {
545
+ this._handleChange();
546
+ }
547
+ };
548
+
549
+ #handleFocus = () => {
550
+ this._focused = true;
551
+ };
552
+
537
553
  _getAriaLabel() {
538
554
  let label;
539
555
  if (this.label && (this.labelHidden || this.labelledBy)) {
@@ -565,20 +581,6 @@ class InputText extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(La
565
581
  this._hasAfterContent = (afterContent && afterContent.length > 0);
566
582
  }
567
583
 
568
- async _handleBlur(e) {
569
- this._focused = false;
570
- this.requestValidate(true);
571
-
572
- /**
573
- * This is needed only for Legacy-Edge
574
- * the _handleChange function is NOT triggered, therefore we have to detect the blur and handle it ourselves.
575
- */
576
- const browserType = window.navigator.userAgent;
577
- if (this._prevValue !== e.target.value && (browserType.indexOf('Edge') > -1)) {
578
- this._handleChange();
579
- }
580
- }
581
-
582
584
  _handleChange() {
583
585
  // Change events aren't composed, so we need to re-dispatch
584
586
  this.dispatchEvent(new CustomEvent(
@@ -587,10 +589,6 @@ class InputText extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(La
587
589
  ));
588
590
  }
589
591
 
590
- _handleFocus() {
591
- this._focused = true;
592
- }
593
-
594
592
  _handleInput(e) {
595
593
  this._setValue(e.target.value, false);
596
594
  return true;
@@ -83,10 +83,8 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
83
83
  constructor() {
84
84
  super();
85
85
 
86
- this._handleItemMutation = this._handleItemMutation.bind(this);
87
- this._handleResize = this._handleResize.bind(this);
88
- this._itemObserver = new MutationObserver(this._handleItemMutation);
89
- this._resizeObserver = new ResizeObserver((entries) => requestAnimationFrame(() => this._handleResize(entries)));
86
+ this._itemObserver = new MutationObserver(this.#handleItemMutation);
87
+ this._resizeObserver = new ResizeObserver((entries) => requestAnimationFrame(() => this.#handleResize(entries)));
90
88
 
91
89
  this._hasResized = false;
92
90
  this._isObservingResize = false;
@@ -183,6 +181,46 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
183
181
  throw new Error('OverflowGroupMixin.getOverflowContainer must be overridden');
184
182
  }
185
183
 
184
+ #handleItemMutation = (mutations) => {
185
+ if (!mutations || mutations.length === 0) return;
186
+ if (this._updateOverflowItemsRequested) return;
187
+
188
+ let isWidthModifyingMutation = false;
189
+ for (const mutation of mutations) {
190
+ if (mutation.attributeName
191
+ && (mutation.attributeName === 'selected' || mutation.attributeName === 'text')
192
+ ) {
193
+ isWidthModifyingMutation = true;
194
+ break;
195
+ }
196
+ }
197
+
198
+ this._updateOverflowItemsRequested = true;
199
+ setTimeout(() => {
200
+ this._overflowItems = this._slotItems.map((node) => this.convertToOverflowItem(node));
201
+
202
+ // when certain attributes change the corresponding item width can also change and so we need to re-get the layouts and chomp
203
+ if (isWidthModifyingMutation) {
204
+ this._itemLayouts = this._getItemLayouts(this._slotItems);
205
+ this._chomp();
206
+ }
207
+ this._updateOverflowItemsRequested = false;
208
+ this.requestUpdate();
209
+ }, 0);
210
+ };
211
+
212
+ #handleResize = async(entries) => {
213
+ await (document.fonts ? document.fonts.ready : Promise.resolve()); // computed widths can be incorrect if we don't wait for fonts to load
214
+ this._availableWidth = Math.ceil(entries[0].contentRect.width);
215
+
216
+ if (!this._hasResized) {
217
+ this._hasResized = true;
218
+ this._handleSlotChange();
219
+ } else {
220
+ this._chomp();
221
+ }
222
+ };
223
+
186
224
  _autoDetectBoundaries(items) {
187
225
  if (!items) return;
188
226
 
@@ -335,46 +373,6 @@ export const OverflowGroupMixin = superclass => class extends LocalizeCoreElemen
335
373
  return filteredNodes;
336
374
  }
337
375
 
338
- _handleItemMutation(mutations) {
339
- if (!mutations || mutations.length === 0) return;
340
- if (this._updateOverflowItemsRequested) return;
341
-
342
- let isWidthModifyingMutation = false;
343
- for (const mutation of mutations) {
344
- if (mutation.attributeName
345
- && (mutation.attributeName === 'selected' || mutation.attributeName === 'text')
346
- ) {
347
- isWidthModifyingMutation = true;
348
- break;
349
- }
350
- }
351
-
352
- this._updateOverflowItemsRequested = true;
353
- setTimeout(() => {
354
- this._overflowItems = this._slotItems.map((node) => this.convertToOverflowItem(node));
355
-
356
- // when certain attributes change the corresponding item width can also change and so we need to re-get the layouts and chomp
357
- if (isWidthModifyingMutation) {
358
- this._itemLayouts = this._getItemLayouts(this._slotItems);
359
- this._chomp();
360
- }
361
- this._updateOverflowItemsRequested = false;
362
- this.requestUpdate();
363
- }, 0);
364
- }
365
-
366
- async _handleResize(entries) {
367
- await (document.fonts ? document.fonts.ready : Promise.resolve()); // computed widths can be incorrect if we don't wait for fonts to load
368
- this._availableWidth = Math.ceil(entries[0].contentRect.width);
369
-
370
- if (!this._hasResized) {
371
- this._hasResized = true;
372
- this._handleSlotChange();
373
- } else {
374
- this._chomp();
375
- }
376
- }
377
-
378
376
  _handleSlotChange() {
379
377
  if (!this._hasResized) return;
380
378
  requestAnimationFrame(async() => {
@@ -111,11 +111,15 @@ class Page extends ProviderMixin(LocalizeCoreElement(LitElement)) {
111
111
  }
112
112
 
113
113
  .content {
114
+ box-sizing: border-box;
114
115
  display: flex;
115
116
  margin-inline: var(--d2l-page-margin-inline, 0);
116
117
  max-width: var(--d2l-page-content-max-width, 100%);
117
118
  padding-bottom: var(--d2l-page-footer-height, 0); /* Reserve space for fixed footer */
118
119
  }
120
+ .content.has-panels {
121
+ min-height: calc(100vh - var(--d2l-page-header-height-measured, 0px));
122
+ }
119
123
 
120
124
  main {
121
125
  flex: 1;
@@ -124,7 +128,7 @@ class Page extends ProviderMixin(LocalizeCoreElement(LitElement)) {
124
128
 
125
129
  .side-nav-panel,
126
130
  .supporting-panel {
127
- height: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0));
131
+ max-height: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0));
128
132
  overflow: clip auto;
129
133
  position: sticky;
130
134
  top: var(--d2l-page-header-height, 0);
@@ -166,6 +170,7 @@ class Page extends ProviderMixin(LocalizeCoreElement(LitElement)) {
166
170
  for (const entry of entries) {
167
171
  if (entry.target.classList.contains('header')) {
168
172
  this._headerHeight = entry.target.offsetHeight;
173
+ this.style.setProperty('--d2l-page-header-height-measured', `${this._headerHeight}px`);
169
174
 
170
175
  const height = this._headerIsSticky ? this._headerHeight : 0;
171
176
  this.style.setProperty('--d2l-page-header-height', `${height}px`);
@@ -216,11 +221,15 @@ class Page extends ProviderMixin(LocalizeCoreElement(LitElement)) {
216
221
  'page': true,
217
222
  'header-sticky': this._headerIsSticky
218
223
  };
224
+ const contentClasses = {
225
+ 'content': true,
226
+ 'has-panels': this._slotVisibility['side-nav'] || this._slotVisibility['supporting']
227
+ };
219
228
 
220
229
  return html`
221
230
  <div class="${classMap(pageClasses)}">
222
231
  ${this.#renderHeader()}
223
- <div class="content">
232
+ <div class="${classMap(contentClasses)}">
224
233
  ${this.#renderSideNavPanel()}
225
234
  <main><slot></slot></main>
226
235
  ${this.#renderSupportingPanel()}
@@ -168,9 +168,7 @@ class ScrollWrapper extends LocalizeCoreElement(LitElement) {
168
168
  this._scrollbarRight = false;
169
169
  this._syncDriver = null;
170
170
  this._syncDriverTimeout = null;
171
- this._checkScrollThresholds = this._checkScrollThresholds.bind(this);
172
171
 
173
- this._synchronizeScroll = this._synchronizeScroll.bind(this);
174
172
  }
175
173
 
176
174
  disconnectedCallback() {
@@ -218,7 +216,7 @@ class ScrollWrapper extends LocalizeCoreElement(LitElement) {
218
216
  checkScrollbar() {
219
217
  if (!this._container) return;
220
218
  this._hScrollbar = this._container.offsetWidth !== this._container.scrollWidth;
221
- this._checkScrollThresholds();
219
+ this.#checkScrollThresholds();
222
220
  }
223
221
 
224
222
  notifyResize() {
@@ -237,13 +235,24 @@ class ScrollWrapper extends LocalizeCoreElement(LitElement) {
237
235
  }
238
236
  }
239
237
 
240
- _checkScrollThresholds() {
238
+ #checkScrollThresholds = () => {
241
239
  if (!this._container) return;
242
240
  const lowerScrollValue = this._container.scrollWidth - this._baseContainer.offsetWidth - Math.abs(this._container.scrollLeft);
243
241
  this._scrollbarLeft = (this._container.scrollLeft === 0);
244
242
  this._scrollbarRight = (lowerScrollValue <= 0);
245
243
 
246
- }
244
+ };
245
+
246
+ #synchronizeScroll = (e) => {
247
+ if (this._syncDriver && e.target !== this._syncDriver) return;
248
+ if (this._syncDriverTimeout) clearTimeout(this._syncDriverTimeout);
249
+
250
+ this._syncDriver = e.target;
251
+ this._allScrollers.forEach(element => {
252
+ if (element && element !== e.target) element.scrollLeft = e.target.scrollLeft;
253
+ });
254
+ this._syncDriverTimeout = setTimeout(() => this._syncDriver = null, 100);
255
+ };
247
256
 
248
257
  _disconnectAll() {
249
258
  this._resizeObserver?.disconnect();
@@ -252,11 +261,11 @@ class ScrollWrapper extends LocalizeCoreElement(LitElement) {
252
261
  this._container.style.removeProperty('overflow-x');
253
262
  this._container.classList.remove('d2l-scroll-wrapper-focus');
254
263
  this._container.removeAttribute('tabindex');
255
- this._container.removeEventListener('scroll', this._synchronizeScroll);
256
- this._container.removeEventListener('scroll', this._checkScrollThresholds);
264
+ this._container.removeEventListener('scroll', this.#synchronizeScroll);
265
+ this._container.removeEventListener('scroll', this.#checkScrollThresholds);
257
266
  this._secondaryScrollers.forEach(element => {
258
267
  element.style.removeProperty('overflow-x');
259
- element.removeEventListener('scroll', this._synchronizeScroll);
268
+ element.removeEventListener('scroll', this.#synchronizeScroll);
260
269
  });
261
270
  }
262
271
  }
@@ -276,17 +285,6 @@ class ScrollWrapper extends LocalizeCoreElement(LitElement) {
276
285
  this.scrollDistance(scrollDistance, true);
277
286
  }
278
287
 
279
- _synchronizeScroll(e) {
280
- if (this._syncDriver && e.target !== this._syncDriver) return;
281
- if (this._syncDriverTimeout) clearTimeout(this._syncDriverTimeout);
282
-
283
- this._syncDriver = e.target;
284
- this._allScrollers.forEach(element => {
285
- if (element && element !== e.target) element.scrollLeft = e.target.scrollLeft;
286
- });
287
- this._syncDriverTimeout = setTimeout(() => this._syncDriver = null, 100);
288
- }
289
-
290
288
  _updateScrollTargets() {
291
289
  this._disconnectAll();
292
290
 
@@ -307,17 +305,17 @@ class ScrollWrapper extends LocalizeCoreElement(LitElement) {
307
305
  }
308
306
  this._container.style.overflowX = 'auto';
309
307
  this._resizeObserver.observe(this._container);
310
- this._container.addEventListener('scroll', this._checkScrollThresholds);
308
+ this._container.addEventListener('scroll', this.#checkScrollThresholds);
311
309
  this._updateTabIndex();
312
310
  }
313
311
 
314
312
  if (this._secondaryScrollers.length) {
315
313
  this._secondaryScrollers.forEach(element => {
316
314
  element.style.overflowX = 'hidden';
317
- element.addEventListener('scroll', this._synchronizeScroll);
315
+ element.addEventListener('scroll', this.#synchronizeScroll);
318
316
  });
319
- this._container.addEventListener('scroll', this._synchronizeScroll);
320
- this._synchronizeScroll({ target: this._container });
317
+ this._container.addEventListener('scroll', this.#synchronizeScroll);
318
+ this.#synchronizeScroll({ target: this._container });
321
319
  }
322
320
  }
323
321
 
@@ -6489,7 +6489,7 @@
6489
6489
  {
6490
6490
  "name": "styles",
6491
6491
  "type": "CSSResult",
6492
- "default": "\"css`\\n\\t\\t:host {\\n\\t\\t\\t--d2l-page-header-max-width: 1230px;\\n\\t\\t\\t--d2l-page-content-max-width: 1230px;\\n\\t\\t\\t--d2l-page-footer-max-width: 1230px;\\n\\t\\t\\t--d2l-page-margin-inline: auto;\\n\\t\\t\\t--d2l-page-padding: 30px;\\n\\t\\t}\\n\\n\\t\\t:host([width-type=\\\"wide\\\"]) {\\n\\t\\t\\t--d2l-page-header-max-width: 1440px;\\n\\t\\t\\t--d2l-page-content-max-width: 1440px;\\n\\t\\t\\t--d2l-page-footer-max-width: 1440px;\\n\\t\\t}\\n\\n\\t\\t:host([width-type=\\\"fullscreen\\\"]) {\\n\\t\\t\\t--d2l-page-header-max-width: 100%;\\n\\t\\t\\t--d2l-page-content-max-width: 100%;\\n\\t\\t\\t--d2l-page-footer-max-width: 100%;\\n\\t\\t}\\n\\n\\t\\t@media (max-width: 929px) {\\n\\t\\t\\t:host {\\n\\t\\t\\t\\t--d2l-page-padding: 24px;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\t@media (max-width: 767px) {\\n\\t\\t\\t:host {\\n\\t\\t\\t\\t--d2l-page-padding: 18px;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t.header {\\n\\t\\t\\tposition: relative;\\n\\t\\t\\tz-index: 15; /* To be over sticky content of our core components */\\n\\t\\t}\\n\\n\\t\\t.page.header-sticky .header {\\n\\t\\t\\tposition: sticky;\\n\\t\\t\\ttop: 0;\\n\\t\\t}\\n\\n\\t\\t.content {\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\tmargin-inline: var(--d2l-page-margin-inline, 0);\\n\\t\\t\\tmax-width: var(--d2l-page-content-max-width, 100%);\\n\\t\\t\\tpadding-bottom: var(--d2l-page-footer-height, 0); /* Reserve space for fixed footer */\\n\\t\\t}\\n\\n\\t\\tmain {\\n\\t\\t\\tflex: 1;\\n\\t\\t\\tmin-width: min(${MAIN_MIN_WIDTH}px, 100%);\\n\\t\\t}\\n\\n\\t\\t.side-nav-panel,\\n\\t\\t.supporting-panel {\\n\\t\\t\\theight: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0));\\n\\t\\t\\toverflow: clip auto;\\n\\t\\t\\tposition: sticky;\\n\\t\\t\\ttop: var(--d2l-page-header-height, 0);\\n\\t\\t}\\n\\n\\t\\t.footer:not([hidden]),\\n\\t\\t.floating-buttons-container {\\n\\t\\t\\tdisplay: inline;\\n\\t\\t}\\n\\t\\t.fixed-footer {\\n\\t\\t\\tbackground-color: white;\\n\\t\\t\\tbox-shadow: 0 -2px 4px rgba(32, 33, 34, 0.2); /* ferrite */\\n\\t\\t\\tinset: auto 0 0;\\n\\t\\t\\tpadding-block-start: 0.75rem;\\n\\t\\t\\tposition: fixed;\\n\\t\\t\\tz-index: 10; /* To be over sticky content of our core components */\\n\\t\\t}\\n\\t\\t.footer-contents {\\n\\t\\t\\tmargin-inline: var(--d2l-page-margin-inline, 0);\\n\\t\\t\\tmax-width: var(--d2l-page-footer-max-width, 100%);\\n\\t\\t}\\n\\t`\""
6492
+ "default": "\"css`\\n\\t\\t:host {\\n\\t\\t\\t--d2l-page-header-max-width: 1230px;\\n\\t\\t\\t--d2l-page-content-max-width: 1230px;\\n\\t\\t\\t--d2l-page-footer-max-width: 1230px;\\n\\t\\t\\t--d2l-page-margin-inline: auto;\\n\\t\\t\\t--d2l-page-padding: 30px;\\n\\t\\t}\\n\\n\\t\\t:host([width-type=\\\"wide\\\"]) {\\n\\t\\t\\t--d2l-page-header-max-width: 1440px;\\n\\t\\t\\t--d2l-page-content-max-width: 1440px;\\n\\t\\t\\t--d2l-page-footer-max-width: 1440px;\\n\\t\\t}\\n\\n\\t\\t:host([width-type=\\\"fullscreen\\\"]) {\\n\\t\\t\\t--d2l-page-header-max-width: 100%;\\n\\t\\t\\t--d2l-page-content-max-width: 100%;\\n\\t\\t\\t--d2l-page-footer-max-width: 100%;\\n\\t\\t}\\n\\n\\t\\t@media (max-width: 929px) {\\n\\t\\t\\t:host {\\n\\t\\t\\t\\t--d2l-page-padding: 24px;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\t@media (max-width: 767px) {\\n\\t\\t\\t:host {\\n\\t\\t\\t\\t--d2l-page-padding: 18px;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t.header {\\n\\t\\t\\tposition: relative;\\n\\t\\t\\tz-index: 15; /* To be over sticky content of our core components */\\n\\t\\t}\\n\\n\\t\\t.page.header-sticky .header {\\n\\t\\t\\tposition: sticky;\\n\\t\\t\\ttop: 0;\\n\\t\\t}\\n\\n\\t\\t.content {\\n\\t\\t\\tbox-sizing: border-box;\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\tmargin-inline: var(--d2l-page-margin-inline, 0);\\n\\t\\t\\tmax-width: var(--d2l-page-content-max-width, 100%);\\n\\t\\t\\tpadding-bottom: var(--d2l-page-footer-height, 0); /* Reserve space for fixed footer */\\n\\t\\t}\\n\\t\\t.content.has-panels {\\n\\t\\t\\tmin-height: calc(100vh - var(--d2l-page-header-height-measured, 0px));\\n\\t\\t}\\n\\n\\t\\tmain {\\n\\t\\t\\tflex: 1;\\n\\t\\t\\tmin-width: min(${MAIN_MIN_WIDTH}px, 100%);\\n\\t\\t}\\n\\n\\t\\t.side-nav-panel,\\n\\t\\t.supporting-panel {\\n\\t\\t\\tmax-height: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0));\\n\\t\\t\\toverflow: clip auto;\\n\\t\\t\\tposition: sticky;\\n\\t\\t\\ttop: var(--d2l-page-header-height, 0);\\n\\t\\t}\\n\\n\\t\\t.footer:not([hidden]),\\n\\t\\t.floating-buttons-container {\\n\\t\\t\\tdisplay: inline;\\n\\t\\t}\\n\\t\\t.fixed-footer {\\n\\t\\t\\tbackground-color: white;\\n\\t\\t\\tbox-shadow: 0 -2px 4px rgba(32, 33, 34, 0.2); /* ferrite */\\n\\t\\t\\tinset: auto 0 0;\\n\\t\\t\\tpadding-block-start: 0.75rem;\\n\\t\\t\\tposition: fixed;\\n\\t\\t\\tz-index: 10; /* To be over sticky content of our core components */\\n\\t\\t}\\n\\t\\t.footer-contents {\\n\\t\\t\\tmargin-inline: var(--d2l-page-margin-inline, 0);\\n\\t\\t\\tmax-width: var(--d2l-page-footer-max-width, 100%);\\n\\t\\t}\\n\\t`\""
6493
6493
  },
6494
6494
  {
6495
6495
  "name": "widthType",
@@ -14,26 +14,25 @@ export const RtlMixin = dedupeMixin(superclass => class extends superclass {
14
14
  constructor() {
15
15
  super();
16
16
  this._localeSettings = getDocumentLocaleSettings();
17
- this._handleLanguageChange = this._handleLanguageChange.bind(this);
18
- this._handleLanguageChange();
17
+ this.#handleLanguageChange();
19
18
  }
20
19
 
21
20
  connectedCallback() {
22
21
  super.connectedCallback();
23
- this._localeSettings.addChangeListener(this._handleLanguageChange);
22
+ this._localeSettings.addChangeListener(this.#handleLanguageChange);
24
23
  }
25
24
 
26
25
  disconnectedCallback() {
27
26
  super.disconnectedCallback();
28
- this._localeSettings.removeChangeListener(this._handleLanguageChange);
27
+ this._localeSettings.removeChangeListener(this.#handleLanguageChange);
29
28
  }
30
29
 
31
- _handleLanguageChange() {
30
+ #handleLanguageChange = () => {
32
31
  const dir = document.documentElement.getAttribute('dir');
33
32
  // avoid reflecting "ltr" for better performance
34
33
  if (dir && (dir !== 'ltr' || this.dir === 'rtl')) {
35
34
  this.dir = dir;
36
35
  }
37
- }
36
+ };
38
37
 
39
38
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.269.4",
3
+ "version": "3.269.5",
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",