@vaadin/a11y-base 25.1.2 → 25.2.0-alpha10

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.
@@ -10,7 +10,22 @@
10
10
  "kind": "mixin",
11
11
  "description": "A mixin to toggle the `active` attribute.\n\nThe attribute is set whenever the user activates the element by a pointer\nor presses an activation key on the element from the keyboard.\n\nThe attribute is removed as soon as the element is deactivated\nby the pointer or by releasing the activation key.",
12
12
  "name": "ActiveMixin",
13
- "members": [],
13
+ "members": [
14
+ {
15
+ "kind": "field",
16
+ "name": "disabled",
17
+ "privacy": "public",
18
+ "type": {
19
+ "text": "boolean"
20
+ },
21
+ "description": "If true, the user cannot interact with this element.",
22
+ "attribute": "disabled",
23
+ "inheritedFrom": {
24
+ "name": "DisabledMixin",
25
+ "module": "src/disabled-mixin.js"
26
+ }
27
+ }
28
+ ],
14
29
  "mixins": [
15
30
  {
16
31
  "name": "DisabledMixin",
@@ -25,6 +40,20 @@
25
40
  {
26
41
  "name": "superclass"
27
42
  }
43
+ ],
44
+ "attributes": [
45
+ {
46
+ "name": "disabled",
47
+ "type": {
48
+ "text": "boolean"
49
+ },
50
+ "description": "If true, the user cannot interact with this element.",
51
+ "fieldName": "disabled",
52
+ "inheritedFrom": {
53
+ "name": "DisabledMixin",
54
+ "module": "src/disabled-mixin.js"
55
+ }
56
+ }
28
57
  ]
29
58
  }
30
59
  ],
@@ -44,9 +73,76 @@
44
73
  "path": "src/delegate-focus-mixin.js",
45
74
  "declarations": [
46
75
  {
47
- "kind": "variable",
76
+ "kind": "mixin",
77
+ "description": "",
48
78
  "name": "DelegateFocusMixin",
49
- "description": "A mixin to forward focus to an element in the light DOM."
79
+ "members": [
80
+ {
81
+ "kind": "field",
82
+ "name": "autofocus",
83
+ "privacy": "public",
84
+ "type": {
85
+ "text": "boolean"
86
+ },
87
+ "description": "Specify that this control should have input focus when the page loads.",
88
+ "attribute": "autofocus"
89
+ },
90
+ {
91
+ "kind": "field",
92
+ "name": "disabled",
93
+ "privacy": "public",
94
+ "type": {
95
+ "text": "boolean"
96
+ },
97
+ "description": "If true, the user cannot interact with this element.",
98
+ "attribute": "disabled",
99
+ "inheritedFrom": {
100
+ "name": "DisabledMixin",
101
+ "module": "src/disabled-mixin.js"
102
+ }
103
+ }
104
+ ],
105
+ "attributes": [
106
+ {
107
+ "name": "autofocus",
108
+ "type": {
109
+ "text": "boolean"
110
+ },
111
+ "description": "Specify that this control should have input focus when the page loads.",
112
+ "fieldName": "autofocus"
113
+ },
114
+ {
115
+ "name": "disabled",
116
+ "type": {
117
+ "text": "boolean"
118
+ },
119
+ "description": "If true, the user cannot interact with this element.",
120
+ "fieldName": "disabled",
121
+ "inheritedFrom": {
122
+ "name": "DisabledMixin",
123
+ "module": "src/disabled-mixin.js"
124
+ }
125
+ }
126
+ ],
127
+ "mixins": [
128
+ {
129
+ "name": "FocusMixin",
130
+ "module": "src/focus-mixin.js"
131
+ },
132
+ {
133
+ "name": "TabindexMixin",
134
+ "module": "src/tabindex-mixin.js"
135
+ },
136
+ {
137
+ "name": "dedupeMixin",
138
+ "package": "@open-wc/dedupe-mixin"
139
+ }
140
+ ],
141
+ "parameters": [
142
+ {
143
+ "name": "superclass"
144
+ }
145
+ ]
50
146
  }
51
147
  ],
52
148
  "exports": [
@@ -65,9 +161,42 @@
65
161
  "path": "src/disabled-mixin.js",
66
162
  "declarations": [
67
163
  {
68
- "kind": "variable",
164
+ "kind": "mixin",
165
+ "description": "",
69
166
  "name": "DisabledMixin",
70
- "description": "A mixin to provide disabled property for field components."
167
+ "members": [
168
+ {
169
+ "kind": "field",
170
+ "name": "disabled",
171
+ "privacy": "public",
172
+ "type": {
173
+ "text": "boolean"
174
+ },
175
+ "description": "If true, the user cannot interact with this element.",
176
+ "attribute": "disabled"
177
+ }
178
+ ],
179
+ "attributes": [
180
+ {
181
+ "name": "disabled",
182
+ "type": {
183
+ "text": "boolean"
184
+ },
185
+ "description": "If true, the user cannot interact with this element.",
186
+ "fieldName": "disabled"
187
+ }
188
+ ],
189
+ "parameters": [
190
+ {
191
+ "name": "superclass"
192
+ }
193
+ ],
194
+ "mixins": [
195
+ {
196
+ "name": "dedupeMixin",
197
+ "package": "@open-wc/dedupe-mixin"
198
+ }
199
+ ]
71
200
  }
72
201
  ],
73
202
  "exports": [
@@ -86,9 +215,21 @@
86
215
  "path": "src/focus-mixin.js",
87
216
  "declarations": [
88
217
  {
89
- "kind": "variable",
218
+ "kind": "mixin",
219
+ "description": "",
90
220
  "name": "FocusMixin",
91
- "description": "A mixin to handle `focused` and `focus-ring` attributes based on focus."
221
+ "members": [],
222
+ "parameters": [
223
+ {
224
+ "name": "superclass"
225
+ }
226
+ ],
227
+ "mixins": [
228
+ {
229
+ "name": "dedupeMixin",
230
+ "package": "@open-wc/dedupe-mixin"
231
+ }
232
+ ]
92
233
  }
93
234
  ],
94
235
  "exports": [
@@ -140,9 +281,21 @@
140
281
  "path": "src/keyboard-mixin.js",
141
282
  "declarations": [
142
283
  {
143
- "kind": "variable",
284
+ "kind": "mixin",
285
+ "description": "",
144
286
  "name": "KeyboardMixin",
145
- "description": "A mixin that manages keyboard handling.\nThe mixin subscribes to the keyboard events while an actual implementation\nfor the event handlers is left to the client (a component or another mixin)."
287
+ "members": [],
288
+ "parameters": [
289
+ {
290
+ "name": "superclass"
291
+ }
292
+ ],
293
+ "mixins": [
294
+ {
295
+ "name": "dedupeMixin",
296
+ "package": "@open-wc/dedupe-mixin"
297
+ }
298
+ ]
146
299
  }
147
300
  ],
148
301
  "exports": [
@@ -265,8 +418,36 @@
265
418
  "kind": "mixin",
266
419
  "description": "A mixin to toggle the `tabindex` attribute.\n\nThe attribute is set to -1 whenever the user disables the element\nand restored with the last known value once the element is enabled.",
267
420
  "name": "TabindexMixin",
268
- "members": [],
269
- "attributes": [],
421
+ "members": [
422
+ {
423
+ "kind": "field",
424
+ "name": "disabled",
425
+ "privacy": "public",
426
+ "type": {
427
+ "text": "boolean"
428
+ },
429
+ "description": "If true, the user cannot interact with this element.",
430
+ "attribute": "disabled",
431
+ "inheritedFrom": {
432
+ "name": "DisabledMixin",
433
+ "module": "src/disabled-mixin.js"
434
+ }
435
+ }
436
+ ],
437
+ "attributes": [
438
+ {
439
+ "name": "disabled",
440
+ "type": {
441
+ "text": "boolean"
442
+ },
443
+ "description": "If true, the user cannot interact with this element.",
444
+ "fieldName": "disabled",
445
+ "inheritedFrom": {
446
+ "name": "DisabledMixin",
447
+ "module": "src/disabled-mixin.js"
448
+ }
449
+ }
450
+ ],
270
451
  "mixins": [
271
452
  {
272
453
  "name": "DisabledMixin",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/a11y-base",
3
- "version": "25.1.2",
3
+ "version": "25.2.0-alpha10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -32,15 +32,15 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@open-wc/dedupe-mixin": "^1.3.0",
35
- "@vaadin/component-base": "~25.1.2",
35
+ "@vaadin/component-base": "25.2.0-alpha10",
36
36
  "lit": "^3.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@vaadin/chai-plugins": "~25.1.2",
40
- "@vaadin/test-runner-commands": "~25.1.2",
39
+ "@vaadin/chai-plugins": "25.2.0-alpha10",
40
+ "@vaadin/test-runner-commands": "25.2.0-alpha10",
41
41
  "@vaadin/testing-helpers": "^2.0.0",
42
42
  "sinon": "^21.0.2"
43
43
  },
44
44
  "customElements": "custom-elements.json",
45
- "gitHead": "48e5dc507ac5eb8d34839be06cac652f1635fe1c"
45
+ "gitHead": "1303b6a3eeecb44a9d26f2b53cb56d9e906febdf"
46
46
  }
@@ -27,7 +27,7 @@ let lockCount = 0;
27
27
  * @param {?Node} node
28
28
  * @return {boolean}
29
29
  */
30
- const isElement = (node) => node && node.nodeType === Node.ELEMENT_NODE;
30
+ const isElement = (node) => node?.nodeType === Node.ELEMENT_NODE;
31
31
 
32
32
  /**
33
33
  * @param {...unknown} args
@@ -14,232 +14,235 @@ import { TabindexMixin } from './tabindex-mixin.js';
14
14
  * @mixes FocusMixin
15
15
  * @mixes TabindexMixin
16
16
  */
17
- export const DelegateFocusMixin = dedupeMixin(
18
- (superclass) =>
19
- class DelegateFocusMixinClass extends FocusMixin(TabindexMixin(superclass)) {
20
- static get properties() {
21
- return {
22
- /**
23
- * Specify that this control should have input focus when the page loads.
24
- */
25
- autofocus: {
26
- type: Boolean,
27
- },
28
-
29
- /**
30
- * A reference to the focusable element controlled by the mixin.
31
- * It can be an input, textarea, button or any element with tabindex > -1.
32
- *
33
- * Any component implementing this mixin is expected to provide it
34
- * by using `this._setFocusElement(input)` Polymer API.
35
- *
36
- * Toggling `tabindex` attribute on the host element propagates its value to `focusElement`.
37
- *
38
- * @protected
39
- * @type {!HTMLElement}
40
- */
41
- focusElement: {
42
- type: Object,
43
- readOnly: true,
44
- observer: '_focusElementChanged',
45
- sync: true,
46
- },
47
-
48
- /**
49
- * Override the property from `TabIndexMixin`
50
- * to ensure the `tabindex` attribute of the focus element
51
- * will be restored to `0` after re-enabling the element.
52
- *
53
- * @protected
54
- * @override
55
- */
56
- _lastTabIndex: {
57
- value: 0,
58
- },
59
- };
60
- }
61
-
62
- constructor() {
63
- super();
64
-
65
- this._boundOnBlur = this._onBlur.bind(this);
66
- this._boundOnFocus = this._onFocus.bind(this);
67
- }
68
-
69
- /** @protected */
70
- ready() {
71
- super.ready();
72
-
73
- if (this.autofocus && !this.disabled) {
74
- requestAnimationFrame(() => {
75
- this.focus();
76
- });
77
- }
78
- }
79
-
80
- /**
81
- * @param {FocusOptions=} options
82
- * @protected
83
- * @override
84
- */
85
- focus(options) {
86
- if (this.focusElement && !this.disabled) {
87
- this.focusElement.focus();
88
-
89
- // Set focus-ring attribute on programmatic focus by default
90
- // unless explicitly disabled by `{ focusVisible: false }`.
91
- if (!(options && options.focusVisible === false)) {
92
- this.setAttribute('focus-ring', '');
93
- }
94
- }
95
- }
96
-
97
- /**
98
- * @protected
99
- * @override
100
- */
101
- blur() {
102
- if (this.focusElement) {
103
- this.focusElement.blur();
17
+ const DelegateFocusMixinImplementation = (superclass) => {
18
+ return class DelegateFocusMixinClass extends FocusMixin(TabindexMixin(superclass)) {
19
+ static get properties() {
20
+ return {
21
+ /**
22
+ * Specify that this control should have input focus when the page loads.
23
+ */
24
+ autofocus: {
25
+ type: Boolean,
26
+ },
27
+
28
+ /**
29
+ * A reference to the focusable element controlled by the mixin.
30
+ * It can be an input, textarea, button or any element with tabindex > -1.
31
+ *
32
+ * Any component implementing this mixin is expected to provide it
33
+ * by using `this._setFocusElement(input)` Polymer API.
34
+ *
35
+ * Toggling `tabindex` attribute on the host element propagates its value to `focusElement`.
36
+ *
37
+ * @protected
38
+ * @type {!HTMLElement}
39
+ */
40
+ focusElement: {
41
+ type: Object,
42
+ readOnly: true,
43
+ observer: '_focusElementChanged',
44
+ sync: true,
45
+ },
46
+
47
+ /**
48
+ * Override the property from `TabIndexMixin`
49
+ * to ensure the `tabindex` attribute of the focus element
50
+ * will be restored to `0` after re-enabling the element.
51
+ *
52
+ * @protected
53
+ * @override
54
+ */
55
+ _lastTabIndex: {
56
+ value: 0,
57
+ },
58
+ };
59
+ }
60
+
61
+ constructor() {
62
+ super();
63
+
64
+ this._boundOnBlur = this._onBlur.bind(this);
65
+ this._boundOnFocus = this._onFocus.bind(this);
66
+ }
67
+
68
+ /** @protected */
69
+ ready() {
70
+ super.ready();
71
+
72
+ if (this.autofocus && !this.disabled) {
73
+ requestAnimationFrame(() => {
74
+ this.focus();
75
+ });
76
+ }
77
+ }
78
+
79
+ /**
80
+ * @param {FocusOptions=} options
81
+ * @protected
82
+ * @override
83
+ */
84
+ focus(options) {
85
+ if (this.focusElement && !this.disabled) {
86
+ this.focusElement.focus();
87
+
88
+ // Set focus-ring attribute on programmatic focus by default
89
+ // unless explicitly disabled by `{ focusVisible: false }`.
90
+ if (options?.focusVisible !== false) {
91
+ this.setAttribute('focus-ring', '');
104
92
  }
105
93
  }
106
-
107
- /**
108
- * @protected
109
- * @override
110
- */
111
- click() {
112
- if (this.focusElement && !this.disabled) {
113
- this.focusElement.click();
94
+ }
95
+
96
+ /**
97
+ * @protected
98
+ * @override
99
+ */
100
+ blur() {
101
+ if (this.focusElement) {
102
+ this.focusElement.blur();
103
+ }
104
+ }
105
+
106
+ /**
107
+ * @protected
108
+ * @override
109
+ */
110
+ click() {
111
+ if (this.focusElement && !this.disabled) {
112
+ this.focusElement.click();
113
+ }
114
+ }
115
+
116
+ /** @protected */
117
+ _focusElementChanged(element, oldElement) {
118
+ if (element) {
119
+ element.disabled = this.disabled;
120
+ this._addFocusListeners(element);
121
+ this.__forwardTabIndex(this.tabindex);
122
+ } else if (oldElement) {
123
+ this._removeFocusListeners(oldElement);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * @param {HTMLElement} element
129
+ * @protected
130
+ */
131
+ _addFocusListeners(element) {
132
+ element.addEventListener('blur', this._boundOnBlur);
133
+ element.addEventListener('focus', this._boundOnFocus);
134
+ }
135
+
136
+ /**
137
+ * @param {HTMLElement} element
138
+ * @protected
139
+ */
140
+ _removeFocusListeners(element) {
141
+ element.removeEventListener('blur', this._boundOnBlur);
142
+ element.removeEventListener('focus', this._boundOnFocus);
143
+ }
144
+
145
+ /**
146
+ * Focus event does not bubble, so we dispatch it manually
147
+ * on the host element to support adding focus listeners
148
+ * when the focusable element is placed in light DOM.
149
+ * @param {FocusEvent} event
150
+ * @protected
151
+ */
152
+ _onFocus(event) {
153
+ event.stopPropagation();
154
+ /** @internal to not document it in CEM */
155
+ this.dispatchEvent(new Event('focus'));
156
+ }
157
+
158
+ /**
159
+ * Blur event does not bubble, so we dispatch it manually
160
+ * on the host element to support adding blur listeners
161
+ * when the focusable element is placed in light DOM.
162
+ * @param {FocusEvent} event
163
+ * @protected
164
+ */
165
+ _onBlur(event) {
166
+ event.stopPropagation();
167
+ /** @internal to not document it in CEM */
168
+ this.dispatchEvent(new Event('blur'));
169
+ }
170
+
171
+ /**
172
+ * @param {FocusEvent} event
173
+ * @return {boolean}
174
+ * @protected
175
+ * @override
176
+ */
177
+ _shouldSetFocus(event) {
178
+ return event.target === this.focusElement;
179
+ }
180
+
181
+ /**
182
+ * @param {FocusEvent} event
183
+ * @return {boolean}
184
+ * @protected
185
+ * @override
186
+ */
187
+ _shouldRemoveFocus(event) {
188
+ return event.target === this.focusElement;
189
+ }
190
+
191
+ /**
192
+ * @param {boolean} disabled
193
+ * @param {boolean} oldDisabled
194
+ * @protected
195
+ * @override
196
+ */
197
+ _disabledChanged(disabled, oldDisabled) {
198
+ super._disabledChanged(disabled, oldDisabled);
199
+
200
+ if (this.focusElement) {
201
+ this.focusElement.disabled = disabled;
202
+ }
203
+
204
+ if (disabled) {
205
+ this.blur();
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Override an observer from `TabindexMixin`.
211
+ * Do not call super to remove tabindex attribute
212
+ * from the host after it has been forwarded.
213
+ * @param {string} tabindex
214
+ * @protected
215
+ * @override
216
+ */
217
+ _tabindexChanged(tabindex) {
218
+ this.__forwardTabIndex(tabindex);
219
+ }
220
+
221
+ /** @private */
222
+ __forwardTabIndex(tabindex) {
223
+ if (tabindex !== undefined && this.focusElement) {
224
+ this.focusElement.tabIndex = tabindex;
225
+
226
+ // Preserve tabindex="-1" on the host element
227
+ if (tabindex !== -1) {
228
+ this.tabindex = undefined;
114
229
  }
115
230
  }
116
231
 
117
- /** @protected */
118
- _focusElementChanged(element, oldElement) {
119
- if (element) {
120
- element.disabled = this.disabled;
121
- this._addFocusListeners(element);
122
- this.__forwardTabIndex(this.tabindex);
123
- } else if (oldElement) {
124
- this._removeFocusListeners(oldElement);
232
+ if (this.disabled && tabindex) {
233
+ // If tabindex attribute was changed while component was disabled
234
+ if (tabindex !== -1) {
235
+ this._lastTabIndex = tabindex;
125
236
  }
237
+ this.tabindex = undefined;
126
238
  }
127
239
 
128
- /**
129
- * @param {HTMLElement} element
130
- * @protected
131
- */
132
- _addFocusListeners(element) {
133
- element.addEventListener('blur', this._boundOnBlur);
134
- element.addEventListener('focus', this._boundOnFocus);
135
- }
136
-
137
- /**
138
- * @param {HTMLElement} element
139
- * @protected
140
- */
141
- _removeFocusListeners(element) {
142
- element.removeEventListener('blur', this._boundOnBlur);
143
- element.removeEventListener('focus', this._boundOnFocus);
144
- }
145
-
146
- /**
147
- * Focus event does not bubble, so we dispatch it manually
148
- * on the host element to support adding focus listeners
149
- * when the focusable element is placed in light DOM.
150
- * @param {FocusEvent} event
151
- * @protected
152
- */
153
- _onFocus(event) {
154
- event.stopPropagation();
155
- this.dispatchEvent(new Event('focus'));
156
- }
157
-
158
- /**
159
- * Blur event does not bubble, so we dispatch it manually
160
- * on the host element to support adding blur listeners
161
- * when the focusable element is placed in light DOM.
162
- * @param {FocusEvent} event
163
- * @protected
164
- */
165
- _onBlur(event) {
166
- event.stopPropagation();
167
- this.dispatchEvent(new Event('blur'));
240
+ // Lit does not remove attribute when setting property to undefined
241
+ if (tabindex === undefined && this.hasAttribute('tabindex')) {
242
+ this.removeAttribute('tabindex');
168
243
  }
244
+ }
245
+ };
246
+ };
169
247
 
170
- /**
171
- * @param {FocusEvent} event
172
- * @return {boolean}
173
- * @protected
174
- * @override
175
- */
176
- _shouldSetFocus(event) {
177
- return event.target === this.focusElement;
178
- }
179
-
180
- /**
181
- * @param {FocusEvent} event
182
- * @return {boolean}
183
- * @protected
184
- * @override
185
- */
186
- _shouldRemoveFocus(event) {
187
- return event.target === this.focusElement;
188
- }
189
-
190
- /**
191
- * @param {boolean} disabled
192
- * @param {boolean} oldDisabled
193
- * @protected
194
- * @override
195
- */
196
- _disabledChanged(disabled, oldDisabled) {
197
- super._disabledChanged(disabled, oldDisabled);
198
-
199
- if (this.focusElement) {
200
- this.focusElement.disabled = disabled;
201
- }
202
-
203
- if (disabled) {
204
- this.blur();
205
- }
206
- }
207
-
208
- /**
209
- * Override an observer from `TabindexMixin`.
210
- * Do not call super to remove tabindex attribute
211
- * from the host after it has been forwarded.
212
- * @param {string} tabindex
213
- * @protected
214
- * @override
215
- */
216
- _tabindexChanged(tabindex) {
217
- this.__forwardTabIndex(tabindex);
218
- }
219
-
220
- /** @private */
221
- __forwardTabIndex(tabindex) {
222
- if (tabindex !== undefined && this.focusElement) {
223
- this.focusElement.tabIndex = tabindex;
224
-
225
- // Preserve tabindex="-1" on the host element
226
- if (tabindex !== -1) {
227
- this.tabindex = undefined;
228
- }
229
- }
230
-
231
- if (this.disabled && tabindex) {
232
- // If tabindex attribute was changed while component was disabled
233
- if (tabindex !== -1) {
234
- this._lastTabIndex = tabindex;
235
- }
236
- this.tabindex = undefined;
237
- }
238
-
239
- // Lit does not remove attribute when setting property to undefined
240
- if (tabindex === undefined && this.hasAttribute('tabindex')) {
241
- this.removeAttribute('tabindex');
242
- }
243
- }
244
- },
245
- );
248
+ export const DelegateFocusMixin = dedupeMixin(DelegateFocusMixinImplementation);
@@ -10,54 +10,55 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin';
10
10
  *
11
11
  * @polymerMixin
12
12
  */
13
- export const DisabledMixin = dedupeMixin(
14
- (superclass) =>
15
- class DisabledMixinClass extends superclass {
16
- static get properties() {
17
- return {
18
- /**
19
- * If true, the user cannot interact with this element.
20
- */
21
- disabled: {
22
- type: Boolean,
23
- value: false,
24
- observer: '_disabledChanged',
25
- reflectToAttribute: true,
26
- sync: true,
27
- },
28
- };
29
- }
13
+ const DisabledMixinImplementation = (superclass) => {
14
+ return class DisabledMixinClass extends superclass {
15
+ static get properties() {
16
+ return {
17
+ /**
18
+ * If true, the user cannot interact with this element.
19
+ */
20
+ disabled: {
21
+ type: Boolean,
22
+ value: false,
23
+ observer: '_disabledChanged',
24
+ reflectToAttribute: true,
25
+ sync: true,
26
+ },
27
+ };
28
+ }
30
29
 
31
- /**
32
- * @param {boolean} disabled
33
- * @protected
34
- */
35
- _disabledChanged(disabled) {
36
- this._setAriaDisabled(disabled);
37
- }
30
+ /**
31
+ * @param {boolean} disabled
32
+ * @protected
33
+ */
34
+ _disabledChanged(disabled) {
35
+ this._setAriaDisabled(disabled);
36
+ }
38
37
 
39
- /**
40
- * @param {boolean} disabled
41
- * @protected
42
- */
43
- _setAriaDisabled(disabled) {
44
- if (disabled) {
45
- this.setAttribute('aria-disabled', 'true');
46
- } else {
47
- this.removeAttribute('aria-disabled');
48
- }
38
+ /**
39
+ * @param {boolean} disabled
40
+ * @protected
41
+ */
42
+ _setAriaDisabled(disabled) {
43
+ if (disabled) {
44
+ this.setAttribute('aria-disabled', 'true');
45
+ } else {
46
+ this.removeAttribute('aria-disabled');
49
47
  }
48
+ }
50
49
 
51
- /**
52
- * Overrides the default element `click` method in order to prevent
53
- * firing the `click` event when the element is disabled.
54
- * @protected
55
- * @override
56
- */
57
- click() {
58
- if (!this.disabled) {
59
- super.click();
60
- }
50
+ /**
51
+ * Overrides the default element `click` method in order to prevent
52
+ * firing the `click` event when the element is disabled.
53
+ * @protected
54
+ * @override
55
+ */
56
+ click() {
57
+ if (!this.disabled) {
58
+ super.click();
61
59
  }
62
- },
63
- );
60
+ }
61
+ };
62
+ };
63
+
64
+ export const DisabledMixin = dedupeMixin(DisabledMixinImplementation);
@@ -11,98 +11,99 @@ import { isKeyboardActive } from './focus-utils.js';
11
11
  *
12
12
  * @polymerMixin
13
13
  */
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
- }
14
+ const FocusMixinImplementation = (superclass) => {
15
+ return class FocusMixinClass extends superclass {
16
+ /**
17
+ * @protected
18
+ * @return {boolean}
19
+ */
20
+ get _keyboardActive() {
21
+ return isKeyboardActive();
22
+ }
24
23
 
25
- /** @protected */
26
- ready() {
27
- this.addEventListener('focusin', (e) => {
28
- if (this._shouldSetFocus(e)) {
29
- this._setFocused(true);
30
- }
31
- });
24
+ /** @protected */
25
+ ready() {
26
+ this.addEventListener('focusin', (e) => {
27
+ if (this._shouldSetFocus(e)) {
28
+ this._setFocused(true);
29
+ }
30
+ });
32
31
 
33
- this.addEventListener('focusout', (e) => {
34
- if (this._shouldRemoveFocus(e)) {
35
- this._setFocused(false);
36
- }
37
- });
32
+ this.addEventListener('focusout', (e) => {
33
+ if (this._shouldRemoveFocus(e)) {
34
+ this._setFocused(false);
35
+ }
36
+ });
38
37
 
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
- }
38
+ // In super.ready() other 'focusin' and 'focusout' listeners might be
39
+ // added, so we call it after our own ones to ensure they execute first.
40
+ // Issue to watch out: when incorrect, <vaadin-combo-box> refocuses the
41
+ // input field on iOS after "Done" is pressed.
42
+ super.ready();
43
+ }
45
44
 
46
- /** @protected */
47
- disconnectedCallback() {
48
- super.disconnectedCallback();
45
+ /** @protected */
46
+ disconnectedCallback() {
47
+ super.disconnectedCallback();
49
48
 
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
- }
49
+ // In non-Chrome browsers, blur does not fire on the element when it is disconnected.
50
+ // reproducible in `<vaadin-date-picker>` when closing on `Cancel` or `Today` click.
51
+ if (this.hasAttribute('focused')) {
52
+ this._setFocused(false);
55
53
  }
54
+ }
56
55
 
57
- /**
58
- * @param {FocusOptions=} options
59
- * @protected
60
- * @override
61
- */
62
- focus(options) {
63
- super.focus(options);
56
+ /**
57
+ * @param {FocusOptions=} options
58
+ * @protected
59
+ * @override
60
+ */
61
+ focus(options) {
62
+ super.focus(options);
64
63
 
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
- }
64
+ // Set focus-ring attribute on programmatic focus by default
65
+ // unless explicitly disabled by `{ focusVisible: false }`.
66
+ if (options?.focusVisible !== false) {
67
+ this.setAttribute('focus-ring', '');
70
68
  }
69
+ }
71
70
 
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);
71
+ /**
72
+ * Override to change how focused and focus-ring attributes are set.
73
+ *
74
+ * @param {boolean} focused
75
+ * @protected
76
+ */
77
+ _setFocused(focused) {
78
+ this.toggleAttribute('focused', focused);
80
79
 
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
- }
80
+ // Focus-ring is true when the element was focused from the keyboard.
81
+ // Focus Ring [A11ycasts]: https://youtu.be/ilj2P5-5CjI
82
+ this.toggleAttribute('focus-ring', focused && this._keyboardActive);
83
+ }
85
84
 
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
- }
85
+ /**
86
+ * Override to define if the field receives focus based on the event.
87
+ *
88
+ * @param {FocusEvent} _event
89
+ * @return {boolean}
90
+ * @protected
91
+ */
92
+ _shouldSetFocus(_event) {
93
+ return true;
94
+ }
96
95
 
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
- );
96
+ /**
97
+ * Override to define if the field loses focus based on the event.
98
+ *
99
+ * @param {FocusEvent} _event
100
+ * @return {boolean}
101
+ * @protected
102
+ */
103
+ _shouldRemoveFocus(_event) {
104
+ return true;
105
+ }
106
+ };
107
+ };
108
+
109
+ export const FocusMixin = dedupeMixin(FocusMixinImplementation);
@@ -12,74 +12,75 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin';
12
12
  *
13
13
  * @polymerMixin
14
14
  */
15
- export const KeyboardMixin = dedupeMixin(
16
- (superclass) =>
17
- class KeyboardMixinClass extends superclass {
18
- /** @protected */
19
- ready() {
20
- super.ready();
15
+ const KeyboardMixinImplementation = (superclass) => {
16
+ return class KeyboardMixinClass extends superclass {
17
+ /** @protected */
18
+ ready() {
19
+ super.ready();
21
20
 
22
- this.addEventListener('keydown', (event) => {
23
- this._onKeyDown(event);
24
- });
21
+ this.addEventListener('keydown', (event) => {
22
+ this._onKeyDown(event);
23
+ });
25
24
 
26
- this.addEventListener('keyup', (event) => {
27
- this._onKeyUp(event);
28
- });
29
- }
25
+ this.addEventListener('keyup', (event) => {
26
+ this._onKeyUp(event);
27
+ });
28
+ }
30
29
 
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
- }
30
+ /**
31
+ * A handler for the `keydown` event. By default, it calls
32
+ * separate methods for handling "Enter" and "Escape" keys.
33
+ * Override the method to implement your own behavior.
34
+ *
35
+ * @param {KeyboardEvent} event
36
+ * @protected
37
+ */
38
+ _onKeyDown(event) {
39
+ switch (event.key) {
40
+ case 'Enter':
41
+ this._onEnter(event);
42
+ break;
43
+ case 'Escape':
44
+ this._onEscape(event);
45
+ break;
46
+ default:
47
+ break;
50
48
  }
49
+ }
51
50
 
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
- }
51
+ /**
52
+ * A handler for the `keyup` event. By default, it does nothing.
53
+ * Override the method to implement your own behavior.
54
+ *
55
+ * @param {KeyboardEvent} _event
56
+ * @protected
57
+ */
58
+ _onKeyUp(_event) {
59
+ // To be implemented.
60
+ }
62
61
 
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
- }
62
+ /**
63
+ * A handler for the "Enter" key. By default, it does nothing.
64
+ * Override the method to implement your own behavior.
65
+ *
66
+ * @param {KeyboardEvent} _event
67
+ * @protected
68
+ */
69
+ _onEnter(_event) {
70
+ // To be implemented.
71
+ }
73
72
 
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
- );
73
+ /**
74
+ * A handler for the "Escape" key. By default, it does nothing.
75
+ * Override the method to implement your own behavior.
76
+ *
77
+ * @param {KeyboardEvent} _event
78
+ * @protected
79
+ */
80
+ _onEscape(_event) {
81
+ // To be implemented.
82
+ }
83
+ };
84
+ };
85
+
86
+ export const KeyboardMixin = dedupeMixin(KeyboardMixinImplementation);
package/src/list-mixin.js CHANGED
@@ -336,11 +336,18 @@ export const ListMixin = (superClass) =>
336
336
  }
337
337
 
338
338
  /**
339
- * Fired when the selection is changed.
340
- * Not fired when used in `multiple` selection mode.
339
+ * Override method inherited from `KeyboardDirectionMixin` to allow
340
+ * focusing disabled items that are configured so.
341
341
  *
342
- * @event selected-changed
343
- * @param {Object} detail
344
- * @param {Object} detail.value the index of the item selected in the items array.
342
+ * @param {Element} item
343
+ * @protected
344
+ * @override
345
345
  */
346
+ _isItemFocusable(item) {
347
+ if (item.disabled && item.__shouldAllowFocusWhenDisabled) {
348
+ return item.__shouldAllowFocusWhenDisabled();
349
+ }
350
+
351
+ return super._isItemFocusable(item);
352
+ }
346
353
  };