@vaadin/a11y-base 25.2.0-alpha9 → 25.2.0-beta2

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.
@@ -8,101 +8,100 @@ import { isKeyboardActive } from './focus-utils.js';
8
8
 
9
9
  /**
10
10
  * A mixin to handle `focused` and `focus-ring` attributes based on focus.
11
- *
12
- * @polymerMixin
13
11
  */
14
- export const FocusMixin = dedupeMixin(
15
- (superclass) =>
16
- class FocusMixinClass extends superclass {
17
- /**
18
- * @protected
19
- * @return {boolean}
20
- */
21
- get _keyboardActive() {
22
- return isKeyboardActive();
23
- }
12
+ const FocusMixinImplementation = (superclass) => {
13
+ return class FocusMixinClass extends superclass {
14
+ /**
15
+ * @protected
16
+ * @return {boolean}
17
+ */
18
+ get _keyboardActive() {
19
+ return isKeyboardActive();
20
+ }
24
21
 
25
- /** @protected */
26
- ready() {
27
- this.addEventListener('focusin', (e) => {
28
- if (this._shouldSetFocus(e)) {
29
- this._setFocused(true);
30
- }
31
- });
22
+ /** @protected */
23
+ ready() {
24
+ this.addEventListener('focusin', (e) => {
25
+ if (this._shouldSetFocus(e)) {
26
+ this._setFocused(true);
27
+ }
28
+ });
32
29
 
33
- this.addEventListener('focusout', (e) => {
34
- if (this._shouldRemoveFocus(e)) {
35
- this._setFocused(false);
36
- }
37
- });
30
+ this.addEventListener('focusout', (e) => {
31
+ if (this._shouldRemoveFocus(e)) {
32
+ this._setFocused(false);
33
+ }
34
+ });
38
35
 
39
- // In super.ready() other 'focusin' and 'focusout' listeners might be
40
- // added, so we call it after our own ones to ensure they execute first.
41
- // Issue to watch out: when incorrect, <vaadin-combo-box> refocuses the
42
- // input field on iOS after "Done" is pressed.
43
- super.ready();
44
- }
36
+ // In super.ready() other 'focusin' and 'focusout' listeners might be
37
+ // added, so we call it after our own ones to ensure they execute first.
38
+ // Issue to watch out: when incorrect, <vaadin-combo-box> refocuses the
39
+ // input field on iOS after "Done" is pressed.
40
+ super.ready();
41
+ }
45
42
 
46
- /** @protected */
47
- disconnectedCallback() {
48
- super.disconnectedCallback();
43
+ /** @protected */
44
+ disconnectedCallback() {
45
+ super.disconnectedCallback();
49
46
 
50
- // In non-Chrome browsers, blur does not fire on the element when it is disconnected.
51
- // reproducible in `<vaadin-date-picker>` when closing on `Cancel` or `Today` click.
52
- if (this.hasAttribute('focused')) {
53
- this._setFocused(false);
54
- }
47
+ // In non-Chrome browsers, blur does not fire on the element when it is disconnected.
48
+ // reproducible in `<vaadin-date-picker>` when closing on `Cancel` or `Today` click.
49
+ if (this.hasAttribute('focused')) {
50
+ this._setFocused(false);
55
51
  }
52
+ }
56
53
 
57
- /**
58
- * @param {FocusOptions=} options
59
- * @protected
60
- * @override
61
- */
62
- focus(options) {
63
- super.focus(options);
54
+ /**
55
+ * @param {FocusOptions=} options
56
+ * @protected
57
+ * @override
58
+ */
59
+ focus(options) {
60
+ super.focus(options);
64
61
 
65
- // Set focus-ring attribute on programmatic focus by default
66
- // unless explicitly disabled by `{ focusVisible: false }`.
67
- if (!(options && options.focusVisible === false)) {
68
- this.setAttribute('focus-ring', '');
69
- }
62
+ // Set focus-ring attribute on programmatic focus by default
63
+ // unless explicitly disabled by `{ focusVisible: false }`.
64
+ if (options?.focusVisible !== false) {
65
+ this.setAttribute('focus-ring', '');
70
66
  }
67
+ }
71
68
 
72
- /**
73
- * Override to change how focused and focus-ring attributes are set.
74
- *
75
- * @param {boolean} focused
76
- * @protected
77
- */
78
- _setFocused(focused) {
79
- this.toggleAttribute('focused', focused);
69
+ /**
70
+ * Override to change how focused and focus-ring attributes are set.
71
+ *
72
+ * @param {boolean} focused
73
+ * @protected
74
+ */
75
+ _setFocused(focused) {
76
+ this.toggleAttribute('focused', focused);
80
77
 
81
- // Focus-ring is true when the element was focused from the keyboard.
82
- // Focus Ring [A11ycasts]: https://youtu.be/ilj2P5-5CjI
83
- this.toggleAttribute('focus-ring', focused && this._keyboardActive);
84
- }
78
+ // Focus-ring is true when the element was focused from the keyboard.
79
+ // Focus Ring [A11ycasts]: https://youtu.be/ilj2P5-5CjI
80
+ this.toggleAttribute('focus-ring', focused && this._keyboardActive);
81
+ }
85
82
 
86
- /**
87
- * Override to define if the field receives focus based on the event.
88
- *
89
- * @param {FocusEvent} _event
90
- * @return {boolean}
91
- * @protected
92
- */
93
- _shouldSetFocus(_event) {
94
- return true;
95
- }
83
+ /**
84
+ * Override to define if the field receives focus based on the event.
85
+ *
86
+ * @param {FocusEvent} _event
87
+ * @return {boolean}
88
+ * @protected
89
+ */
90
+ _shouldSetFocus(_event) {
91
+ return true;
92
+ }
96
93
 
97
- /**
98
- * Override to define if the field loses focus based on the event.
99
- *
100
- * @param {FocusEvent} _event
101
- * @return {boolean}
102
- * @protected
103
- */
104
- _shouldRemoveFocus(_event) {
105
- return true;
106
- }
107
- },
108
- );
94
+ /**
95
+ * Override to define if the field loses focus based on the event.
96
+ *
97
+ * @param {FocusEvent} _event
98
+ * @return {boolean}
99
+ * @protected
100
+ */
101
+ _shouldRemoveFocus(_event) {
102
+ return true;
103
+ }
104
+ };
105
+ };
106
+
107
+ export const FocusMixin = dedupeMixin(FocusMixinImplementation);
@@ -8,9 +8,6 @@ import { KeyboardMixin } from './keyboard-mixin.js';
8
8
 
9
9
  /**
10
10
  * A mixin for navigating items with keyboard.
11
- *
12
- * @polymerMixin
13
- * @mixes KeyboardMixin
14
11
  */
15
12
  export const KeyboardDirectionMixin = (superclass) =>
16
13
  class KeyboardDirectionMixinClass extends KeyboardMixin(superclass) {
@@ -127,7 +124,7 @@ export const KeyboardDirectionMixin = (superclass) =>
127
124
 
128
125
  if (idx >= 0) {
129
126
  event.preventDefault();
130
- this._focus(idx, { focusVisible: true }, true);
127
+ this._focus(idx, { focusVisible: true, preventScroll: true }, true);
131
128
  }
132
129
  }
133
130
 
@@ -9,77 +9,76 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin';
9
9
  * A mixin that manages keyboard handling.
10
10
  * The mixin subscribes to the keyboard events while an actual implementation
11
11
  * for the event handlers is left to the client (a component or another mixin).
12
- *
13
- * @polymerMixin
14
12
  */
15
- export const KeyboardMixin = dedupeMixin(
16
- (superclass) =>
17
- class KeyboardMixinClass extends superclass {
18
- /** @protected */
19
- ready() {
20
- super.ready();
13
+ const KeyboardMixinImplementation = (superclass) => {
14
+ return class KeyboardMixinClass extends superclass {
15
+ /** @protected */
16
+ ready() {
17
+ super.ready();
21
18
 
22
- this.addEventListener('keydown', (event) => {
23
- this._onKeyDown(event);
24
- });
19
+ this.addEventListener('keydown', (event) => {
20
+ this._onKeyDown(event);
21
+ });
25
22
 
26
- this.addEventListener('keyup', (event) => {
27
- this._onKeyUp(event);
28
- });
29
- }
23
+ this.addEventListener('keyup', (event) => {
24
+ this._onKeyUp(event);
25
+ });
26
+ }
30
27
 
31
- /**
32
- * A handler for the `keydown` event. By default, it calls
33
- * separate methods for handling "Enter" and "Escape" keys.
34
- * Override the method to implement your own behavior.
35
- *
36
- * @param {KeyboardEvent} event
37
- * @protected
38
- */
39
- _onKeyDown(event) {
40
- switch (event.key) {
41
- case 'Enter':
42
- this._onEnter(event);
43
- break;
44
- case 'Escape':
45
- this._onEscape(event);
46
- break;
47
- default:
48
- break;
49
- }
28
+ /**
29
+ * A handler for the `keydown` event. By default, it calls
30
+ * separate methods for handling "Enter" and "Escape" keys.
31
+ * Override the method to implement your own behavior.
32
+ *
33
+ * @param {KeyboardEvent} event
34
+ * @protected
35
+ */
36
+ _onKeyDown(event) {
37
+ switch (event.key) {
38
+ case 'Enter':
39
+ this._onEnter(event);
40
+ break;
41
+ case 'Escape':
42
+ this._onEscape(event);
43
+ break;
44
+ default:
45
+ break;
50
46
  }
47
+ }
51
48
 
52
- /**
53
- * A handler for the `keyup` event. By default, it does nothing.
54
- * Override the method to implement your own behavior.
55
- *
56
- * @param {KeyboardEvent} _event
57
- * @protected
58
- */
59
- _onKeyUp(_event) {
60
- // To be implemented.
61
- }
49
+ /**
50
+ * A handler for the `keyup` event. By default, it does nothing.
51
+ * Override the method to implement your own behavior.
52
+ *
53
+ * @param {KeyboardEvent} _event
54
+ * @protected
55
+ */
56
+ _onKeyUp(_event) {
57
+ // To be implemented.
58
+ }
62
59
 
63
- /**
64
- * A handler for the "Enter" key. By default, it does nothing.
65
- * Override the method to implement your own behavior.
66
- *
67
- * @param {KeyboardEvent} _event
68
- * @protected
69
- */
70
- _onEnter(_event) {
71
- // To be implemented.
72
- }
60
+ /**
61
+ * A handler for the "Enter" key. By default, it does nothing.
62
+ * Override the method to implement your own behavior.
63
+ *
64
+ * @param {KeyboardEvent} _event
65
+ * @protected
66
+ */
67
+ _onEnter(_event) {
68
+ // To be implemented.
69
+ }
73
70
 
74
- /**
75
- * A handler for the "Escape" key. By default, it does nothing.
76
- * Override the method to implement your own behavior.
77
- *
78
- * @param {KeyboardEvent} _event
79
- * @protected
80
- */
81
- _onEscape(_event) {
82
- // To be implemented.
83
- }
84
- },
85
- );
71
+ /**
72
+ * A handler for the "Escape" key. By default, it does nothing.
73
+ * Override the method to implement your own behavior.
74
+ *
75
+ * @param {KeyboardEvent} _event
76
+ * @protected
77
+ */
78
+ _onEscape(_event) {
79
+ // To be implemented.
80
+ }
81
+ };
82
+ };
83
+
84
+ export const KeyboardMixin = dedupeMixin(KeyboardMixinImplementation);
package/src/list-mixin.js CHANGED
@@ -12,9 +12,6 @@ import { KeyboardDirectionMixin } from './keyboard-direction-mixin.js';
12
12
 
13
13
  /**
14
14
  * A mixin for list elements, facilitating navigation and selection of items.
15
- *
16
- * @polymerMixin
17
- * @mixes KeyboardDirectionMixin
18
15
  */
19
16
  export const ListMixin = (superClass) =>
20
17
  class ListMixinClass extends KeyboardDirectionMixin(superClass) {
@@ -285,40 +282,19 @@ export const ListMixin = (superClass) =>
285
282
  });
286
283
  this._setFocusable(idx);
287
284
  this._scrollToItem(idx);
288
- super._focus(idx, options);
285
+ super._focus(idx, options ?? { preventScroll: true });
289
286
  }
290
287
 
291
288
  /**
292
- * Scroll the container to have the next item by the edge of the viewport.
289
+ * Scroll the container to have the item visible.
293
290
  * @param {number} idx
294
291
  * @protected
295
292
  */
296
293
  _scrollToItem(idx) {
297
- const item = this.items[idx];
298
- if (!item) {
299
- return;
294
+ const item = this._getItems()[idx];
295
+ if (item) {
296
+ item.scrollIntoView({ block: 'nearest', inline: 'nearest' });
300
297
  }
301
-
302
- const props = this._vertical ? ['top', 'bottom'] : this._isRTL ? ['right', 'left'] : ['left', 'right'];
303
-
304
- const scrollerRect = this._scrollerElement.getBoundingClientRect();
305
- const nextItemRect = (this.items[idx + 1] || item).getBoundingClientRect();
306
- const prevItemRect = (this.items[idx - 1] || item).getBoundingClientRect();
307
-
308
- let scrollDistance = 0;
309
- if (
310
- (!this._isRTL && nextItemRect[props[1]] >= scrollerRect[props[1]]) ||
311
- (this._isRTL && nextItemRect[props[1]] <= scrollerRect[props[1]])
312
- ) {
313
- scrollDistance = nextItemRect[props[1]] - scrollerRect[props[1]];
314
- } else if (
315
- (!this._isRTL && prevItemRect[props[0]] <= scrollerRect[props[0]]) ||
316
- (this._isRTL && prevItemRect[props[0]] >= scrollerRect[props[0]])
317
- ) {
318
- scrollDistance = prevItemRect[props[0]] - scrollerRect[props[0]];
319
- }
320
-
321
- this._scroll(scrollDistance);
322
298
  }
323
299
 
324
300
  /**
@@ -350,13 +326,4 @@ export const ListMixin = (superClass) =>
350
326
 
351
327
  return super._isItemFocusable(item);
352
328
  }
353
-
354
- /**
355
- * Fired when the selection is changed.
356
- * Not fired when used in `multiple` selection mode.
357
- *
358
- * @event selected-changed
359
- * @param {Object} detail
360
- * @param {Object} detail.value the index of the item selected in the items array.
361
- */
362
329
  };
@@ -10,9 +10,6 @@ import { DisabledMixin } from './disabled-mixin.js';
10
10
  *
11
11
  * The attribute is set to -1 whenever the user disables the element
12
12
  * and restored with the last known value once the element is enabled.
13
- *
14
- * @polymerMixin
15
- * @mixes DisabledMixin
16
13
  */
17
14
  export const TabindexMixin = (superclass) =>
18
15
  class TabindexMixinClass extends DisabledMixin(superclass) {