@brightspace-ui/core 1.235.1 → 1.236.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import '../colors/colors.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
3
  import { classMap } from 'lit-html/directives/class-map.js';
4
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
4
5
  import { ifDefined } from 'lit-html/directives/if-defined.js';
5
6
 
6
7
  export const linkStyles = css`
@@ -41,7 +42,7 @@ export const linkStyles = css`
41
42
  * This component can be used just like the native anchor tag.
42
43
  * @slot - The content (e.g., text) that when selected causes navigation
43
44
  */
44
- class Link extends LitElement {
45
+ class Link extends FocusMixin(LitElement) {
45
46
 
46
47
  static get properties() {
47
48
  return {
@@ -96,6 +97,8 @@ class Link extends LitElement {
96
97
  ];
97
98
  }
98
99
 
100
+ static focusElementSelector = '.d2l-link';
101
+
99
102
  constructor() {
100
103
  super();
101
104
  this.download = false;
@@ -117,9 +120,5 @@ class Link extends LitElement {
117
120
  target="${ifDefined(this.target)}"><slot></slot></a>`;
118
121
  }
119
122
 
120
- focus() {
121
- const link = this.shadowRoot && this.shadowRoot.querySelector('.d2l-link');
122
- if (link) link.focus();
123
- }
124
123
  }
125
124
  customElements.define('d2l-link', Link);
@@ -193,6 +193,7 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
193
193
  .d2l-list-item-actions-container {
194
194
  padding: 0.55rem 0;
195
195
  }
196
+
196
197
  ::slotted([slot="actions"]),
197
198
  .d2l-list-item-actions * {
198
199
  display: grid;
@@ -202,6 +203,16 @@ export const ListItemMixin = superclass => class extends LocalizeCoreElement(Lis
202
203
  margin: 0.15rem 0;
203
204
  }
204
205
 
206
+ .d2l-list-item-content-extend-separators ::slotted([slot="actions"]),
207
+ .d2l-list-item-content-extend-separators .d2l-list-item-actions * {
208
+ margin-right: 0.9rem;
209
+ }
210
+ :host([dir="rtl"]) .d2l-list-item-content-extend-separators ::slotted([slot="actions"]),
211
+ :host([dir="rtl"]) .d2l-list-item-content-extend-separators .d2l-list-item-actions * {
212
+ margin-left: 0.9rem;
213
+ margin-right: 0;
214
+ }
215
+
205
216
  [data-breakpoint="1"] ::slotted([slot="illustration"]),
206
217
  [data-breakpoint="1"] .d2l-list-item-illustration * {
207
218
  margin-right: 1rem;
@@ -2,6 +2,7 @@ import '../button/button-subtle.js';
2
2
  import { html, LitElement } from 'lit-element/lit-element.js';
3
3
  import { DropdownOpenerMixin } from '../dropdown/dropdown-opener-mixin.js';
4
4
  import { dropdownOpenerStyles } from '../dropdown/dropdown-opener-styles.js';
5
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
5
6
  import { ifDefined } from 'lit-html/directives/if-defined.js';
6
7
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
7
8
  import { SelectionActionMixin } from './selection-action-mixin.js';
@@ -11,7 +12,7 @@ import { SelectionActionMixin } from './selection-action-mixin.js';
11
12
  * @slot - Dropdown content (e.g., "d2l-dropdown-content", "d2l-dropdown-menu" or "d2l-dropdown-tabs")
12
13
  * @fires d2l-selection-observer-subscribe - Internal event
13
14
  */
14
- class ActionDropdown extends LocalizeCoreElement(SelectionActionMixin(DropdownOpenerMixin(LitElement))) {
15
+ class ActionDropdown extends FocusMixin(LocalizeCoreElement(SelectionActionMixin(DropdownOpenerMixin(LitElement)))) {
15
16
 
16
17
  static get properties() {
17
18
  return {
@@ -27,6 +28,8 @@ class ActionDropdown extends LocalizeCoreElement(SelectionActionMixin(DropdownOp
27
28
  return dropdownOpenerStyles;
28
29
  }
29
30
 
31
+ static focusElementSelector = 'd2l-button-subtle';
32
+
30
33
  render() {
31
34
  return html`
32
35
  <d2l-button-subtle
@@ -39,11 +42,6 @@ class ActionDropdown extends LocalizeCoreElement(SelectionActionMixin(DropdownOp
39
42
  `;
40
43
  }
41
44
 
42
- focus() {
43
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-button-subtle');
44
- if (elem) elem.focus();
45
- }
46
-
47
45
  /**
48
46
  * Gets the opener element with class "d2l-dropdown-opener" (required by dropdown-opener-mixin).
49
47
  * @return {HTMLElement}
@@ -1,6 +1,7 @@
1
1
  import '../button/button-subtle.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
3
  import { ButtonMixin } from '../button/button-mixin.js';
4
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
4
5
  import { ifDefined } from 'lit-html/directives/if-defined.js';
5
6
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
6
7
  import { SelectionActionMixin } from './selection-action-mixin.js';
@@ -11,7 +12,7 @@ import { SelectionInfo } from './selection-mixin.js';
11
12
  * @fires d2l-selection-action-click - Dispatched when the user clicks the action button. The `SelectionInfo` is provided as the event `detail`. If `requires-selection` was specified then the event will only be dispatched if items are selected.
12
13
  * @fires d2l-selection-observer-subscribe - Internal event
13
14
  */
14
- class Action extends LocalizeCoreElement(SelectionActionMixin(ButtonMixin(LitElement))) {
15
+ class Action extends FocusMixin(LocalizeCoreElement(SelectionActionMixin(ButtonMixin(LitElement)))) {
15
16
 
16
17
  static get properties() {
17
18
  return {
@@ -39,6 +40,8 @@ class Action extends LocalizeCoreElement(SelectionActionMixin(ButtonMixin(LitEle
39
40
  `;
40
41
  }
41
42
 
43
+ static focusElementSelector = 'd2l-button-subtle';
44
+
42
45
  connectedCallback() {
43
46
  super.connectedCallback();
44
47
  this.addEventListener('d2l-button-ghost-click', this._handleActionClick);
@@ -61,11 +64,6 @@ class Action extends LocalizeCoreElement(SelectionActionMixin(ButtonMixin(LitEle
61
64
  `;
62
65
  }
63
66
 
64
- focus() {
65
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-button-subtle');
66
- if (elem) elem.focus();
67
- }
68
-
69
67
  _handleActionClick(e) {
70
68
  e.stopPropagation();
71
69
 
@@ -1,5 +1,6 @@
1
1
  import '../button/button-subtle.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
3
4
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
4
5
  import { SelectionInfo } from './selection-mixin.js';
5
6
  import { SelectionObserverMixin } from './selection-observer-mixin.js';
@@ -8,7 +9,7 @@ import { SelectionObserverMixin } from './selection-observer-mixin.js';
8
9
  * A subtle button that selects all items for all pages.
9
10
  * @fires d2l-selection-observer-subscribe - Internal event
10
11
  */
11
- class SelectAllPages extends LocalizeCoreElement(SelectionObserverMixin(LitElement)) {
12
+ class SelectAllPages extends FocusMixin(LocalizeCoreElement(SelectionObserverMixin(LitElement))) {
12
13
 
13
14
  static get styles() {
14
15
  return css`
@@ -21,6 +22,8 @@ class SelectAllPages extends LocalizeCoreElement(SelectionObserverMixin(LitEleme
21
22
  `;
22
23
  }
23
24
 
25
+ static focusElementSelector = 'd2l-button-subtle';
26
+
24
27
  render() {
25
28
  if (!this._provider) return;
26
29
  if (!this._provider.itemCount) return;
@@ -34,11 +37,6 @@ class SelectAllPages extends LocalizeCoreElement(SelectionObserverMixin(LitEleme
34
37
  </d2l-button-subtle>`;
35
38
  }
36
39
 
37
- focus() {
38
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-button-subtle');
39
- if (elem) elem.focus();
40
- }
41
-
42
40
  _handleClick() {
43
41
  if (this._provider) this._provider.setSelectionForAll(true, true);
44
42
  }
@@ -1,5 +1,6 @@
1
1
  import '../inputs/input-checkbox.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
3
4
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
5
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
5
6
  import { SelectionInfo } from './selection-mixin.js';
@@ -9,7 +10,7 @@ import { SelectionObserverMixin } from './selection-observer-mixin.js';
9
10
  * A checkbox that provides select-all behavior for selection components such as tables and lists.
10
11
  * @fires d2l-selection-observer-subscribe - Internal event
11
12
  */
12
- class SelectAll extends LocalizeCoreElement(SelectionObserverMixin(LitElement)) {
13
+ class SelectAll extends FocusMixin(LocalizeCoreElement(SelectionObserverMixin(LitElement))) {
13
14
 
14
15
  static get properties() {
15
16
  return {
@@ -33,6 +34,8 @@ class SelectAll extends LocalizeCoreElement(SelectionObserverMixin(LitElement))
33
34
  `;
34
35
  }
35
36
 
37
+ static focusElementSelector = 'd2l-input-checkbox';
38
+
36
39
  constructor() {
37
40
  super();
38
41
  this.disabled = false;
@@ -56,11 +59,6 @@ class SelectAll extends LocalizeCoreElement(SelectionObserverMixin(LitElement))
56
59
  `;
57
60
  }
58
61
 
59
- focus() {
60
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-checkbox');
61
- if (elem) elem.focus();
62
- }
63
-
64
62
  _handleCheckboxChange(e) {
65
63
  if (this._provider) this._provider.setSelectionForAll(e.target.checked, false);
66
64
  }
@@ -32,7 +32,7 @@ The `d2l-switch` element is a generic switch with on/off semantics.
32
32
  ![Switch](./screenshots/switch.png?raw=true)
33
33
  <!-- docs: end hidden content -->
34
34
 
35
- <!-- docs: demo live name:d2l-switch -->
35
+ <!-- docs: demo live name:d2l-switch autoSize:false size:small -->
36
36
  ```html
37
37
  <script type="module">
38
38
  import '@brightspace-ui/core/components/switch/switch.js';
@@ -71,7 +71,7 @@ The `d2l-switch-visibility` element is a variant of the generic switch configure
71
71
  ![Visibility Switch](./screenshots/switch-visibility.png?raw=true)
72
72
  <!-- docs: end hidden content -->
73
73
 
74
- <!-- docs: demo live name:d2l-switch-visibility -->
74
+ <!-- docs: demo live name:d2l-switch-visibility autoSize:false size:small -->
75
75
  ```html
76
76
  <script type="module">
77
77
  import '@brightspace-ui/core/components/switch/switch-visibility.js';
@@ -1,12 +1,13 @@
1
1
  import '../colors/colors.js';
2
2
  import '../tooltip/tooltip.js';
3
3
  import { css, html } from 'lit-element/lit-element.js';
4
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
4
5
  import { FocusVisiblePolyfillMixin } from '../../mixins/focus-visible-polyfill-mixin.js';
5
6
  import { getUniqueId } from '../../helpers/uniqueId.js';
6
7
  import { ifDefined } from 'lit-html/directives/if-defined.js';
7
8
  import { RtlMixin } from '../../mixins/rtl-mixin.js';
8
9
 
9
- export const SwitchMixin = superclass => class extends RtlMixin(FocusVisiblePolyfillMixin(superclass)) {
10
+ export const SwitchMixin = superclass => class extends FocusMixin(RtlMixin(FocusVisiblePolyfillMixin(superclass))) {
10
11
 
11
12
  static get properties() {
12
13
  return {
@@ -165,6 +166,8 @@ export const SwitchMixin = superclass => class extends RtlMixin(FocusVisiblePoly
165
166
  `;
166
167
  }
167
168
 
169
+ static focusElementSelector = '.d2l-switch-container';
170
+
168
171
  constructor() {
169
172
  super();
170
173
  this.disabled = false;
@@ -212,11 +215,6 @@ export const SwitchMixin = superclass => class extends RtlMixin(FocusVisiblePoly
212
215
  `;
213
216
  }
214
217
 
215
- focus() {
216
- const elem = this.shadowRoot && this.shadowRoot.querySelector('.d2l-switch-container');
217
- if (elem) elem.focus();
218
- }
219
-
220
218
  _handleClick() {
221
219
  this._toggleState();
222
220
  }
@@ -1,11 +1,12 @@
1
1
  import '../icons/icon.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
3
4
 
4
5
  /**
5
6
  * Button for sorting a table column in ascending/descending order.
6
7
  * @slot - Text of the sort button
7
8
  */
8
- export class TableColSortButton extends LitElement {
9
+ export class TableColSortButton extends FocusMixin(LitElement) {
9
10
 
10
11
  static get properties() {
11
12
  return {
@@ -57,6 +58,8 @@ export class TableColSortButton extends LitElement {
57
58
  `;
58
59
  }
59
60
 
61
+ static focusElementSelector = 'button';
62
+
60
63
  constructor() {
61
64
  super();
62
65
  this.nosort = false;
@@ -70,11 +73,6 @@ export class TableColSortButton extends LitElement {
70
73
  return html`<button type="button"><slot></slot>${iconView}</button>`;
71
74
  }
72
75
 
73
- focus() {
74
- const button = this.shadowRoot && this.shadowRoot.querySelector('button');
75
- if (button) button.focus();
76
- }
77
-
78
76
  }
79
77
 
80
78
  customElements.define('d2l-table-col-sort-button', TableColSortButton);
@@ -408,6 +408,11 @@
408
408
  "type": "boolean",
409
409
  "default": "false"
410
410
  },
411
+ {
412
+ "name": "focusElementSelector",
413
+ "type": "string",
414
+ "default": "\"button\""
415
+ },
411
416
  {
412
417
  "name": "visibleOnAncestor",
413
418
  "type": "boolean",
@@ -502,6 +507,11 @@
502
507
  "description": "Disables the button",
503
508
  "type": "boolean",
504
509
  "default": "false"
510
+ },
511
+ {
512
+ "name": "focusElementSelector",
513
+ "type": "string",
514
+ "default": "\"button\""
505
515
  }
506
516
  ],
507
517
  "slots": [
@@ -565,6 +575,11 @@
565
575
  "description": "Disables the button",
566
576
  "type": "boolean",
567
577
  "default": "false"
578
+ },
579
+ {
580
+ "name": "focusElementSelector",
581
+ "type": "string",
582
+ "default": "\"button\""
568
583
  }
569
584
  ],
570
585
  "slots": [
@@ -979,6 +994,11 @@
979
994
  "description": "Subtle aesthetic on non-white backgrounds",
980
995
  "type": "boolean",
981
996
  "default": "false"
997
+ },
998
+ {
999
+ "name": "focusElementSelector",
1000
+ "type": "string",
1001
+ "default": "\"a\""
982
1002
  }
983
1003
  ],
984
1004
  "slots": [
@@ -3137,6 +3157,11 @@
3137
3157
  "description": "Indicates if the filter is open",
3138
3158
  "type": "boolean",
3139
3159
  "default": "false"
3160
+ },
3161
+ {
3162
+ "name": "focusElementSelector",
3163
+ "type": "string",
3164
+ "default": "\"d2l-dropdown-button-subtle\""
3140
3165
  }
3141
3166
  ],
3142
3167
  "events": [
@@ -3179,6 +3204,11 @@
3179
3204
  "description": "Whether the component should trap user focus.",
3180
3205
  "type": "boolean",
3181
3206
  "default": "false"
3207
+ },
3208
+ {
3209
+ "name": "focusElementSelector",
3210
+ "type": "string",
3211
+ "default": "\".d2l-focus-trap-start\""
3182
3212
  }
3183
3213
  ],
3184
3214
  "events": [
@@ -3759,6 +3789,11 @@
3759
3789
  "type": "string",
3760
3790
  "default": "\"on\""
3761
3791
  },
3792
+ {
3793
+ "name": "focusElementSelector",
3794
+ "type": "string",
3795
+ "default": "\"input.d2l-input-checkbox\""
3796
+ },
3762
3797
  {
3763
3798
  "name": "skeleton",
3764
3799
  "attribute": "skeleton",
@@ -3983,6 +4018,11 @@
3983
4018
  "type": "boolean",
3984
4019
  "default": "false"
3985
4020
  },
4021
+ {
4022
+ "name": "focusElementSelector",
4023
+ "type": "string",
4024
+ "default": "\"d2l-input-date\""
4025
+ },
3986
4026
  {
3987
4027
  "name": "skeleton",
3988
4028
  "attribute": "skeleton",
@@ -4280,6 +4320,11 @@
4280
4320
  "type": "boolean",
4281
4321
  "default": "false"
4282
4322
  },
4323
+ {
4324
+ "name": "focusElementSelector",
4325
+ "type": "string",
4326
+ "default": "\"d2l-input-date-time\""
4327
+ },
4283
4328
  {
4284
4329
  "name": "skeleton",
4285
4330
  "attribute": "skeleton",
@@ -4450,6 +4495,11 @@
4450
4495
  "type": "string",
4451
4496
  "default": "\"startOfDay\""
4452
4497
  },
4498
+ {
4499
+ "name": "focusElementSelector",
4500
+ "type": "string",
4501
+ "default": "\"d2l-input-date\""
4502
+ },
4453
4503
  {
4454
4504
  "name": "labelledBy",
4455
4505
  "attribute": "labelled-by",
@@ -4616,6 +4666,11 @@
4616
4666
  "type": "string",
4617
4667
  "default": "\"\""
4618
4668
  },
4669
+ {
4670
+ "name": "focusElementSelector",
4671
+ "type": "string",
4672
+ "default": "\"d2l-input-text\""
4673
+ },
4619
4674
  {
4620
4675
  "name": "labelledBy",
4621
4676
  "attribute": "labelled-by",
@@ -4955,6 +5010,11 @@
4955
5010
  "type": "boolean",
4956
5011
  "default": "false"
4957
5012
  },
5013
+ {
5014
+ "name": "focusElementSelector",
5015
+ "type": "string",
5016
+ "default": "\"d2l-input-text\""
5017
+ },
4958
5018
  {
4959
5019
  "name": "labelledBy",
4960
5020
  "attribute": "labelled-by",
@@ -5153,6 +5213,11 @@
5153
5213
  "type": "boolean",
5154
5214
  "default": "false"
5155
5215
  },
5216
+ {
5217
+ "name": "focusElementSelector",
5218
+ "type": "string",
5219
+ "default": "\"d2l-input-number\""
5220
+ },
5156
5221
  {
5157
5222
  "name": "labelledBy",
5158
5223
  "attribute": "labelled-by",
@@ -5290,6 +5355,11 @@
5290
5355
  "description": "Value of the input",
5291
5356
  "type": "string",
5292
5357
  "default": "\"\""
5358
+ },
5359
+ {
5360
+ "name": "focusElementSelector",
5361
+ "type": "string",
5362
+ "default": "\"d2l-input-text\""
5293
5363
  }
5294
5364
  ],
5295
5365
  "events": [
@@ -5629,6 +5699,11 @@
5629
5699
  "type": "'text'|'email'|'number'|'password'|'search'|'tel'|'url'",
5630
5700
  "default": "\"text\""
5631
5701
  },
5702
+ {
5703
+ "name": "focusElementSelector",
5704
+ "type": "string",
5705
+ "default": "\".d2l-input\""
5706
+ },
5632
5707
  {
5633
5708
  "name": "labelledBy",
5634
5709
  "attribute": "labelled-by",
@@ -5868,6 +5943,11 @@
5868
5943
  "type": "string",
5869
5944
  "default": "\"\""
5870
5945
  },
5946
+ {
5947
+ "name": "focusElementSelector",
5948
+ "type": "string",
5949
+ "default": "\"textarea\""
5950
+ },
5871
5951
  {
5872
5952
  "name": "labelledBy",
5873
5953
  "attribute": "labelled-by",
@@ -6117,6 +6197,11 @@
6117
6197
  "type": "'five'|'ten'|'fifteen'|'twenty'|'thirty'|'sixty'",
6118
6198
  "default": "\"thirty\""
6119
6199
  },
6200
+ {
6201
+ "name": "focusElementSelector",
6202
+ "type": "string",
6203
+ "default": "\"d2l-input-time\""
6204
+ },
6120
6205
  {
6121
6206
  "name": "skeleton",
6122
6207
  "attribute": "skeleton",
@@ -6277,6 +6362,11 @@
6277
6362
  "type": "'five'|'ten'|'fifteen'|'twenty'|'thirty'|'sixty'",
6278
6363
  "default": "\"thirty\""
6279
6364
  },
6365
+ {
6366
+ "name": "focusElementSelector",
6367
+ "type": "string",
6368
+ "default": "\".d2l-input\""
6369
+ },
6280
6370
  {
6281
6371
  "name": "labelledBy",
6282
6372
  "attribute": "labelled-by",
@@ -6393,6 +6483,11 @@
6393
6483
  "description": "Whether to apply the \"small\" link style",
6394
6484
  "type": "boolean",
6395
6485
  "default": "false"
6486
+ },
6487
+ {
6488
+ "name": "focusElementSelector",
6489
+ "type": "string",
6490
+ "default": "\".d2l-link\""
6396
6491
  }
6397
6492
  ],
6398
6493
  "slots": [
@@ -8518,6 +8613,11 @@
8518
8613
  "description": "REQUIRED: Text for the dropdown opener button",
8519
8614
  "type": "string"
8520
8615
  },
8616
+ {
8617
+ "name": "focusElementSelector",
8618
+ "type": "string",
8619
+ "default": "\"d2l-button-subtle\""
8620
+ },
8521
8621
  {
8522
8622
  "name": "requiresSelection",
8523
8623
  "attribute": "requires-selection",
@@ -8751,6 +8851,11 @@
8751
8851
  "description": "Disables the button",
8752
8852
  "type": "boolean",
8753
8853
  "default": "false"
8854
+ },
8855
+ {
8856
+ "name": "focusElementSelector",
8857
+ "type": "string",
8858
+ "default": "\"d2l-button-subtle\""
8754
8859
  }
8755
8860
  ],
8756
8861
  "events": [
@@ -8870,6 +8975,11 @@
8870
8975
  }
8871
8976
  ],
8872
8977
  "properties": [
8978
+ {
8979
+ "name": "focusElementSelector",
8980
+ "type": "string",
8981
+ "default": "\"d2l-button-subtle\""
8982
+ },
8873
8983
  {
8874
8984
  "name": "selectionFor",
8875
8985
  "attribute": "selection-for",
@@ -8912,6 +9022,11 @@
8912
9022
  "type": "boolean",
8913
9023
  "default": "false"
8914
9024
  },
9025
+ {
9026
+ "name": "focusElementSelector",
9027
+ "type": "string",
9028
+ "default": "\"d2l-input-checkbox\""
9029
+ },
8915
9030
  {
8916
9031
  "name": "selectionFor",
8917
9032
  "attribute": "selection-for",
@@ -9334,6 +9449,11 @@
9334
9449
  "description": "Determines where text should be positioned relative to the switch.",
9335
9450
  "type": "'start'|'end'|'hidden'",
9336
9451
  "default": "\"end\""
9452
+ },
9453
+ {
9454
+ "name": "focusElementSelector",
9455
+ "type": "string",
9456
+ "default": "\".d2l-switch-container\""
9337
9457
  }
9338
9458
  ],
9339
9459
  "events": [
@@ -9423,6 +9543,11 @@
9423
9543
  "description": "Determines where text should be positioned relative to the switch.",
9424
9544
  "type": "'start'|'end'|'hidden'",
9425
9545
  "default": "\"end\""
9546
+ },
9547
+ {
9548
+ "name": "focusElementSelector",
9549
+ "type": "string",
9550
+ "default": "\".d2l-switch-container\""
9426
9551
  }
9427
9552
  ],
9428
9553
  "events": [
@@ -9516,6 +9641,11 @@
9516
9641
  "description": "Whether sort direction is descending",
9517
9642
  "type": "boolean",
9518
9643
  "default": "false"
9644
+ },
9645
+ {
9646
+ "name": "focusElementSelector",
9647
+ "type": "string",
9648
+ "default": "\"button\""
9519
9649
  }
9520
9650
  ],
9521
9651
  "slots": [
@@ -0,0 +1,41 @@
1
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
2
+
3
+ export const FocusMixin = dedupeMixin(superclass => class extends superclass {
4
+
5
+ static focusElementSelector = null;
6
+
7
+ constructor() {
8
+ super();
9
+ this._focusOnFirstRender = false;
10
+ }
11
+
12
+ firstUpdated(changedProperties) {
13
+ super.firstUpdated(changedProperties);
14
+ if (this._focusOnFirstRender) {
15
+ this._focusOnFirstRender = false;
16
+ this.focus();
17
+ }
18
+ }
19
+
20
+ focus() {
21
+
22
+ const selector = this.constructor.focusElementSelector;
23
+ if (!selector) {
24
+ throw new Error(`FocusMixin: no static focusElementSelector provided for "${this.tagName}"`);
25
+ }
26
+
27
+ if (!this.hasUpdated) {
28
+ this._focusOnFirstRender = true;
29
+ return;
30
+ }
31
+
32
+ const elem = this.shadowRoot.querySelector(selector);
33
+ if (!elem) {
34
+ throw new Error(`FocusMixin: selector "${selector}" yielded no element for "${this.tagName}"`);
35
+ }
36
+
37
+ elem.focus();
38
+
39
+ }
40
+
41
+ });
@@ -0,0 +1,24 @@
1
+ # FocusMixin
2
+
3
+ The `FocusMixin` can be used to delegate focus to an element within a component's shadow root when its `focus()` method is called.
4
+
5
+ If the component has yet to render, focus will automatically be applied after `firstUpdated`.
6
+
7
+ ## Usage
8
+
9
+ Apply the mixin and set the static `focusElementSelector` to a CSS query selector which will match the element to which focus should be delegated.
10
+
11
+ ```js
12
+ import { FocusMixin } from '@brightspace-ui/core/mixins/focus-mixin.js';
13
+
14
+ class MyComponent extends FocusMixin(LitElement) {
15
+
16
+ // delegate focus to the underlying input
17
+ static focusElementSelector = 'input';
18
+
19
+ render() {
20
+ return html`<input type="text">`;
21
+ }
22
+
23
+ }
24
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "1.235.1",
3
+ "version": "1.236.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/BrightspaceUI/core.git",