@brightspace-ui/core 3.88.3 → 3.89.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.
@@ -63,7 +63,7 @@ export const PopoverMixin = superclass => class extends superclass {
63
63
  --d2l-popover-default-border-color: var(--d2l-color-mica);
64
64
  --d2l-popover-default-border-radius: 0.3rem;
65
65
  --d2l-popover-default-foreground-color: var(--d2l-color-ferrite);
66
- --d2l-popover-default-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.15);
66
+ --d2l-popover-default-shadow-color: rgba(0, 0, 0, 0.15);
67
67
  background-color: transparent; /* override popover default */
68
68
  border: none; /* override popover */
69
69
  box-sizing: border-box;
@@ -75,8 +75,17 @@ export const PopoverMixin = superclass => class extends superclass {
75
75
  overflow: visible; /* override popover */
76
76
  padding: 0; /* override popover */
77
77
  position: fixed; /* normalize popover */
78
+ text-align: start;
78
79
  width: fit-content; /* normalize popover */
79
80
  }
81
+ :host([theme="dark"]) {
82
+ --d2l-popover-default-animation-name: d2l-popover-animation-dark;
83
+ --d2l-popover-default-background-color: #333536; /* tungsten @ 70% */
84
+ --d2l-popover-default-border-color: var(--d2l-color-tungsten);
85
+ --d2l-popover-default-foreground-color: var(--d2l-color-sylvite);
86
+ --d2l-popover-default-shadow-color: rgba(0, 0, 0, 1);
87
+ opacity: 0.9;
88
+ }
80
89
  :host([hidden]) {
81
90
  display: none;
82
91
  }
@@ -99,8 +108,9 @@ export const PopoverMixin = superclass => class extends superclass {
99
108
  background-color: var(--d2l-popover-background-color, var(--d2l-popover-default-background-color));
100
109
  border: 1px solid var(--d2l-popover-border-color, var(--d2l-popover-default-border-color));
101
110
  border-radius: var(--d2l-popover-border-radius, var(--d2l-popover-default-border-radius));
102
- box-shadow: var(--d2l-popover-shadow, var(--d2l-popover-default-shadow));
111
+ box-shadow: 0 2px 12px 0 var(--d2l-popover-shadow-color, var(--d2l-popover-default-shadow-color));
103
112
  box-sizing: border-box;
113
+ display: flex;
104
114
  max-width: 370px;
105
115
  min-width: 70px;
106
116
  width: 100vw;
@@ -109,6 +119,7 @@ export const PopoverMixin = superclass => class extends superclass {
109
119
  box-sizing: border-box;
110
120
  display: inline-block;
111
121
  max-width: 100%;
122
+ min-width: inherit;
112
123
  outline: none;
113
124
  overflow-y: auto;
114
125
  }
@@ -142,6 +153,10 @@ export const PopoverMixin = superclass => class extends superclass {
142
153
  0% { opacity: 0; transform: translate(0, -10px); }
143
154
  100% { opacity: 1; transform: translate(0, 0); }
144
155
  }
156
+ @keyframes d2l-popover-animation-dark {
157
+ 0% { opacity: 0; transform: translate(0, -10px); }
158
+ 100% { opacity: 0.9; transform: translate(0, 0); }
159
+ }
145
160
  @media (prefers-reduced-motion: no-preference) {
146
161
  :host([_opened]) {
147
162
  animation: var(--d2l-popover-animation-name, var(--d2l-popover-default-animation-name)) 300ms ease;
@@ -259,6 +274,8 @@ export const PopoverMixin = superclass => class extends superclass {
259
274
 
260
275
  await this.updateComplete; // wait before applying focus to opener
261
276
  this.#focusOpener();
277
+
278
+ /** @ignore */
262
279
  this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
263
280
 
264
281
  }
@@ -290,7 +307,7 @@ export const PopoverMixin = superclass => class extends superclass {
290
307
  this._trapFocus = properties?.trapFocus ?? false;
291
308
  }
292
309
 
293
- async open(applyFocus = true) {
310
+ async open(opener, applyFocus = true) {
294
311
  if (this._opened) return;
295
312
 
296
313
  const ifrauBackdropService = await tryGetIfrauBackdropService();
@@ -306,10 +323,10 @@ export const PopoverMixin = superclass => class extends superclass {
306
323
 
307
324
  this._previousFocusableAncestor = getPreviousFocusableAncestor(this, false, false);
308
325
 
309
- this._opener = getComposedActiveElement();
326
+ this._opener = opener;
310
327
  this.#addAutoCloseHandlers();
311
328
 
312
- await this.#position();
329
+ await this.position();
313
330
 
314
331
  this._showBackdrop = this._mobile && this._mobileTrayLocation;
315
332
  if (ifrauBackdropService && this._showBackdrop) {
@@ -322,10 +339,99 @@ export const PopoverMixin = superclass => class extends superclass {
322
339
 
323
340
  this.#addRepositionHandlers();
324
341
 
342
+ /** @ignore */
325
343
  this.dispatchEvent(new CustomEvent('d2l-popover-open', { bubbles: true, composed: true }));
326
344
 
327
345
  }
328
346
 
347
+ async position(contentRect, options) {
348
+ if (!this._opener) return;
349
+
350
+ options = Object.assign({ updateLocation: true, updateHeight: true }, options);
351
+
352
+ const content = this.#getContentContainer();
353
+
354
+ if (!this._noAutoFit && options.updateHeight) {
355
+ this._contentHeight = null;
356
+ }
357
+
358
+ // don't let popover content horizontally overflow viewport
359
+ this._width = null;
360
+
361
+ await this.updateComplete;
362
+
363
+ const adjustPosition = async() => {
364
+
365
+ const scrollHeight = document.documentElement.scrollHeight;
366
+ const openerRect = this._opener.getBoundingClientRect();
367
+ contentRect = contentRect ?? content.getBoundingClientRect();
368
+
369
+ const height = this._minHeight ?? Math.min(this._maxHeight ?? Number.MAX_VALUE, contentRect.height);
370
+
371
+ const spaceRequired = {
372
+ height: height + 10,
373
+ width: contentRect.width
374
+ };
375
+
376
+ // space in viewport
377
+ const spaceAround = this.#constrainSpaceAround({
378
+ // allow for opener offset + outer margin
379
+ above: openerRect.top - this._offset - this._margin,
380
+ // allow for opener offset + outer margin
381
+ below: window.innerHeight - openerRect.bottom - this._offset - this._margin,
382
+ // allow for outer margin
383
+ left: openerRect.left - 20,
384
+ // allow for outer margin
385
+ right: document.documentElement.clientWidth - openerRect.right - 15
386
+ }, spaceRequired, openerRect);
387
+
388
+ // space in document
389
+ const spaceAroundScroll = this.#constrainSpaceAround({
390
+ above: openerRect.top + document.documentElement.scrollTop,
391
+ below: scrollHeight - openerRect.bottom - document.documentElement.scrollTop
392
+ }, spaceRequired, openerRect);
393
+
394
+ if (options.updateLocation) {
395
+ this._location = this.#getLocation(spaceAround, spaceAroundScroll, spaceRequired);
396
+ }
397
+
398
+ this._position = this.#getPosition(spaceAround, openerRect, contentRect);
399
+ if (!this._noPointer) this._pointerPosition = this.#getPointerPosition(openerRect);
400
+
401
+ if (options.updateHeight) {
402
+
403
+ // calculate height available to the popover contents for overflow because that is the only area capable of scrolling
404
+ const availableHeight = (this._location === 'block-start') ? spaceAround.above : spaceAround.below;
405
+
406
+ if (!this._noAutoFit && availableHeight && availableHeight > 0) {
407
+ // only apply maximum if it's less than space available and the header/footer alone won't exceed it (content must be visible)
408
+ this._contentHeight = this._maxHeight !== null && availableHeight > this._maxHeight
409
+ ? this._maxHeight - 2 : availableHeight;
410
+
411
+ // ensure the content height has updated when the __toggleScrollStyles event handler runs
412
+ await this.updateComplete;
413
+ }
414
+
415
+ // todo: handle inline-start and inline-end locations
416
+
417
+ }
418
+
419
+ /** @ignore */
420
+ this.dispatchEvent(new CustomEvent('d2l-popover-position', { bubbles: true, composed: true }));
421
+
422
+ };
423
+
424
+ const scrollWidth = content.scrollWidth;
425
+ const availableWidth = window.innerWidth - 40;
426
+
427
+ this._width = (availableWidth > scrollWidth ? scrollWidth : availableWidth);
428
+
429
+ await this.updateComplete;
430
+
431
+ await adjustPosition();
432
+
433
+ }
434
+
329
435
  renderPopover(content) {
330
436
 
331
437
  const mobileTrayLocation = this._mobile ? this._mobileTrayLocation : null;
@@ -392,12 +498,12 @@ export const PopoverMixin = superclass => class extends superclass {
392
498
  async resize() {
393
499
  if (!this._opened) return;
394
500
  this._showBackdrop = this._mobile && this._mobileTrayLocation;
395
- await this.#position();
501
+ await this.position();
396
502
  }
397
503
 
398
- toggleOpen(applyFocus = true) {
504
+ toggleOpen(opener, applyFocus = true) {
399
505
  if (this._opened) return this.close();
400
- else return this.open(!this._noAutoFocus && applyFocus);
506
+ else return this.open(opener, (!this._noAutoFocus && applyFocus));
401
507
  }
402
508
 
403
509
  #ifrauContextInfo;
@@ -864,7 +970,7 @@ export const PopoverMixin = superclass => class extends superclass {
864
970
  #handleFocusTrapEnter() {
865
971
  this.#focusContent(this.#getContentContainer());
866
972
 
867
- /** Dispatched when user focus enters the popover (trap-focus option only) */
973
+ /** @ignore */
868
974
  this.dispatchEvent(new CustomEvent('d2l-popover-focus-enter', { detail: { applyFocus: this._applyFocus } }));
869
975
  }
870
976
 
@@ -872,7 +978,7 @@ export const PopoverMixin = superclass => class extends superclass {
872
978
  this._mobile = this.#mediaQueryList.matches;
873
979
  if (this._opened) {
874
980
  this._showBackdrop = this._mobile && this._mobileTrayLocation;
875
- await this.#position();
981
+ await this.position();
876
982
  }
877
983
  }
878
984
 
@@ -880,94 +986,6 @@ export const PopoverMixin = superclass => class extends superclass {
880
986
  this.resize();
881
987
  }
882
988
 
883
- async #position(contentRect, options) {
884
- if (!this._opener) return;
885
-
886
- options = Object.assign({ updateLocation: true, updateHeight: true }, options);
887
-
888
- const content = this.#getContentContainer();
889
-
890
- if (!this._noAutoFit && options.updateHeight) {
891
- this._contentHeight = null;
892
- }
893
-
894
- // don't let popover content horizontally overflow viewport
895
- this._width = null;
896
-
897
- await this.updateComplete;
898
-
899
- const adjustPosition = async() => {
900
-
901
- const scrollHeight = document.documentElement.scrollHeight;
902
- const openerRect = this._opener.getBoundingClientRect();
903
- contentRect = contentRect ?? content.getBoundingClientRect();
904
-
905
- const height = this._minHeight ?? Math.min(this._maxHeight ?? Number.MAX_VALUE, contentRect.height);
906
-
907
- const spaceRequired = {
908
- height: height + 10,
909
- width: contentRect.width
910
- };
911
-
912
- // space in viewport
913
- const spaceAround = this.#constrainSpaceAround({
914
- // allow for opener offset + outer margin
915
- above: openerRect.top - this._offset - this._margin,
916
- // allow for opener offset + outer margin
917
- below: window.innerHeight - openerRect.bottom - this._offset - this._margin,
918
- // allow for outer margin
919
- left: openerRect.left - 20,
920
- // allow for outer margin
921
- right: document.documentElement.clientWidth - openerRect.right - 15
922
- }, spaceRequired, openerRect);
923
-
924
- // space in document
925
- const spaceAroundScroll = this.#constrainSpaceAround({
926
- above: openerRect.top + document.documentElement.scrollTop,
927
- below: scrollHeight - openerRect.bottom - document.documentElement.scrollTop
928
- }, spaceRequired, openerRect);
929
-
930
- if (options.updateLocation) {
931
- this._location = this.#getLocation(spaceAround, spaceAroundScroll, spaceRequired);
932
- }
933
-
934
- this._position = this.#getPosition(spaceAround, openerRect, contentRect);
935
- if (!this._noPointer) this._pointerPosition = this.#getPointerPosition(openerRect);
936
-
937
- if (options.updateHeight) {
938
-
939
- // calculate height available to the popover contents for overflow because that is the only area capable of scrolling
940
- const availableHeight = (this._location === 'block-start') ? spaceAround.above : spaceAround.below;
941
-
942
- if (!this._noAutoFit && availableHeight && availableHeight > 0) {
943
- // only apply maximum if it's less than space available and the header/footer alone won't exceed it (content must be visible)
944
- this._contentHeight = this._maxHeight !== null && availableHeight > this._maxHeight
945
- ? this._maxHeight - 2 : availableHeight;
946
-
947
- // ensure the content height has updated when the __toggleScrollStyles event handler runs
948
- await this.updateComplete;
949
- }
950
-
951
- // todo: handle inline-start and inline-end locations
952
-
953
- }
954
-
955
- /** Dispatched when the popover position finishes adjusting */
956
- this.dispatchEvent(new CustomEvent('d2l-popover-position', { bubbles: true, composed: true }));
957
-
958
- };
959
-
960
- const scrollWidth = content.scrollWidth;
961
- const availableWidth = window.innerWidth - 40;
962
-
963
- this._width = (availableWidth > scrollWidth ? scrollWidth : availableWidth);
964
-
965
- await this.updateComplete;
966
-
967
- await adjustPosition();
968
-
969
- }
970
-
971
989
  #removeAutoCloseHandlers() {
972
990
  this.removeEventListener('blur', this.#handleAutoCloseFocusBound, { capture: true });
973
991
  document.body?.removeEventListener('focus', this.#handleAutoCloseFocusBound, { capture: true }); // DE41322: document.body can be null in some scenarios
@@ -979,7 +997,9 @@ export const PopoverMixin = superclass => class extends superclass {
979
997
  }
980
998
 
981
999
  #removeRepositionHandlers() {
982
- this._openerIntersectionObserver?.unobserve(this._opener);
1000
+ if (this._opener) {
1001
+ this._openerIntersectionObserver?.unobserve(this._opener);
1002
+ }
983
1003
  this._scrollablesObserved?.forEach(node => {
984
1004
  node.removeEventListener('scroll', this.#repositionBound);
985
1005
  });
@@ -992,7 +1012,7 @@ export const PopoverMixin = superclass => class extends superclass {
992
1012
  // throttle repositioning (https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event#scroll_event_throttling)
993
1013
  if (!this._repositioning) {
994
1014
  requestAnimationFrame(() => {
995
- this.#position(undefined, { updateLocation: false, updateHeight: false });
1015
+ this.position(undefined, { updateLocation: false, updateHeight: false });
996
1016
  this._repositioning = false;
997
1017
  });
998
1018
  }
@@ -2,7 +2,6 @@ import '../colors/colors.js';
2
2
  import { css, html, LitElement, unsafeCSS } from 'lit';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
4
  import { getFocusPseudoClass } from '../../helpers/focus.js';
5
- import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
6
5
  import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
7
6
 
8
7
  const keyCodes = {
@@ -10,7 +9,7 @@ const keyCodes = {
10
9
  SPACE: 32
11
10
  };
12
11
 
13
- class Tab extends SkeletonMixin(RtlMixin(LitElement)) {
12
+ class Tab extends SkeletonMixin(LitElement) {
14
13
 
15
14
  static get properties() {
16
15
  return {
@@ -44,11 +43,7 @@ class Tab extends SkeletonMixin(RtlMixin(LitElement)) {
44
43
  top: 0.15rem;
45
44
  }
46
45
  :host(:first-child) .d2l-tab-text {
47
- margin-left: 0;
48
- }
49
- :host([dir="rtl"]:first-child) .d2l-tab-text {
50
- margin-left: 0.6rem;
51
- margin-right: 0;
46
+ margin-inline-start: 0;
52
47
  }
53
48
  .d2l-tab-selected-indicator {
54
49
  border-top: 4px solid var(--d2l-color-celestine);
@@ -69,13 +64,9 @@ class Tab extends SkeletonMixin(RtlMixin(LitElement)) {
69
64
  min-width: 50px;
70
65
  }
71
66
  :host(:first-child) .d2l-tab-selected-indicator {
72
- margin-left: 0;
67
+ margin-inline-start: 0;
73
68
  width: calc(100% - 0.6rem);
74
69
  }
75
- :host([dir="rtl"]:first-child) .d2l-tab-selected-indicator {
76
- margin-left: 0.6rem;
77
- margin-right: 0;
78
- }
79
70
  :host(:${unsafeCSS(getFocusPseudoClass())}) > .d2l-tab-text {
80
71
  border-radius: 0.3rem;
81
72
  box-shadow: 0 0 0 2px var(--d2l-color-celestine);
@@ -37,7 +37,6 @@ export const TabMixin = superclass => class extends SkeletonMixin(superclass) {
37
37
  width: calc(100% - 1.2rem);
38
38
  }
39
39
  :host(:first-child) .d2l-tab-selected-indicator {
40
- margin-inline-end: 0.6rem;
41
40
  margin-inline-start: 0;
42
41
  width: calc(100% - 0.6rem);
43
42
  }
@@ -15,7 +15,6 @@ class Tab extends TabMixin(LitElement) {
15
15
  white-space: nowrap;
16
16
  }
17
17
  :host(:first-child) .d2l-tab-text {
18
- margin-inline-end: 0.6rem;
19
18
  margin-inline-start: 0;
20
19
  }
21
20
  :host(:${unsafeCSS(getFocusPseudoClass())}) > .d2l-tab-text {
@@ -11,7 +11,6 @@ import { getFocusPseudoClass } from '../../helpers/focus.js';
11
11
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
12
12
  import { repeat } from 'lit/directives/repeat.js';
13
13
  import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
14
- import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
15
14
  import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
16
15
  import { styleMap } from 'lit/directives/style-map.js';
17
16
 
@@ -19,41 +18,13 @@ const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
19
18
 
20
19
  const scrollButtonWidth = 56;
21
20
 
22
- // remove once IE11 is no longer supported
23
- if (!Array.prototype.findIndex) {
24
- Object.defineProperty(Array.prototype, 'findIndex', {
25
- value: function(predicate) {
26
-
27
- if (this === null) throw new TypeError('"this" is null or not defined');
28
-
29
- const o = Object(this);
30
- const len = o.length >>> 0;
31
-
32
- if (typeof predicate !== 'function') throw new TypeError('predicate must be a function');
33
-
34
- const thisArg = arguments[1];
35
- let k = 0;
36
-
37
- while (k < len) {
38
- const kValue = o[k];
39
- if (predicate.call(thisArg, kValue, k, o)) return k;
40
- k++;
41
- }
42
-
43
- return -1;
44
- },
45
- configurable: true,
46
- writable: true
47
- });
48
- }
49
-
50
21
  /**
51
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.
52
23
  * @slot - Contains the tab panels (e.g., "d2l-tab-panel" components)
53
24
  * @slot ext - Additional content (e.g., a button) positioned at right
54
25
  * @fires d2l-tabs-initialized - Dispatched when the component is initialized
55
26
  */
56
- class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(LitElement)))) {
27
+ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(LitElement))) {
57
28
 
58
29
  static get properties() {
59
30
  return {
@@ -113,11 +84,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
113
84
  }
114
85
  .d2l-tabs-container-ext {
115
86
  flex: none;
116
- padding-left: 4px;
117
- }
118
- :host([dir="rtl"]) .d2l-tabs-container-ext {
119
- padding-left: 0;
120
- padding-right: 4px;
87
+ padding-inline: 4px 0;
121
88
  }
122
89
  .d2l-tabs-container-list {
123
90
  display: block;
@@ -136,27 +103,15 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
136
103
  z-index: 1;
137
104
  }
138
105
  .d2l-tabs-scroll-previous-container {
139
- left: 0;
140
- margin-left: 4px;
141
- }
142
- :host([dir="rtl"]) .d2l-tabs-scroll-previous-container {
143
- left: auto;
144
- margin-left: 0;
145
- margin-right: 4px;
146
- right: 0;
106
+ inset-inline-start: 0;
107
+ margin-inline: 4px 0;
147
108
  }
148
109
  .d2l-tabs-container[data-allow-scroll-previous] > .d2l-tabs-scroll-previous-container {
149
110
  display: inline-block;
150
111
  }
151
112
  .d2l-tabs-scroll-next-container {
152
- margin-right: 4px;
153
- right: 0;
154
- }
155
- :host([dir="rtl"]) .d2l-tabs-scroll-next-container {
156
- left: 0;
157
- margin-left: 4px;
158
- margin-right: 0;
159
- right: auto;
113
+ inset-inline-end: 0;
114
+ margin-inline: 0 4px;
160
115
  }
161
116
  .d2l-tabs-container[data-allow-scroll-next] > .d2l-tabs-scroll-next-container {
162
117
  display: inline-block;
@@ -290,7 +245,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
290
245
  const measures = this._getMeasures();
291
246
  const newTranslationValue = this._calculateScrollPosition(tabInfo, measures);
292
247
 
293
- if (this.dir !== 'rtl') {
248
+ if (!this.#isRTL()) {
294
249
  if (newTranslationValue >= 0) return;
295
250
  } else {
296
251
  if (newTranslationValue <= 0) return;
@@ -434,8 +389,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
434
389
  const isOverflowingLeft = (selectedTabMeasures.offsetLeft + this._translationValue < 0);
435
390
  const isOverflowingRight = (selectedTabMeasures.offsetLeft + selectedTabMeasures.rect.width + this._translationValue > measures.tabsContainerRect.width);
436
391
 
392
+ const isRTL = this.#isRTL();
393
+
437
394
  let getNewTranslationValue;
438
- if (this.dir !== 'rtl') {
395
+ if (!isRTL) {
439
396
  getNewTranslationValue = () => {
440
397
  if (selectedTabIndex === 0) {
441
398
  // position selected tab at beginning
@@ -471,7 +428,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
471
428
  let expectedPosition;
472
429
 
473
430
  // make sure the new position will not place selected tab behind left scroll button
474
- if (this.dir !== 'rtl') {
431
+ if (!isRTL) {
475
432
  expectedPosition = selectedTabMeasures.offsetLeft + newTranslationValue;
476
433
  if (newTranslationValue < 0 && this._isPositionInLeftScrollArea(expectedPosition)) {
477
434
  newTranslationValue = getNewTranslationValue();
@@ -483,7 +440,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
483
440
  }
484
441
  }
485
442
 
486
- if (this.dir !== 'rtl') {
443
+ if (!isRTL) {
487
444
  // make sure there will not be any empty space between left side of container and first tab
488
445
  if (newTranslationValue > 0) newTranslationValue = 0;
489
446
  } else {
@@ -492,7 +449,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
492
449
  }
493
450
 
494
451
  // make sure the new position will not place selected tab behind the right scroll button
495
- if (this.dir !== 'rtl') {
452
+ if (!isRTL) {
496
453
  expectedPosition = selectedTabMeasures.offsetLeft + selectedTabMeasures.rect.width + newTranslationValue;
497
454
  if ((selectedTabIndex < this._tabInfos.length - 1) && this._isPositionInRightScrollArea(expectedPosition, measures)) {
498
455
  newTranslationValue = getNewTranslationValue();
@@ -556,13 +513,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
556
513
  }
557
514
 
558
515
  _getTabInfo(id) {
559
- if (this._tabInfos.find) {
560
- return this._tabInfos.find((t) => t.id === id);
561
- } else {
562
- // IE11
563
- const index = this._tabInfos.findIndex((t) => t.id === id);
564
- return index !== -1 ? this._tabInfos[index] : null;
565
- }
516
+ return this._tabInfos.find((t) => t.id === id);
566
517
  }
567
518
 
568
519
  _handleFocusOut(e) {
@@ -695,7 +646,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
695
646
  const lastTabMeasures = measures.tabRects[measures.tabRects.length - 1];
696
647
  let isOverflowingNext;
697
648
 
698
- if (this.dir !== 'rtl') {
649
+ if (!this.#isRTL()) {
699
650
 
700
651
  newTranslationValue = (this._translationValue - measures.tabsContainerRect.width + scrollButtonWidth);
701
652
  if (newTranslationValue < 0) newTranslationValue += scrollButtonWidth;
@@ -738,7 +689,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
738
689
  let newTranslationValue;
739
690
  let isOverflowingPrevious;
740
691
 
741
- if (this.dir !== 'rtl') {
692
+ if (!this.#isRTL()) {
742
693
 
743
694
  newTranslationValue = (this._translationValue + measures.tabsContainerRect.width - scrollButtonWidth);
744
695
  isOverflowingPrevious = (newTranslationValue < 0);
@@ -921,7 +872,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
921
872
  return Promise.resolve();
922
873
  }
923
874
 
924
- if (this.dir !== 'rtl') {
875
+ if (!this.#isRTL()) {
925
876
  // show/hide scroll buttons
926
877
  this._allowScrollPrevious = (this._translationValue < 0);
927
878
  this._allowScrollNext = (lastTabMeasures.offsetLeft + lastTabMeasures.rect.width + this._translationValue > measures.tabsContainerRect.width);
@@ -986,6 +937,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(SkeletonMixin(RtlMixin(Lit
986
937
  return this.updateComplete;
987
938
  }
988
939
 
940
+ #isRTL() {
941
+ return document.documentElement.getAttribute('dir') === 'rtl';
942
+ }
943
+
989
944
  }
990
945
 
991
946
  customElements.define('d2l-tabs', Tabs);