@brightspace-ui/core 1.235.2 → 1.236.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.
Files changed (31) hide show
  1. package/README.md +1 -0
  2. package/components/button/button-mixin.js +4 -6
  3. package/components/card/card.js +4 -7
  4. package/components/filter/filter.js +4 -6
  5. package/components/focus-trap/focus-trap.js +4 -6
  6. package/components/inputs/input-checkbox.js +4 -6
  7. package/components/inputs/input-date-range.js +4 -6
  8. package/components/inputs/input-date-time-range.js +4 -6
  9. package/components/inputs/input-date-time.js +4 -6
  10. package/components/inputs/input-date.js +4 -5
  11. package/components/inputs/input-number.js +4 -11
  12. package/components/inputs/input-percent.js +4 -6
  13. package/components/inputs/input-search.js +4 -6
  14. package/components/inputs/input-text.js +4 -11
  15. package/components/inputs/input-textarea.js +4 -11
  16. package/components/inputs/input-time-range.js +4 -6
  17. package/components/inputs/input-time.js +4 -6
  18. package/components/link/link.js +4 -5
  19. package/components/list/list-item-mixin.js +11 -0
  20. package/components/overflow-group/demo/overflow-group.html +9 -11
  21. package/components/overflow-group/overflow-group.js +28 -28
  22. package/components/selection/selection-action-dropdown.js +4 -6
  23. package/components/selection/selection-action.js +4 -6
  24. package/components/selection/selection-select-all-pages.js +4 -6
  25. package/components/selection/selection-select-all.js +4 -6
  26. package/components/switch/switch-mixin.js +4 -6
  27. package/components/table/table-col-sort-button.js +4 -6
  28. package/custom-elements.json +130 -0
  29. package/mixins/focus-mixin.js +41 -0
  30. package/mixins/focus-mixin.md +24 -0
  31. package/package.json +1 -1
package/README.md CHANGED
@@ -66,6 +66,7 @@ npm install @brightspace-ui/core
66
66
  * Mixins
67
67
  * [ArrowKeysMixin](mixins/arrow-keys-mixin.md): manage focus with arrow keys
68
68
  * [AsyncContainerMixin](mixins/async-container/): manage collective async state
69
+ * [FocusMixin](mixins/focus-mixin.md): delegate focus to a nested element when `focus()` is called
69
70
  * [FocusVisiblePolyfillMixin](mixins/focus-visible-polyfill-mixin.md): components can use the `:focus-visible` pseudo-class polyfill
70
71
  * [FormElementMixin](components/form/docs/form-element-mixin.md): allow components to participate in forms and validation
71
72
  * [LabelledMixin](mixins/labelled-mixin.md): label custom elements by referencing elements across DOM scopes
@@ -1,6 +1,7 @@
1
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
1
2
  import { FocusVisiblePolyfillMixin } from '../../mixins/focus-visible-polyfill-mixin.js';
2
3
 
3
- export const ButtonMixin = superclass => class extends FocusVisiblePolyfillMixin(superclass) {
4
+ export const ButtonMixin = superclass => class extends FocusMixin(FocusVisiblePolyfillMixin(superclass)) {
4
5
 
5
6
  static get properties() {
6
7
  return {
@@ -65,6 +66,8 @@ export const ButtonMixin = superclass => class extends FocusVisiblePolyfillMixin
65
66
  };
66
67
  }
67
68
 
69
+ static focusElementSelector = 'button';
70
+
68
71
  constructor() {
69
72
  super();
70
73
  this.disabled = false;
@@ -107,11 +110,6 @@ export const ButtonMixin = superclass => class extends FocusVisiblePolyfillMixin
107
110
  this.removeEventListener('click', this._handleClick, true);
108
111
  }
109
112
 
110
- focus() {
111
- const button = this.shadowRoot && this.shadowRoot.querySelector('button');
112
- if (button) button.focus();
113
- }
114
-
115
113
  /** @internal */
116
114
  _getType() {
117
115
  if (this.type === 'submit' || this.type === 'reset') {
@@ -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
  import { offscreenStyles } from '../offscreen/offscreen.js';
6
7
  import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
@@ -15,7 +16,7 @@ import { styleMap } from 'lit-html/directives/style-map.js';
15
16
  * @slot footer - Slot for footer content, such secondary actions
16
17
  * @slot header - Slot for header content, such as course image (no actionable elements)
17
18
  */
18
- class Card extends RtlMixin(LitElement) {
19
+ class Card extends FocusMixin(RtlMixin(LitElement)) {
19
20
 
20
21
  static get properties() {
21
22
  return {
@@ -234,6 +235,8 @@ class Card extends RtlMixin(LitElement) {
234
235
  `];
235
236
  }
236
237
 
238
+ static focusElementSelector = 'a';
239
+
237
240
  constructor() {
238
241
  super();
239
242
  this.alignCenter = false;
@@ -306,12 +309,6 @@ class Card extends RtlMixin(LitElement) {
306
309
  `;
307
310
  }
308
311
 
309
- focus() {
310
- const elem = this.shadowRoot && this.shadowRoot.querySelector('a');
311
- if (!elem) return;
312
- elem.focus();
313
- }
314
-
315
312
  _onBadgeResize(entries) {
316
313
  if (!entries || entries.length === 0) return;
317
314
  const entry = entries[0];
@@ -19,6 +19,7 @@ import { bodyCompactStyles, bodySmallStyles, bodyStandardStyles } from '../typog
19
19
  import { css, html, LitElement } from 'lit-element/lit-element.js';
20
20
  import { announce } from '../../helpers/announce.js';
21
21
  import { classMap } from 'lit-html/directives/class-map.js';
22
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
22
23
  import { ifDefined } from 'lit-html/directives/if-defined.js';
23
24
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
24
25
  import { offscreenStyles } from '../offscreen/offscreen.js';
@@ -37,7 +38,7 @@ const SET_DIMENSION_ID_PREFIX = 'list-';
37
38
  * @fires d2l-filter-dimension-first-open - Dispatched when a dimension is opened for the first time
38
39
  * @fires d2l-filter-dimension-search - Dispatched when a dimension that supports searching and has the "manual" search-type is searched
39
40
  */
40
- class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
41
+ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
41
42
 
42
43
  static get properties() {
43
44
  return {
@@ -136,6 +137,8 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
136
137
  `];
137
138
  }
138
139
 
140
+ static focusElementSelector = 'd2l-dropdown-button-subtle';
141
+
139
142
  constructor() {
140
143
  super();
141
144
  this.disabled = false;
@@ -229,11 +232,6 @@ class Filter extends LocalizeCoreElement(RtlMixin(LitElement)) {
229
232
  `;
230
233
  }
231
234
 
232
- focus() {
233
- const opener = this.shadowRoot && this.shadowRoot.querySelector('d2l-dropdown-button-subtle');
234
- if (opener) opener.focus();
235
- }
236
-
237
235
  getSubscriberController() {
238
236
  return this._activeFiltersSubscribers;
239
237
  }
@@ -1,5 +1,6 @@
1
1
  import { css, html, LitElement } from 'lit-element/lit-element.js';
2
2
  import { forceFocusVisible, getNextFocusable, getPreviousFocusable } from '../../helpers/focus.js';
3
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
3
4
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
5
  import { isComposedAncestor } from '../../helpers/dom.js';
5
6
 
@@ -7,7 +8,7 @@ import { isComposedAncestor } from '../../helpers/dom.js';
7
8
  * A generic container component to trap user focus.
8
9
  * @fires d2l-focus-trap-enter - Dispatched when focus enters the trap. May be used to override initial focus placement when focus enters the trap.
9
10
  */
10
- class FocusTrap extends LitElement {
11
+ class FocusTrap extends FocusMixin(LitElement) {
11
12
 
12
13
  static get properties() {
13
14
  return {
@@ -30,6 +31,8 @@ class FocusTrap extends LitElement {
30
31
  `;
31
32
  }
32
33
 
34
+ static focusElementSelector = '.d2l-focus-trap-start';
35
+
33
36
  constructor() {
34
37
  super();
35
38
  this.trap = false;
@@ -55,11 +58,6 @@ class FocusTrap extends LitElement {
55
58
  `;
56
59
  }
57
60
 
58
- focus() {
59
- const focusable = this.shadowRoot && this.shadowRoot.querySelector('.d2l-focus-trap-start');
60
- if (focusable) focusable.focus();
61
- }
62
-
63
61
  _focusFirst() {
64
62
  const focusable = this.shadowRoot &&
65
63
  getNextFocusable(this.shadowRoot.querySelector('.d2l-focus-trap-start'));
@@ -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 { getUniqueId } from '../../helpers/uniqueId.js';
5
6
  import { ifDefined } from 'lit-html/directives/if-defined.js';
6
7
  import { offscreenStyles } from '../offscreen/offscreen.js';
@@ -56,7 +57,7 @@ export const checkboxStyles = css`
56
57
  * @slot - Checkbox information (e.g., text)
57
58
  * @fires change - Dispatched when the checkbox's state changes
58
59
  */
59
- class InputCheckbox extends SkeletonMixin(RtlMixin(LitElement)) {
60
+ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
60
61
 
61
62
  static get properties() {
62
63
  return {
@@ -163,6 +164,8 @@ class InputCheckbox extends SkeletonMixin(RtlMixin(LitElement)) {
163
164
  ];
164
165
  }
165
166
 
167
+ static focusElementSelector = 'input.d2l-input-checkbox';
168
+
166
169
  constructor() {
167
170
  super();
168
171
  this.checked = false;
@@ -205,11 +208,6 @@ class InputCheckbox extends SkeletonMixin(RtlMixin(LitElement)) {
205
208
  `;
206
209
  }
207
210
 
208
- focus() {
209
- const elem = this.shadowRoot && this.shadowRoot.querySelector('input.d2l-input-checkbox');
210
- if (elem) elem.focus();
211
- }
212
-
213
211
  simulateClick() {
214
212
  this.checked = !this.checked;
215
213
  this.indeterminate = false;
@@ -4,6 +4,7 @@ import './input-fieldset.js';
4
4
  import '../tooltip/tooltip.js';
5
5
  import { css, html, LitElement } from 'lit-element/lit-element.js';
6
6
  import { formatDateTimeInISO, getDateFromISODate, parseISODateTime } from '../../helpers/dateTime.js';
7
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
7
8
  import { FormElementMixin } from '../form/form-element-mixin.js';
8
9
  import { getUniqueId } from '../../helpers/uniqueId.js';
9
10
  import { ifDefined } from 'lit-html/directives/if-defined.js';
@@ -30,7 +31,7 @@ export function getShiftedEndDate(startValue, endValue, prevStartValue, inclusiv
30
31
  * A component consisting of two input-date components - one for start of range and one for end of range. Values specified for these components (through start-value and/or end-value attributes) should be localized to the user's timezone if applicable and must be in ISO 8601 calendar date format ("YYYY-MM-DD").
31
32
  * @fires change - Dispatched when there is a change to selected start date or selected end date. `start-value` and `end-value` correspond to the selected values and are formatted in ISO 8601 calendar date format (`YYYY-MM-DD`).
32
33
  */
33
- class InputDateRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCoreElement(LitElement)))) {
34
+ class InputDateRange extends FocusMixin(SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCoreElement(LitElement))))) {
34
35
 
35
36
  static get properties() {
36
37
  return {
@@ -128,6 +129,8 @@ class InputDateRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCor
128
129
  `];
129
130
  }
130
131
 
132
+ static focusElementSelector = 'd2l-input-date';
133
+
131
134
  constructor() {
132
135
  super();
133
136
 
@@ -251,11 +254,6 @@ class InputDateRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCor
251
254
  });
252
255
  }
253
256
 
254
- focus() {
255
- const input = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-date');
256
- if (input) input.focus();
257
- }
258
-
259
257
  async validate() {
260
258
  if (!this.shadowRoot) return;
261
259
  const startDateInput = this.shadowRoot.querySelector('.d2l-input-date-range-start');
@@ -5,6 +5,7 @@ import '../tooltip/tooltip.js';
5
5
  import { convertLocalToUTCDateTime, convertUTCToLocalDateTime } from '@brightspace-ui/intl/lib/dateTime.js';
6
6
  import { css, html, LitElement } from 'lit-element/lit-element.js';
7
7
  import { formatDateTimeInISO, getAdjustedTime, getDateFromISODateTime, getDateNoConversion, parseISODateTime } from '../../helpers/dateTime.js';
8
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
8
9
  import { FormElementMixin } from '../form/form-element-mixin.js';
9
10
  import { getUniqueId } from '../../helpers/uniqueId.js';
10
11
  import { ifDefined } from 'lit-html/directives/if-defined.js';
@@ -63,7 +64,7 @@ export function getShiftedEndDateTime(startValue, endValue, prevStartValue, incl
63
64
  * @slot end - Optional content that would appear below the end input-date-time
64
65
  * @fires change - Dispatched when there is a change to selected start date-time or selected end date-time. `start-value` and `end-value` correspond to the selected values and are formatted in ISO 8601 combined date and time format (`YYYY-MM-DDTHH:mm:ss.sssZ`).
65
66
  */
66
- class InputDateTimeRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCoreElement(LitElement)))) {
67
+ class InputDateTimeRange extends FocusMixin(SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCoreElement(LitElement))))) {
67
68
 
68
69
  static get properties() {
69
70
  return {
@@ -171,6 +172,8 @@ class InputDateTimeRange extends SkeletonMixin(FormElementMixin(RtlMixin(Localiz
171
172
  `];
172
173
  }
173
174
 
175
+ static focusElementSelector = 'd2l-input-date-time';
176
+
174
177
  constructor() {
175
178
  super();
176
179
 
@@ -307,11 +310,6 @@ class InputDateTimeRange extends SkeletonMixin(FormElementMixin(RtlMixin(Localiz
307
310
  });
308
311
  }
309
312
 
310
- focus() {
311
- const input = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-date-time');
312
- if (input) input.focus();
313
- }
314
-
315
313
  async validate() {
316
314
  if (!this.shadowRoot) return;
317
315
  const startDateTimeInput = this.shadowRoot.querySelector('.d2l-input-date-time-range-start');
@@ -13,6 +13,7 @@ import { formatDateInISO,
13
13
  parseISODate,
14
14
  parseISODateTime,
15
15
  parseISOTime } from '../../helpers/dateTime.js';
16
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
16
17
  import { FormElementMixin } from '../form/form-element-mixin.js';
17
18
  import { getDefaultTime } from './input-time.js';
18
19
  import { getDocumentLocaleSettings } from '@brightspace-ui/intl/lib/common.js';
@@ -40,7 +41,7 @@ function _getFormattedDefaultTime(defaultValue) {
40
41
  * A component that consists of a "<d2l-input-date>" and a "<d2l-input-time>" component. The time input only appears once a date is selected. This component displays the "value" if one is specified, and reflects the selected value when one is selected or entered.
41
42
  * @fires change - Dispatched when there is a change to selected date or selected time. `value` corresponds to the selected value and is formatted in ISO 8601 combined date and time format (`YYYY-MM-DDTHH:mm:ss.sssZ`).
42
43
  */
43
- class InputDateTime extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(RtlMixin(LitElement))))) {
44
+ class InputDateTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(RtlMixin(LitElement)))))) {
44
45
 
45
46
  static get properties() {
46
47
  return {
@@ -112,6 +113,8 @@ class InputDateTime extends LabelledMixin(SkeletonMixin(FormElementMixin(Localiz
112
113
  `];
113
114
  }
114
115
 
116
+ static focusElementSelector = 'd2l-input-date';
117
+
115
118
  constructor() {
116
119
  super();
117
120
  this.disabled = false;
@@ -295,11 +298,6 @@ class InputDateTime extends LabelledMixin(SkeletonMixin(FormElementMixin(Localiz
295
298
  });
296
299
  }
297
300
 
298
- focus() {
299
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-date');
300
- if (elem) elem.focus();
301
- }
302
-
303
301
  async validate() {
304
302
  if (!this.shadowRoot) return;
305
303
  const dateInput = this.shadowRoot.querySelector('d2l-input-date');
@@ -8,6 +8,7 @@ import './input-text.js';
8
8
  import { css, html, LitElement } from 'lit-element/lit-element.js';
9
9
  import { formatDate, parseDate } from '@brightspace-ui/intl/lib/dateTime.js';
10
10
  import { formatDateInISO, getDateFromISODate, getDateTimeDescriptorShared, getToday } from '../../helpers/dateTime.js';
11
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
11
12
  import { FormElementMixin } from '../form/form-element-mixin.js';
12
13
  import { getUniqueId } from '../../helpers/uniqueId.js';
13
14
  import { ifDefined } from 'lit-html/directives/if-defined.js';
@@ -27,7 +28,7 @@ export function formatISODateInUserCalDescriptor(val) {
27
28
  * A component that consists of a text input field for typing a date and an attached calendar (d2l-calendar) dropdown. It displays the "value" if one is specified, or a placeholder if not, and reflects the selected value when one is selected in the calendar or entered in the text input.
28
29
  * @fires change - Dispatched when there is a change to selected date. `value` corresponds to the selected value and is formatted in ISO 8601 calendar date format (`YYYY-MM-DD`).
29
30
  */
30
- class InputDate extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(LitElement)))) {
31
+ class InputDate extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(LitElement))))) {
31
32
 
32
33
  static get properties() {
33
34
  return {
@@ -137,6 +138,8 @@ class InputDate extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCor
137
138
  `];
138
139
  }
139
140
 
141
+ static focusElementSelector = 'd2l-input-text';
142
+
140
143
  constructor() {
141
144
  super();
142
145
 
@@ -331,10 +334,6 @@ class InputDate extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCor
331
334
  });
332
335
  }
333
336
 
334
- focus() {
335
- if (this._textInput) this._textInput.focus();
336
- }
337
-
338
337
  async validate() {
339
338
  if (!this.shadowRoot) return;
340
339
  const textInput = this.shadowRoot.querySelector('d2l-input-text');
@@ -1,6 +1,7 @@
1
1
  import './input-text.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
3
  import { formatNumber, getNumberDescriptor, parseNumber } from '@brightspace-ui/intl/lib/number.js';
4
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
4
5
  import { FormElementMixin } from '../form/form-element-mixin.js';
5
6
  import { getUniqueId } from '../../helpers/uniqueId.js';
6
7
  import { ifDefined } from 'lit-html/directives/if-defined.js';
@@ -68,7 +69,7 @@ function roundPrecisely(val, maxFractionDigits) {
68
69
  * @slot right - Slot within the input on the right side. Useful for an "icon" or "button-icon".
69
70
  * @fires change - Dispatched when an alteration to the value is committed (typically after focus is lost) by the user. The `value` attribute reflects a JavaScript Number which is parsed from the formatted input value.
70
71
  */
71
- class InputNumber extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(LitElement)))) {
72
+ class InputNumber extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(LitElement))))) {
72
73
 
73
74
  static get properties() {
74
75
  return {
@@ -185,6 +186,8 @@ class InputNumber extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeC
185
186
  ];
186
187
  }
187
188
 
189
+ static focusElementSelector = 'd2l-input-text';
190
+
188
191
  constructor() {
189
192
  super();
190
193
  this.autofocus = false;
@@ -364,16 +367,6 @@ class InputNumber extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeC
364
367
  });
365
368
  }
366
369
 
367
- async focus() {
368
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-text');
369
- if (elem) {
370
- elem.focus();
371
- } else {
372
- await this.updateComplete;
373
- this.focus();
374
- }
375
- }
376
-
377
370
  async validate() {
378
371
  if (!this.shadowRoot) return;
379
372
  const inputTextElem = this.shadowRoot.querySelector('d2l-input-text');
@@ -1,5 +1,6 @@
1
1
  import './input-number.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
3
4
  import { FormElementMixin } from '../form/form-element-mixin.js';
4
5
  import { ifDefined } from 'lit-html/directives/if-defined.js';
5
6
  import { LabelledMixin } from '../../mixins/labelled-mixin.js';
@@ -12,7 +13,7 @@ import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
12
13
  * @slot after - Slot beside the input on the right side. Useful for an "icon" or "button-icon".
13
14
  * @fires change - Dispatched when an alteration to the value is committed (typically after focus is lost) by the user. The `value` attribute reflects a JavaScript Number which is parsed from the formatted input value.
14
15
  */
15
- class InputPercent extends LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(RtlMixin(LitElement))))) {
16
+ class InputPercent extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(LocalizeCoreElement(RtlMixin(LitElement)))))) {
16
17
 
17
18
  static get properties() {
18
19
  return {
@@ -85,6 +86,8 @@ class InputPercent extends LabelledMixin(SkeletonMixin(FormElementMixin(Localize
85
86
  ];
86
87
  }
87
88
 
89
+ static focusElementSelector = 'd2l-input-number';
90
+
88
91
  constructor() {
89
92
  super();
90
93
  this.autofocus = false;
@@ -131,11 +134,6 @@ class InputPercent extends LabelledMixin(SkeletonMixin(FormElementMixin(Localize
131
134
  `;
132
135
  }
133
136
 
134
- focus() {
135
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-number');
136
- if (elem) elem.focus();
137
- }
138
-
139
137
  async validate() {
140
138
  if (!this.shadowRoot) return;
141
139
  const inputNumberElem = this.shadowRoot.querySelector('d2l-input-number');
@@ -2,6 +2,7 @@ import '../button/button-icon.js';
2
2
  import '../colors/colors.js';
3
3
  import './input-text.js';
4
4
  import { css, html, LitElement } from 'lit-element/lit-element.js';
5
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
5
6
  import { ifDefined } from 'lit-html/directives/if-defined.js';
6
7
  import { inputStyles } from './input-styles.js';
7
8
  import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
@@ -11,7 +12,7 @@ import { RtlMixin } from '../../mixins/rtl-mixin.js';
11
12
  * This component wraps the native "<input type="search">"" element and is for text searching.
12
13
  * @fires d2l-input-search-searched - Dispatched when a search is performed. When the input is cleared, this will be fired with an empty value.
13
14
  */
14
- class InputSearch extends LocalizeCoreElement(RtlMixin(LitElement)) {
15
+ class InputSearch extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
15
16
 
16
17
  static get properties() {
17
18
  return {
@@ -73,6 +74,8 @@ class InputSearch extends LocalizeCoreElement(RtlMixin(LitElement)) {
73
74
  ];
74
75
  }
75
76
 
77
+ static focusElementSelector = 'd2l-input-text';
78
+
76
79
  constructor() {
77
80
  super();
78
81
  this._lastSearchValue = '';
@@ -122,11 +125,6 @@ class InputSearch extends LocalizeCoreElement(RtlMixin(LitElement)) {
122
125
  `;
123
126
  }
124
127
 
125
- focus() {
126
- const elem = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-text');
127
- if (elem) elem.focus();
128
- }
129
-
130
128
  search() {
131
129
  this._setLastSearchValue(this.value);
132
130
  this._dispatchEvent();
@@ -1,6 +1,7 @@
1
1
  import '../tooltip/tooltip.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 { formatNumber } from '@brightspace-ui/intl/lib/number.js';
5
6
  import { FormElementMixin } from '../form/form-element-mixin.js';
6
7
  import { getUniqueId } from '../../helpers/uniqueId.js';
@@ -22,7 +23,7 @@ import { styleMap } from 'lit-html/directives/style-map.js';
22
23
  * @fires change - Dispatched when an alteration to the value is committed (typically after focus is lost) by the user
23
24
  * @fires input - Dispatched immediately after changes by the user
24
25
  */
25
- class InputText extends LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(LitElement)))) {
26
+ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(LitElement))))) {
26
27
 
27
28
  static get properties() {
28
29
  return {
@@ -234,6 +235,8 @@ class InputText extends LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(Li
234
235
  ];
235
236
  }
236
237
 
238
+ static focusElementSelector = '.d2l-input';
239
+
237
240
  constructor() {
238
241
  super();
239
242
  this.autofocus = false;
@@ -463,16 +466,6 @@ class InputText extends LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(Li
463
466
  });
464
467
  }
465
468
 
466
- async focus() {
467
- const elem = this.shadowRoot && this.shadowRoot.querySelector('.d2l-input');
468
- if (elem) {
469
- elem.focus();
470
- } else {
471
- await this.updateComplete;
472
- this.focus();
473
- }
474
- }
475
-
476
469
  _getAriaLabel() {
477
470
  if (this.label && (this.labelHidden || this.labelledBy)) {
478
471
  return this.label;
@@ -1,5 +1,6 @@
1
1
  import '../tooltip/tooltip.js';
2
2
  import { css, html, LitElement } from 'lit-element/lit-element.js';
3
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
3
4
  import { formatNumber } from '@brightspace-ui/intl/lib/number.js';
4
5
  import { FormElementMixin } from '../form/form-element-mixin.js';
5
6
  import { getUniqueId } from '../../helpers/uniqueId.js';
@@ -17,7 +18,7 @@ import { styleMap } from 'lit-html/directives/style-map.js';
17
18
  * @fires change - Dispatched when an alteration to the value is committed (typically after focus is lost) by the user
18
19
  * @fires input - Dispatched immediately after changes by the user
19
20
  */
20
- class InputTextArea extends LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(LitElement)))) {
21
+ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixin(LitElement))))) {
21
22
 
22
23
  static get properties() {
23
24
  return {
@@ -149,6 +150,8 @@ class InputTextArea extends LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixi
149
150
  `];
150
151
  }
151
152
 
153
+ static focusElementSelector = 'textarea';
154
+
152
155
  constructor() {
153
156
  super();
154
157
  this.disabled = false;
@@ -263,16 +266,6 @@ class InputTextArea extends LabelledMixin(FormElementMixin(SkeletonMixin(RtlMixi
263
266
  });
264
267
  }
265
268
 
266
- async focus() {
267
- const elem = this.shadowRoot && this.shadowRoot.querySelector('textarea');
268
- if (elem) {
269
- elem.focus();
270
- } else {
271
- await this.updateComplete;
272
- this.focus();
273
- }
274
- }
275
-
276
269
  async select() {
277
270
  const elem = this.shadowRoot && this.shadowRoot.querySelector('textarea');
278
271
  if (elem) {
@@ -4,6 +4,7 @@ import '../tooltip/tooltip.js';
4
4
  import { css, html, LitElement } from 'lit-element/lit-element.js';
5
5
  import { formatDateInISOTime, formatTimeInISO, getAdjustedTime, getDateFromISOTime, isValidTime, parseISOTime } from '../../helpers/dateTime.js';
6
6
  import { getDefaultTime, getIntervalNumber, getTimeAtInterval } from './input-time.js';
7
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
7
8
  import { FormElementMixin } from '../form/form-element-mixin.js';
8
9
  import { getUniqueId } from '../../helpers/uniqueId.js';
9
10
  import { ifDefined } from 'lit-html/directives/if-defined.js';
@@ -38,7 +39,7 @@ function getValidISOTimeAtInterval(val, timeInterval) {
38
39
  * @fires change - Dispatched when there is a change to selected start time or selected end time. `start-value` and `end-value` correspond to the selected values and are formatted in ISO 8601 calendar time format (`hh:mm:ss`).
39
40
  */
40
41
 
41
- class InputTimeRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCoreElement(LitElement)))) {
42
+ class InputTimeRange extends FocusMixin(SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCoreElement(LitElement))))) {
42
43
 
43
44
  static get properties() {
44
45
  return {
@@ -136,6 +137,8 @@ class InputTimeRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCor
136
137
  `];
137
138
  }
138
139
 
140
+ static focusElementSelector = 'd2l-input-time';
141
+
139
142
  constructor() {
140
143
  super();
141
144
 
@@ -302,11 +305,6 @@ class InputTimeRange extends SkeletonMixin(FormElementMixin(RtlMixin(LocalizeCor
302
305
  });
303
306
  }
304
307
 
305
- focus() {
306
- const input = this.shadowRoot && this.shadowRoot.querySelector('d2l-input-time');
307
- if (input) input.focus();
308
- }
309
-
310
308
  async validate() {
311
309
  if (!this.shadowRoot) return;
312
310
  const startTimeInput = this.shadowRoot.querySelector('.d2l-input-time-range-start');
@@ -7,6 +7,7 @@ import { css, html, LitElement } from 'lit-element/lit-element.js';
7
7
  import { formatDateInISOTime, getDateFromISOTime, getToday } from '../../helpers/dateTime.js';
8
8
  import { formatTime, parseTime } from '@brightspace-ui/intl/lib/dateTime.js';
9
9
  import { bodySmallStyles } from '../typography/styles.js';
10
+ import { FocusMixin } from '../../mixins/focus-mixin.js';
10
11
  import { FormElementMixin } from '../form/form-element-mixin.js';
11
12
  import { getUniqueId } from '../../helpers/uniqueId.js';
12
13
  import { ifDefined } from 'lit-html/directives/if-defined.js';
@@ -116,7 +117,7 @@ function initIntervals(size, enforceTimeIntervals) {
116
117
  * A component that consists of a text input field for typing a time and an attached dropdown for time selection. It displays the "value" if one is specified, or a placeholder if not, and reflects the selected value when one is selected in the dropdown or entered in the text input.
117
118
  * @fires change - Dispatched when there is a change to selected time. `value` corresponds to the selected value and is formatted in ISO 8601 time format (`hh:mm:ss`).
118
119
  */
119
- class InputTime extends LabelledMixin(SkeletonMixin(FormElementMixin(LitElement))) {
120
+ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(LitElement)))) {
120
121
 
121
122
  static get properties() {
122
123
  return {
@@ -214,6 +215,8 @@ class InputTime extends LabelledMixin(SkeletonMixin(FormElementMixin(LitElement)
214
215
  ];
215
216
  }
216
217
 
218
+ static focusElementSelector = '.d2l-input';
219
+
217
220
  constructor() {
218
221
  super();
219
222
  this.disabled = false;
@@ -349,11 +352,6 @@ class InputTime extends LabelledMixin(SkeletonMixin(FormElementMixin(LitElement)
349
352
  });
350
353
  }
351
354
 
352
- focus() {
353
- const elem = this.shadowRoot && this.shadowRoot.querySelector('.d2l-input');
354
- if (elem) elem.focus();
355
- }
356
-
357
355
  getTime() {
358
356
  const time = getDateFromISOTime(this.value);
359
357
  return {
@@ -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);