@brightspace-ui/core 2.0.3 → 2.1.1

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.
@@ -124,7 +124,12 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
124
124
  }
125
125
 
126
126
  resize() {
127
- return this._updateSize();
127
+ return new Promise(resolve => {
128
+ setTimeout(async() => {
129
+ await this._updateSize();
130
+ resolve();
131
+ }, 0);
132
+ });
128
133
  }
129
134
 
130
135
  _addHandlers() {
@@ -330,7 +335,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
330
335
  // focus first focusable child prior to auto resize (fixes screen reader hiccups)
331
336
  this._focusInitial();
332
337
 
333
- requestAnimationFrame(async() => {
338
+ setTimeout(async() => {
334
339
 
335
340
  this.shadowRoot.querySelector('.d2l-dialog-content').scrollTop = 0;
336
341
  // scrollbar is kept hidden while we update the scroll position to avoid scrollbar flash
@@ -340,6 +345,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
340
345
 
341
346
  await this._updateSize();
342
347
  this._state = 'showing';
348
+ await this._updateComplete;
343
349
 
344
350
  // edge case: no children were focused, try again after one redraw
345
351
  const activeElement = getComposedActiveElement();
@@ -354,7 +360,7 @@ export const DialogMixin = superclass => class extends RtlMixin(superclass) {
354
360
  this.dispatchEvent(new CustomEvent(
355
361
  'd2l-dialog-open', { bubbles: true, composed: true }
356
362
  ));
357
- });
363
+ }, 0);
358
364
 
359
365
  }
360
366
 
@@ -11,6 +11,15 @@ export const dialogStyles = css`
11
11
  display: block;
12
12
  }
13
13
 
14
+ :host([opened]:not([_state="showing"])) {
15
+ visibility: hidden;
16
+ }
17
+
18
+ :host([opened][_state="showing"]),
19
+ :host([opened][_state="hiding"]) {
20
+ visibility: visible;
21
+ }
22
+
14
23
  .d2l-dialog-outer {
15
24
  background-color: white;
16
25
  border: 1px solid var(--d2l-color-mica);
@@ -19,20 +19,26 @@
19
19
 
20
20
  <div style="margin-bottom: 30px;">
21
21
  <d2l-button-subtle id="add" text="Add"></d2l-button-subtle>
22
+ <d2l-button-subtle id="add-selected" text="Add Selected"></d2l-button-subtle>
22
23
  <d2l-button-subtle id="remove" text="Remove"></d2l-button-subtle>
23
24
  </div>
24
25
  <script>
25
26
  let newPanelId = 0;
26
- document.querySelector('#add').addEventListener('click', () => {
27
+ const addPanel = selected => {
27
28
  newPanelId += 1;
28
29
  const panel = document.createElement('d2l-tab-panel');
30
+ panel.selected = selected;
29
31
  panel.text = `New Panel ${newPanelId}`;
30
32
  panel.textContent = `Content for new panel ${newPanelId}`;
31
33
  const tabs = document.querySelector('d2l-tabs');
32
34
  const panels = [...tabs.querySelectorAll('d2l-tab-panel')];
33
35
  if (panels.length < 2) tabs.appendChild(panel);
34
36
  else tabs.insertBefore(panel, panels[1]);
35
- });
37
+ };
38
+
39
+ document.querySelector('#add').addEventListener('click', () => addPanel(false));
40
+ document.querySelector('#add-selected').addEventListener('click', () => addPanel(true));
41
+
36
42
  document.querySelector('#remove').addEventListener('click', () => {
37
43
  const tabs = document.querySelector('d2l-tabs');
38
44
  const panels = [...tabs.querySelectorAll('d2l-tab-panel')];
@@ -73,30 +79,32 @@
73
79
 
74
80
  <d2l-demo-snippet>
75
81
  <template>
76
- <d2l-tabs>
77
- <d2l-tab-panel text="S18">Tab content for S18</d2l-tab-panel>
78
- <d2l-tab-panel text="W18">Tab content for W18</d2l-tab-panel>
79
- <d2l-tab-panel text="F17">Tab content for F17</d2l-tab-panel>
80
- <d2l-tab-panel text="S17">Tab content for S17</d2l-tab-panel>
81
- <d2l-tab-panel text="W17">Tab content for W17</d2l-tab-panel>
82
- <d2l-tab-panel text="F16">Tab content for F16</d2l-tab-panel>
83
- <d2l-tab-panel text="S16">Tab content for S16</d2l-tab-panel>
84
- <d2l-tab-panel text="W16">Tab content for W16</d2l-tab-panel>
85
- <d2l-tab-panel text="F15">Tab content for F15</d2l-tab-panel>
86
- <d2l-tab-panel text="S15">Tab content for S15</d2l-tab-panel>
87
- <d2l-tab-panel text="W15">Tab content for W15</d2l-tab-panel>
88
- <d2l-tab-panel text="F14">Tab content for F14</d2l-tab-panel>
89
- <d2l-tab-panel text="S14">Tab content for S14</d2l-tab-panel>
90
- <d2l-tab-panel text="W14">Tab content for W14</d2l-tab-panel>
91
- <d2l-tab-panel text="F13">Tab content for F13</d2l-tab-panel>
92
- <d2l-tab-panel text="S13">Tab content for S13</d2l-tab-panel>
93
- <d2l-tab-panel text="W13">Tab content for W13</d2l-tab-panel>
94
- <d2l-tab-panel text="F12">Tab content for F12</d2l-tab-panel>
95
- <d2l-tab-panel text="S12">Tab content for S12</d2l-tab-panel>
96
- <d2l-tab-panel text="W12">Tab content for W12</d2l-tab-panel>
97
- <d2l-tab-panel text="F11">Tab content for F11</d2l-tab-panel>
98
- <d2l-tab-panel text="S11">Tab content for S11</d2l-tab-panel>
99
- </d2l-tabs>
82
+ <div style="max-width: 500px;">
83
+ <d2l-tabs>
84
+ <d2l-tab-panel text="S18">Tab content for S18</d2l-tab-panel>
85
+ <d2l-tab-panel text="W18">Tab content for W18</d2l-tab-panel>
86
+ <d2l-tab-panel text="F17">Tab content for F17</d2l-tab-panel>
87
+ <d2l-tab-panel text="S17">Tab content for S17</d2l-tab-panel>
88
+ <d2l-tab-panel text="W17">Tab content for W17</d2l-tab-panel>
89
+ <d2l-tab-panel text="F16">Tab content for F16</d2l-tab-panel>
90
+ <d2l-tab-panel text="S16">Tab content for S16</d2l-tab-panel>
91
+ <d2l-tab-panel text="W16">Tab content for W16</d2l-tab-panel>
92
+ <d2l-tab-panel text="F15">Tab content for F15</d2l-tab-panel>
93
+ <d2l-tab-panel text="S15">Tab content for S15</d2l-tab-panel>
94
+ <d2l-tab-panel text="W15">Tab content for W15</d2l-tab-panel>
95
+ <d2l-tab-panel text="F14">Tab content for F14</d2l-tab-panel>
96
+ <d2l-tab-panel text="S14">Tab content for S14</d2l-tab-panel>
97
+ <d2l-tab-panel text="W14">Tab content for W14</d2l-tab-panel>
98
+ <d2l-tab-panel text="F13">Tab content for F13</d2l-tab-panel>
99
+ <d2l-tab-panel text="S13">Tab content for S13</d2l-tab-panel>
100
+ <d2l-tab-panel text="W13">Tab content for W13</d2l-tab-panel>
101
+ <d2l-tab-panel text="F12">Tab content for F12</d2l-tab-panel>
102
+ <d2l-tab-panel text="S12">Tab content for S12</d2l-tab-panel>
103
+ <d2l-tab-panel text="W12">Tab content for W12</d2l-tab-panel>
104
+ <d2l-tab-panel text="F11">Tab content for F11</d2l-tab-panel>
105
+ <d2l-tab-panel text="S11">Tab content for S11</d2l-tab-panel>
106
+ </d2l-tabs>
107
+ </div>
100
108
  </template>
101
109
  </d2l-demo-snippet>
102
110
 
@@ -4,7 +4,6 @@ import '../../helpers/queueMicrotask.js';
4
4
  import './tab-internal.js';
5
5
  import { css, html, LitElement } from 'lit-element/lit-element.js';
6
6
  import { cssEscape, findComposedAncestor } from '../../helpers/dom.js';
7
- import { getNextFocusable, getPreviousFocusable } from '../../helpers/focus.js';
8
7
  import { ArrowKeysMixin } from '../../mixins/arrow-keys-mixin.js';
9
8
  import { bodyCompactStyles } from '../typography/styles.js';
10
9
  import { classMap } from 'lit-html/directives/class-map.js';
@@ -125,11 +124,6 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
125
124
  transition: transform 200ms ease-out;
126
125
  white-space: nowrap;
127
126
  }
128
- .d2l-tabs-focus-start,
129
- .d2l-tabs-focus-end {
130
- left: 0;
131
- position: absolute;
132
- }
133
127
  .d2l-tabs-scroll-previous-container,
134
128
  .d2l-tabs-scroll-next-container {
135
129
  background-color: var(--d2l-tabs-background-color);
@@ -280,6 +274,11 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
280
274
 
281
275
  this.arrowKeysOnBeforeFocus = async(tab) => {
282
276
  const tabInfo = this._getTabInfo(tab.controlsPanel);
277
+ this._setFocusable(tabInfo);
278
+
279
+ this.requestUpdate();
280
+ await this.updateComplete;
281
+
283
282
  if (!this._scrollCollapsed) {
284
283
  return this._updateScrollPosition(tabInfo);
285
284
  } else {
@@ -340,22 +339,22 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
340
339
  <d2l-icon icon="tier1:chevron-left"></d2l-icon>
341
340
  </button>
342
341
  </div>
343
- <span class="d2l-tabs-focus-start" @focus="${this._handleFocusStart}" tabindex="0"></span>
344
342
  ${this.arrowKeysContainer(html`
345
343
  <div class="d2l-tabs-container-list"
346
344
  @d2l-tab-selected="${this._handleTabSelected}"
345
+ @focusout="${this._handleFocusOut}"
347
346
  role="tablist"
348
347
  style="${styleMap(tabsContainerListStyles)}">
349
348
  ${repeat(this._tabInfos, (tabInfo) => tabInfo.id, (tabInfo) => html`
350
349
  <d2l-tab-internal aria-selected="${tabInfo.selected ? 'true' : 'false'}"
351
350
  .controlsPanel="${tabInfo.id}"
352
351
  data-state="${tabInfo.state}"
352
+ tabindex="${tabInfo.activeFocusable ? 0 : -1}"
353
353
  text="${tabInfo.text}">
354
354
  </d2l-tab-internal>
355
355
  `)}
356
356
  </div>
357
357
  `)}
358
- <span class="d2l-tabs-focus-end" @focus="${this._handleFocusEnd}" tabindex="0"></span>
359
358
  <div class="d2l-tabs-scroll-next-container">
360
359
  <button class="d2l-tabs-scroll-button"
361
360
  @click="${this._handleScrollNext}"
@@ -552,28 +551,17 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
552
551
  }
553
552
  }
554
553
 
555
- _handleFocusEnd(e) {
556
- if (e.relatedTarget && e.relatedTarget.role !== 'tab') {
557
- this._focusSelected();
558
- } else {
559
- const nextFocusable = getNextFocusable(e.target, false);
560
- if (nextFocusable) nextFocusable.focus();
561
- }
562
- }
563
-
564
- _handleFocusStart(e) {
565
- if (e.relatedTarget && e.relatedTarget.role === 'tab') {
566
- const previousFocusable = getPreviousFocusable(e.target, false);
567
- if (previousFocusable) previousFocusable.focus();
568
- } else {
569
- this._focusSelected();
570
- }
554
+ _handleFocusOut(e) {
555
+ if (e.relatedTarget && e.relatedTarget.role === 'tab') return;
556
+ this._resetFocusables();
571
557
  }
572
558
 
573
559
  _handlePanelSelected(e) {
574
560
  const tabInfo = this._getTabInfo(e.target.id);
575
561
  // event could be from nested tabs
576
562
  if (!tabInfo) return;
563
+
564
+ this._setFocusable(tabInfo);
577
565
  tabInfo.selected = true;
578
566
  this.requestUpdate();
579
567
  }
@@ -603,7 +591,10 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
603
591
  selected: panel.selected,
604
592
  state: state
605
593
  };
606
- if (tabInfo.selected) selectedTabInfo = tabInfo;
594
+ if (tabInfo.selected) {
595
+ selectedTabInfo = tabInfo;
596
+ this._setFocusable(tabInfo);
597
+ }
607
598
  return tabInfo;
608
599
  });
609
600
 
@@ -619,6 +610,7 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
619
610
  this._tabInfos = newTabInfos;
620
611
 
621
612
  if (this._tabInfos.length > 0 && !selectedTabInfo) {
613
+ this._tabInfos[0].activeFocusable = true;
622
614
  this._tabInfos[0].selected = true;
623
615
  selectedTabInfo = this._tabInfos[0];
624
616
  }
@@ -756,19 +748,24 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
756
748
  const selectedTab = e.target;
757
749
  const selectedPanel = this._getPanel(selectedTab.controlsPanel);
758
750
  const selectedTabInfo = this._getTabInfo(selectedTab.controlsPanel);
751
+ selectedTabInfo.activeFocusable = true;
759
752
 
760
753
  await this.updateComplete;
761
754
  this._updateScrollPosition(selectedTabInfo);
762
755
 
763
756
  selectedPanel.selected = true;
764
757
  this._tabInfos.forEach((tabInfo) => {
765
- if (tabInfo.selected && tabInfo.id !== selectedTab.controlsPanel) {
766
- tabInfo.selected = false;
767
- const panel = this._getPanel(tabInfo.id);
768
- // panel may not exist if it's being removed
769
- if (panel) panel.selected = false;
758
+ if (tabInfo.id !== selectedTab.controlsPanel) {
759
+ if (tabInfo.selected) {
760
+ tabInfo.selected = false;
761
+ const panel = this._getPanel(tabInfo.id);
762
+ // panel may not exist if it's being removed
763
+ if (panel) panel.selected = false;
764
+ }
765
+ if (tabInfo.activeFocusable) tabInfo.activeFocusable = false;
770
766
  }
771
767
  });
768
+
772
769
  this.requestUpdate();
773
770
  }
774
771
 
@@ -780,6 +777,12 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
780
777
  return (position > measures.tabsContainerRect.width - scrollButtonWidth) && (position < measures.tabsContainerRect.width);
781
778
  }
782
779
 
780
+ _resetFocusables() {
781
+ const selectedTab = this._tabInfos.find(ti => ti.selected);
782
+ if (selectedTab) this._setFocusable(selectedTab);
783
+ this.requestUpdate();
784
+ }
785
+
783
786
  _scrollToPosition(translationValue) {
784
787
  if (translationValue === this._translationValue) {
785
788
  return Promise.resolve();
@@ -801,6 +804,13 @@ class Tabs extends LocalizeCoreElement(ArrowKeysMixin(RtlMixin(FocusVisiblePolyf
801
804
  });
802
805
  }
803
806
 
807
+ _setFocusable(tabInfo) {
808
+ const currentFocusable = this._tabInfos.find(ti => ti.activeFocusable);
809
+ if (currentFocusable) currentFocusable.activeFocusable = false;
810
+
811
+ tabInfo.activeFocusable = true;
812
+ }
813
+
804
814
  async _tryExpandTabsContainer(measures) {
805
815
 
806
816
  if (!this._scrollCollapsed) return false;
@@ -2,11 +2,17 @@ import { getLocalizeOverrideResources } from '../helpers/getLocalizeResources.js
2
2
  import { LocalizeMixin } from './localize-mixin.js';
3
3
 
4
4
  const fallbackLang = 'en';
5
+ const supportedLangpacks = ['ar', 'cy', 'da', 'de', 'en', 'es', 'es-es', 'fr', 'fr-fr', 'fr-on', 'hi', 'ja', 'ko', 'nl', 'pt', 'sv', 'tr', 'zh-cn', 'zh-tw'];
5
6
 
6
7
  export const LocalizeDynamicMixin = superclass => class extends LocalizeMixin(superclass) {
7
8
 
8
9
  static async getLocalizeResources(langs, { importFunc, osloCollection }) {
9
10
 
11
+ // in dev, don't request unsupported langpacks
12
+ if (!importFunc.toString().includes('switch')) {
13
+ langs = langs.filter(lang => supportedLangpacks.includes(lang));
14
+ }
15
+
10
16
  for (const lang of [...langs, fallbackLang]) {
11
17
 
12
18
  const resources = await importFunc(lang).catch(() => {});
@@ -83,7 +83,9 @@ class MyComponent extends LocalizeDynamicMixin(LitElement) {
83
83
  }
84
84
  ```
85
85
 
86
- If your build system does not support variable dynamic imports, you'll need to manually set up imports for each language:
86
+ When using this method, depending on various user settings, it's possible that a language file that does not exist will be requested, resulting in a network error (404). In production, your build system should prevent this by transpiling the variable dynamic import into a `switch` statement.
87
+
88
+ If your build system does not support variable dynamic imports, you'll need to manually set up imports for each supported language:
87
89
 
88
90
  ```javascript
89
91
  static get localizeConfig() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.0.3",
3
+ "version": "2.1.1",
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",