@vaadin/field-base 22.0.0-alpha3 → 22.0.0-alpha7

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 (77) hide show
  1. package/index.d.ts +9 -14
  2. package/index.js +9 -14
  3. package/package.json +24 -18
  4. package/src/aria-label-controller.d.ts +11 -0
  5. package/src/aria-label-controller.js +53 -0
  6. package/src/checked-mixin.d.ts +21 -0
  7. package/src/checked-mixin.js +54 -0
  8. package/src/delegate-focus-mixin.d.ts +2 -2
  9. package/src/delegate-focus-mixin.js +150 -133
  10. package/src/delegate-state-mixin.d.ts +23 -0
  11. package/src/delegate-state-mixin.js +125 -0
  12. package/src/field-mixin.d.ts +39 -0
  13. package/src/field-mixin.js +317 -0
  14. package/src/input-constraints-mixin.d.ts +2 -1
  15. package/src/input-constraints-mixin.js +105 -53
  16. package/src/input-control-mixin.d.ts +52 -0
  17. package/src/input-control-mixin.js +170 -0
  18. package/src/input-controller.d.ts +11 -0
  19. package/src/input-controller.js +35 -0
  20. package/src/input-field-mixin.d.ts +2 -16
  21. package/src/input-field-mixin.js +20 -97
  22. package/src/input-mixin.d.ts +1 -1
  23. package/src/input-mixin.js +156 -145
  24. package/src/label-mixin.d.ts +2 -2
  25. package/src/label-mixin.js +73 -60
  26. package/src/pattern-mixin.d.ts +2 -2
  27. package/src/pattern-mixin.js +13 -13
  28. package/src/shadow-focus-mixin.d.ts +21 -0
  29. package/src/shadow-focus-mixin.js +87 -0
  30. package/src/slot-controller.d.ts +8 -0
  31. package/src/slot-controller.js +36 -0
  32. package/src/slot-label-mixin.d.ts +20 -0
  33. package/src/slot-label-mixin.js +38 -0
  34. package/src/slot-styles-mixin.d.ts +24 -0
  35. package/src/slot-styles-mixin.js +76 -0
  36. package/src/slot-target-mixin.d.ts +32 -0
  37. package/src/slot-target-mixin.js +110 -0
  38. package/src/styles/clear-button-styles.d.ts +8 -0
  39. package/src/styles/clear-button-styles.js +21 -0
  40. package/src/styles/field-shared-styles.d.ts +8 -0
  41. package/src/styles/field-shared-styles.js +29 -0
  42. package/src/styles/input-field-container-styles.d.ts +8 -0
  43. package/src/styles/input-field-container-styles.js +16 -0
  44. package/src/styles/input-field-shared-styles.d.ts +8 -0
  45. package/src/styles/input-field-shared-styles.js +10 -0
  46. package/src/text-area-controller.d.ts +11 -0
  47. package/src/text-area-controller.js +38 -0
  48. package/src/validate-mixin.d.ts +1 -9
  49. package/src/validate-mixin.js +43 -118
  50. package/src/active-mixin.d.ts +0 -25
  51. package/src/active-mixin.js +0 -84
  52. package/src/aria-label-mixin.d.ts +0 -20
  53. package/src/aria-label-mixin.js +0 -71
  54. package/src/char-length-mixin.d.ts +0 -30
  55. package/src/char-length-mixin.js +0 -42
  56. package/src/clear-button-mixin.d.ts +0 -27
  57. package/src/clear-button-mixin.js +0 -80
  58. package/src/disabled-mixin.d.ts +0 -23
  59. package/src/disabled-mixin.js +0 -48
  60. package/src/field-aria-mixin.d.ts +0 -24
  61. package/src/field-aria-mixin.js +0 -61
  62. package/src/focus-mixin.d.ts +0 -33
  63. package/src/focus-mixin.js +0 -104
  64. package/src/forward-input-props-mixin.d.ts +0 -41
  65. package/src/forward-input-props-mixin.js +0 -110
  66. package/src/helper-text-mixin.d.ts +0 -24
  67. package/src/helper-text-mixin.js +0 -109
  68. package/src/input-slot-mixin.d.ts +0 -26
  69. package/src/input-slot-mixin.js +0 -71
  70. package/src/slot-mixin.d.ts +0 -23
  71. package/src/slot-mixin.js +0 -55
  72. package/src/tabindex-mixin.d.ts +0 -29
  73. package/src/tabindex-mixin.js +0 -78
  74. package/src/text-area-slot-mixin.d.ts +0 -21
  75. package/src/text-area-slot-mixin.js +0 -56
  76. package/src/text-field-mixin.d.ts +0 -21
  77. package/src/text-field-mixin.js +0 -17
@@ -5,165 +5,176 @@
5
5
  */
6
6
  import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
7
7
 
8
- const InputMixinImplementation = (superclass) =>
9
- class InputMixinClass extends superclass {
10
- static get properties() {
11
- return {
12
- /**
13
- * A reference to the input element controlled by the mixin.
14
- * Any component implementing this mixin is expected to provide it
15
- * by using `this._setInputElement(input)` Polymer API.
16
- *
17
- * A typical case is using `InputSlotMixin` that does this automatically.
18
- * However, the input element does not have to always be native <input>:
19
- * as an example, <vaadin-combo-box-light> accepts other components.
20
- *
21
- * @protected
22
- * @type {!HTMLElement}
23
- */
24
- inputElement: {
25
- type: Object,
26
- readOnly: true,
27
- observer: '_inputElementChanged'
28
- },
29
-
30
- /**
31
- * The value of the field.
32
- */
33
- value: {
34
- type: String,
35
- value: '',
36
- observer: '_valueChanged',
37
- notify: true
38
- }
39
- };
40
- }
8
+ /**
9
+ * A mixin to store the reference to an input element
10
+ * and add input and change event listeners to it.
11
+ *
12
+ * @polymerMixin
13
+ */
14
+ export const InputMixin = dedupingMixin(
15
+ (superclass) =>
16
+ class InputMixinClass extends superclass {
17
+ static get properties() {
18
+ return {
19
+ /**
20
+ * A reference to the input element controlled by the mixin.
21
+ * Any component implementing this mixin is expected to provide it
22
+ * by using `this._setInputElement(input)` Polymer API.
23
+ *
24
+ * A typical case is using `InputController` that does this automatically.
25
+ * However, the input element does not have to always be native <input>:
26
+ * as an example, <vaadin-combo-box-light> accepts other components.
27
+ *
28
+ * @protected
29
+ * @type {!HTMLElement}
30
+ */
31
+ inputElement: {
32
+ type: Object,
33
+ readOnly: true,
34
+ observer: '_inputElementChanged'
35
+ },
36
+
37
+ /**
38
+ * String used to define input type.
39
+ * @protected
40
+ */
41
+ type: {
42
+ type: String,
43
+ readOnly: true
44
+ },
45
+
46
+ /**
47
+ * The value of the field.
48
+ */
49
+ value: {
50
+ type: String,
51
+ value: '',
52
+ observer: '_valueChanged',
53
+ notify: true
54
+ }
55
+ };
56
+ }
41
57
 
42
- constructor() {
43
- super();
58
+ constructor() {
59
+ super();
44
60
 
45
- this._boundOnInput = this._onInput.bind(this);
46
- this._boundOnChange = this._onChange.bind(this);
47
- }
61
+ this._boundOnInput = this._onInput.bind(this);
62
+ this._boundOnChange = this._onChange.bind(this);
63
+ }
48
64
 
49
- /**
50
- * Clear the value of the field.
51
- */
52
- clear() {
53
- this.value = '';
54
- }
65
+ /**
66
+ * Clear the value of the field.
67
+ */
68
+ clear() {
69
+ this.value = '';
70
+ }
55
71
 
56
- /**
57
- * Add event listeners to the input element instance.
58
- * Override this method to add custom listeners.
59
- * @param {!HTMLElement} input
60
- */
61
- _addInputListeners(input) {
62
- input.addEventListener('input', this._boundOnInput);
63
- input.addEventListener('change', this._boundOnChange);
64
- }
72
+ /**
73
+ * Add event listeners to the input element instance.
74
+ * Override this method to add custom listeners.
75
+ * @param {!HTMLElement} input
76
+ */
77
+ _addInputListeners(input) {
78
+ input.addEventListener('input', this._boundOnInput);
79
+ input.addEventListener('change', this._boundOnChange);
80
+ }
65
81
 
66
- /**
67
- * Remove event listeners from the input element instance.
68
- * @param {!HTMLElement} input
69
- */
70
- _removeInputListeners(input) {
71
- input.removeEventListener('input', this._boundOnInput);
72
- input.removeEventListener('change', this._boundOnChange);
73
- }
82
+ /**
83
+ * Remove event listeners from the input element instance.
84
+ * @param {!HTMLElement} input
85
+ */
86
+ _removeInputListeners(input) {
87
+ input.removeEventListener('input', this._boundOnInput);
88
+ input.removeEventListener('change', this._boundOnChange);
89
+ }
90
+
91
+ /**
92
+ * A method to forward the value property set on the field
93
+ * programmatically back to the input element value.
94
+ * Override this method to perform additional checks,
95
+ * for example to skip this in certain conditions.
96
+ * @param {string} value
97
+ * @protected
98
+ * @override
99
+ */
100
+ _forwardInputValue(value) {
101
+ // Value might be set before an input element is initialized.
102
+ // This case should be handled separately by a component that
103
+ // implements this mixin, for example in `connectedCallback`.
104
+ if (!this.inputElement) {
105
+ return;
106
+ }
74
107
 
75
- /**
76
- * A method to forward the value property set on the field
77
- * programmatically back to the input element value.
78
- * Override this method to perform additional checks,
79
- * for example to skip this in certain conditions.
80
- * @param {string} value
81
- * @protected
82
- * @override
83
- */
84
- _forwardInputValue(value) {
85
- // Value might be set before an input element is initialized.
86
- // This case should be handled separately by a component that
87
- // implements this mixin, for example in `connectedCallback`.
88
- if (!this.inputElement) {
89
- return;
108
+ if (value != undefined) {
109
+ this.inputElement.value = value;
110
+ } else {
111
+ this.inputElement.value = '';
112
+ }
90
113
  }
91
114
 
92
- if (value != undefined) {
93
- this.inputElement.value = value;
94
- } else {
95
- this.inputElement.value = '';
115
+ /** @protected */
116
+ _inputElementChanged(input, oldInput) {
117
+ if (input) {
118
+ this._addInputListeners(input);
119
+ } else if (oldInput) {
120
+ this._removeInputListeners(oldInput);
121
+ }
96
122
  }
97
- }
98
123
 
99
- /** @protected */
100
- _inputElementChanged(input, oldInput) {
101
- if (input) {
102
- this._addInputListeners(input);
103
- } else if (oldInput) {
104
- this._removeInputListeners(oldInput);
124
+ /**
125
+ * An input event listener used to update the field value.
126
+ * Override this method with an actual implementation.
127
+ * @param {Event} _event
128
+ * @protected
129
+ * @override
130
+ */
131
+ _onInput(event) {
132
+ // Ignore fake input events e.g. used by clear button.
133
+ this.__userInput = event.isTrusted;
134
+ this.value = event.target.value;
135
+ this.__userInput = false;
105
136
  }
106
- }
107
137
 
108
- /**
109
- * An input event listener used to update the field value.
110
- * Override this method with an actual implementation.
111
- * @param {Event} _event
112
- * @protected
113
- * @override
114
- */
115
- _onInput(event) {
116
- // Ignore fake input events e.g. used by clear button.
117
- this.__userInput = event.isTrusted;
118
- this.value = event.target.value;
119
- this.__userInput = false;
120
- }
138
+ /**
139
+ * A change event listener.
140
+ * Override this method with an actual implementation.
141
+ * @param {Event} _event
142
+ * @protected
143
+ * @override
144
+ */
145
+ _onChange(_event) {}
146
+
147
+ /**
148
+ * Toggle the has-value attribute based on the value property.
149
+ * @param {boolean} hasValue
150
+ * @protected
151
+ */
152
+ _toggleHasValue(hasValue) {
153
+ this.toggleAttribute('has-value', hasValue);
154
+ }
121
155
 
122
- /**
123
- * A change event listener.
124
- * Override this method with an actual implementation.
125
- * @param {Event} _event
126
- * @protected
127
- * @override
128
- */
129
- _onChange(_event) {}
130
-
131
- /**
132
- * Toggle the has-value attribute based on the value property.
133
- * @param {boolean} hasValue
134
- * @protected
135
- */
136
- _toggleHasValue(hasValue) {
137
- this.toggleAttribute('has-value', hasValue);
138
- }
156
+ /**
157
+ * Observer called when a value property changes.
158
+ * @param {string | undefined} newVal
159
+ * @param {string | undefined} oldVal
160
+ * @protected
161
+ * @override
162
+ */
163
+ _valueChanged(newVal, oldVal) {
164
+ this._toggleHasValue(newVal !== '' && newVal != null);
165
+
166
+ // Setting initial value to empty string, do nothing.
167
+ if (newVal === '' && oldVal === undefined) {
168
+ return;
169
+ }
139
170
 
140
- /**
141
- * Observer called when a value property changes.
142
- * @param {string | undefined} newVal
143
- * @param {string | undefined} oldVal
144
- * @protected
145
- * @override
146
- */
147
- _valueChanged(newVal, oldVal) {
148
- this._toggleHasValue(newVal !== '' && newVal != null);
149
-
150
- // Setting initial value to empty string, do nothing.
151
- if (newVal === '' && oldVal === undefined) {
152
- return;
153
- }
171
+ // Value is set by the user, no need to sync it back to input.
172
+ if (this.__userInput) {
173
+ return;
174
+ }
154
175
 
155
- // Value is set by the user, no need to sync it back to input.
156
- if (this.__userInput) {
157
- return;
176
+ // Setting a value programmatically, sync it to input element.
177
+ this._forwardInputValue(newVal);
158
178
  }
159
-
160
- // Setting a value programmatically, sync it to input element.
161
- this._forwardInputValue(newVal);
162
179
  }
163
- };
164
-
165
- /**
166
- * A mixin to store the reference to an input element
167
- * and add input and change event listeners to it.
168
- */
169
- export const InputMixin = dedupingMixin(InputMixinImplementation);
180
+ );
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2021 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { SlotMixin } from './slot-mixin.js';
6
+ import { SlotMixin } from '@vaadin/component-base/src/slot-mixin.js';
7
7
 
8
8
  /**
9
9
  * A mixin to provide label via corresponding property or named slot.
@@ -18,7 +18,7 @@ interface LabelMixin extends SlotMixin {
18
18
  /**
19
19
  * String used for a label element.
20
20
  */
21
- label: string;
21
+ label: string | null | undefined;
22
22
  }
23
23
 
24
24
  export { LabelMixinConstructor, LabelMixin };
@@ -4,77 +4,90 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
7
- import { SlotMixin } from './slot-mixin.js';
7
+ import { SlotMixin } from '@vaadin/component-base/src/slot-mixin.js';
8
8
 
9
- const LabelMixinImplementation = (superclass) =>
10
- class LabelMixinClass extends SlotMixin(superclass) {
11
- static get properties() {
12
- return {
13
- /**
14
- * The label text for the input node.
15
- * When no light dom defined via [slot=label], this value will be used.
16
- */
17
- label: {
18
- type: String,
19
- observer: '_labelChanged'
20
- }
21
- };
22
- }
9
+ /**
10
+ * A mixin to provide label via corresponding property or named slot.
11
+ *
12
+ * @polymerMixin
13
+ * @mixes SlotMixin
14
+ */
15
+ export const LabelMixin = dedupingMixin(
16
+ (superclass) =>
17
+ class LabelMixinClass extends SlotMixin(superclass) {
18
+ static get properties() {
19
+ return {
20
+ /**
21
+ * The label text for the input node.
22
+ * When no light dom defined via [slot=label], this value will be used.
23
+ */
24
+ label: {
25
+ type: String,
26
+ observer: '_labelChanged'
27
+ }
28
+ };
29
+ }
23
30
 
24
- get slots() {
25
- return {
26
- ...super.slots,
27
- label: () => {
28
- const label = document.createElement('label');
29
- label.textContent = this.label;
30
- return label;
31
- }
32
- };
33
- }
31
+ /** @protected */
32
+ get slots() {
33
+ return {
34
+ ...super.slots,
35
+ label: () => {
36
+ const label = document.createElement('label');
37
+ label.textContent = this.label;
38
+ return label;
39
+ }
40
+ };
41
+ }
34
42
 
35
- /** @protected */
36
- get _labelNode() {
37
- return this._getDirectSlotChild('label');
38
- }
43
+ /** @protected */
44
+ get _labelNode() {
45
+ return this._getDirectSlotChild('label');
46
+ }
39
47
 
40
- constructor() {
41
- super();
48
+ constructor() {
49
+ super();
42
50
 
43
- // Ensure every instance has unique ID
44
- const uniqueId = (LabelMixinClass._uniqueId = 1 + LabelMixinClass._uniqueId || 0);
45
- this._labelId = `label-${this.localName}-${uniqueId}`;
46
- }
51
+ // Ensure every instance has unique ID
52
+ const uniqueId = (LabelMixinClass._uniqueLabelId = 1 + LabelMixinClass._uniqueLabelId || 0);
53
+ this._labelId = `label-${this.localName}-${uniqueId}`;
47
54
 
48
- /** @protected */
49
- connectedCallback() {
50
- super.connectedCallback();
55
+ /**
56
+ * @type {MutationObserver}
57
+ * @private
58
+ */
59
+ this.__labelNodeObserver = new MutationObserver(() => {
60
+ this._toggleHasLabelAttribute();
61
+ });
62
+ }
51
63
 
52
- if (this._labelNode) {
53
- this._labelNode.id = this._labelId;
64
+ /** @protected */
65
+ ready() {
66
+ super.ready();
54
67
 
55
- this._applyCustomLabel();
56
- }
57
- }
68
+ if (this._labelNode) {
69
+ this._labelNode.id = this._labelId;
70
+ this._toggleHasLabelAttribute();
58
71
 
59
- /** @protected */
60
- _applyCustomLabel() {
61
- const label = this._labelNode.textContent;
62
- if (label !== this.label) {
63
- this.label = label;
72
+ this.__labelNodeObserver.observe(this._labelNode, { childList: true });
73
+ }
64
74
  }
65
- }
66
75
 
67
- /** @protected */
68
- _labelChanged(label) {
69
- if (this._labelNode) {
70
- this._labelNode.textContent = label;
76
+ /** @protected */
77
+ _labelChanged(label) {
78
+ if (this._labelNode) {
79
+ this._labelNode.textContent = label;
80
+ this._toggleHasLabelAttribute();
81
+ }
71
82
  }
72
83
 
73
- this.toggleAttribute('has-label', Boolean(label));
74
- }
75
- };
84
+ /** @protected */
85
+ _toggleHasLabelAttribute() {
86
+ if (this._labelNode) {
87
+ const hasLabel = this._labelNode.children.length > 0 || this._labelNode.textContent.trim() !== '';
76
88
 
77
- /**
78
- * A mixin to provide label via corresponding property or named slot.
79
- */
80
- export const LabelMixin = dedupingMixin(LabelMixinImplementation);
89
+ this.toggleAttribute('has-label', hasLabel);
90
+ }
91
+ }
92
+ }
93
+ );
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2021 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { ForwardInputPropsMixin } from './forward-input-props-mixin.js';
6
+ import { InputConstraintsMixin } from './input-constraints-mixin.js';
7
7
 
8
8
  /**
9
9
  * A mixin to provide `pattern` and `preventInvalidInput` properties.
@@ -14,7 +14,7 @@ interface PatternMixinConstructor {
14
14
  new (...args: any[]): PatternMixin;
15
15
  }
16
16
 
17
- interface PatternMixin extends ForwardInputPropsMixin {
17
+ interface PatternMixin extends InputConstraintsMixin {
18
18
  /**
19
19
  * A regular expression that the value is checked against.
20
20
  * The pattern must match the entire value, not just some subset.
@@ -3,13 +3,18 @@
3
3
  * Copyright (c) 2021 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
7
- import { timeOut } from '@polymer/polymer/lib/utils/async.js';
8
- import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
9
- import { ForwardInputPropsMixin } from './forward-input-props-mixin.js';
6
+ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
7
+ import { timeOut } from '@vaadin/component-base/src/async.js';
8
+ import { InputConstraintsMixin } from './input-constraints-mixin.js';
10
9
 
11
- const PatternMixinImplementation = (superclass) =>
12
- class PatternMixinClass extends ForwardInputPropsMixin(superclass) {
10
+ /**
11
+ * A mixin to provide `pattern` and `preventInvalidInput` properties.
12
+ *
13
+ * @polymerMixin
14
+ * @mixes InputConstraintsMixin
15
+ */
16
+ export const PatternMixin = (superclass) =>
17
+ class PatternMixinClass extends InputConstraintsMixin(superclass) {
13
18
  static get properties() {
14
19
  return {
15
20
  /**
@@ -31,8 +36,8 @@ const PatternMixinImplementation = (superclass) =>
31
36
  };
32
37
  }
33
38
 
34
- static get forwardProps() {
35
- return [...super.forwardProps, 'pattern'];
39
+ static get delegateAttrs() {
40
+ return [...super.delegateAttrs, 'pattern'];
36
41
  }
37
42
 
38
43
  static get constraints() {
@@ -65,8 +70,3 @@ const PatternMixinImplementation = (superclass) =>
65
70
  super._onInput(event);
66
71
  }
67
72
  };
68
-
69
- /**
70
- * A mixin to provide `pattern` and `preventInvalidInput` properties.
71
- */
72
- export const PatternMixin = dedupingMixin(PatternMixinImplementation);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { KeyboardMixin } from '@vaadin/component-base/src/keyboard-mixin.js';
7
+ import { TabindexMixin } from '@vaadin/component-base/src/tabindex-mixin.js';
8
+ import { DelegateFocusMixin } from './delegate-focus-mixin.js';
9
+
10
+ /**
11
+ * A mixin to forward focus to an element in the shadow DOM.
12
+ */
13
+ declare function ShadowFocusMixin<T extends new (...args: any[]) => {}>(base: T): T & ShadowFocusMixinConstructor;
14
+
15
+ interface ShadowFocusMixinConstructor {
16
+ new (...args: any[]): ShadowFocusMixin;
17
+ }
18
+
19
+ interface ShadowFocusMixin extends KeyboardMixin, TabindexMixin, DelegateFocusMixin {}
20
+
21
+ export { ShadowFocusMixinConstructor, ShadowFocusMixin };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { KeyboardMixin } from '@vaadin/component-base/src/keyboard-mixin.js';
7
+ import { TabindexMixin } from '@vaadin/component-base/src/tabindex-mixin.js';
8
+ import { DelegateFocusMixin } from './delegate-focus-mixin.js';
9
+
10
+ /**
11
+ * A mixin to forward focus to an element in the shadow DOM.
12
+ *
13
+ * @polymerMixin
14
+ * @mixes DelegateFocusMixin
15
+ * @mixes KeyboardMixin
16
+ * @mixes TabindexMixin
17
+ */
18
+ export const ShadowFocusMixin = (superClass) =>
19
+ class ShadowFocusMixinClass extends TabindexMixin(DelegateFocusMixin(KeyboardMixin(superClass))) {
20
+ /**
21
+ * Override an event listener from `KeyboardMixin`
22
+ * to prevent setting `focused` on Shift Tab.
23
+ * @param {KeyboardEvent} event
24
+ * @protected
25
+ * @override
26
+ */
27
+ _onKeyDown(event) {
28
+ super._onKeyDown(event);
29
+
30
+ // When focus moves with Shift + Tab, do not mark host as focused.
31
+ // The flag set here will be later used in focusin event listener.
32
+ if (!event.defaultPrevented && event.keyCode === 9 && event.shiftKey) {
33
+ this._isShiftTabbing = true;
34
+ HTMLElement.prototype.focus.apply(this);
35
+ this._setFocused(false);
36
+ setTimeout(() => (this._isShiftTabbing = false), 0);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Override method inherited from `FocusMixin`
42
+ * to support focusElement in Shadow DOM.
43
+ * @param {Event} event
44
+ * @return {boolean}
45
+ * @protected
46
+ * @override
47
+ */
48
+ _shouldSetFocus(event) {
49
+ if (!this.disabled && this.focusElement) {
50
+ const path = event.composedPath();
51
+
52
+ // When focus moves from outside and not with Shift + Tab, delegate it to focusElement.
53
+ if (path[0] === this && !this.contains(event.relatedTarget) && !this._isShiftTabbing) {
54
+ this.focusElement.focus();
55
+ return true;
56
+ }
57
+
58
+ if (path.includes(this.focusElement)) {
59
+ return true;
60
+ }
61
+ }
62
+
63
+ return false;
64
+ }
65
+
66
+ /**
67
+ * Override an observer from `TabindexMixin`.
68
+ * Do not call super to remove tabindex attribute
69
+ * from host when disabled by setting undefined.
70
+ * @param {string} tabindex
71
+ * @protected
72
+ * @override
73
+ */
74
+ _tabindexChanged(tabindex) {
75
+ if (tabindex !== undefined) {
76
+ this.focusElement.tabIndex = tabindex;
77
+ }
78
+
79
+ if (this.disabled && tabindex) {
80
+ // If tabindex attribute was changed while component was disabled
81
+ if (tabindex !== -1) {
82
+ this.__lastTabIndex = tabindex;
83
+ }
84
+ this.tabindex = undefined;
85
+ }
86
+ }
87
+ };