@vaadin/field-base 22.0.0-alpha1 → 22.0.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.
Files changed (67) hide show
  1. package/index.d.ts +10 -9
  2. package/index.js +10 -9
  3. package/package.json +25 -19
  4. package/src/aria-label-controller.d.ts +11 -0
  5. package/src/aria-label-controller.js +58 -0
  6. package/src/checked-mixin.d.ts +26 -0
  7. package/src/checked-mixin.js +54 -0
  8. package/src/delegate-focus-mixin.d.ts +7 -4
  9. package/src/delegate-focus-mixin.js +154 -72
  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 +28 -0
  15. package/src/input-constraints-mixin.js +126 -0
  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 -22
  21. package/src/input-field-mixin.js +117 -168
  22. package/src/input-mixin.d.ts +22 -6
  23. package/src/input-mixin.js +161 -51
  24. package/src/label-mixin.d.ts +2 -2
  25. package/src/label-mixin.js +74 -60
  26. package/src/pattern-mixin.d.ts +32 -0
  27. package/src/pattern-mixin.js +72 -0
  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/clear-button-mixin.d.ts +0 -32
  51. package/src/clear-button-mixin.js +0 -87
  52. package/src/disabled-mixin.d.ts +0 -23
  53. package/src/disabled-mixin.js +0 -48
  54. package/src/field-aria-mixin.d.ts +0 -24
  55. package/src/field-aria-mixin.js +0 -61
  56. package/src/focus-mixin.d.ts +0 -33
  57. package/src/focus-mixin.js +0 -104
  58. package/src/helper-text-mixin.d.ts +0 -24
  59. package/src/helper-text-mixin.js +0 -109
  60. package/src/input-aria-mixin.d.ts +0 -20
  61. package/src/input-aria-mixin.js +0 -69
  62. package/src/input-props-mixin.d.ts +0 -40
  63. package/src/input-props-mixin.js +0 -106
  64. package/src/slot-mixin.d.ts +0 -23
  65. package/src/slot-mixin.js +0 -55
  66. package/src/text-field-mixin.d.ts +0 -47
  67. package/src/text-field-mixin.js +0 -125
@@ -0,0 +1,125 @@
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 { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
7
+
8
+ /**
9
+ * A mixin to delegate properties and attributes to a target element.
10
+ *
11
+ * @polymerMixin
12
+ */
13
+ export const DelegateStateMixin = dedupingMixin(
14
+ (superclass) =>
15
+ class DelegateStateMixinClass extends superclass {
16
+ static get properties() {
17
+ return {
18
+ /**
19
+ * A target element to which attributes and properties are delegated.
20
+ * @protected
21
+ */
22
+ stateTarget: {
23
+ type: Object,
24
+ observer: '_stateTargetChanged'
25
+ }
26
+ };
27
+ }
28
+
29
+ /**
30
+ * An array of the host attributes to delegate to the target element.
31
+ */
32
+ static get delegateAttrs() {
33
+ return [];
34
+ }
35
+
36
+ /**
37
+ * An array of the host properties to delegate to the target element.
38
+ */
39
+ static get delegateProps() {
40
+ return [];
41
+ }
42
+
43
+ /** @protected */
44
+ ready() {
45
+ super.ready();
46
+
47
+ this._createDelegateAttrsObserver();
48
+ this._createDelegatePropsObserver();
49
+ }
50
+
51
+ /** @protected */
52
+ _stateTargetChanged(target) {
53
+ if (target) {
54
+ this._ensureAttrsDelegated();
55
+ this._ensurePropsDelegated();
56
+ }
57
+ }
58
+
59
+ /** @protected */
60
+ _createDelegateAttrsObserver() {
61
+ this._createMethodObserver(`_delegateAttrsChanged(${this.constructor.delegateAttrs.join(', ')})`);
62
+ }
63
+
64
+ /** @protected */
65
+ _createDelegatePropsObserver() {
66
+ this._createMethodObserver(`_delegatePropsChanged(${this.constructor.delegateProps.join(', ')})`);
67
+ }
68
+
69
+ /** @protected */
70
+ _ensureAttrsDelegated() {
71
+ this.constructor.delegateAttrs.forEach((name) => {
72
+ this._delegateAttribute(name, this[name]);
73
+ });
74
+ }
75
+
76
+ /** @protected */
77
+ _ensurePropsDelegated() {
78
+ this.constructor.delegateProps.forEach((name) => {
79
+ this._delegateProperty(name, this[name]);
80
+ });
81
+ }
82
+
83
+ /** @protected */
84
+ _delegateAttrsChanged(...values) {
85
+ this.constructor.delegateAttrs.forEach((name, index) => {
86
+ this._delegateAttribute(name, values[index]);
87
+ });
88
+ }
89
+
90
+ /** @protected */
91
+ _delegatePropsChanged(...values) {
92
+ this.constructor.delegateProps.forEach((name, index) => {
93
+ this._delegateProperty(name, values[index]);
94
+ });
95
+ }
96
+
97
+ /** @protected */
98
+ _delegateAttribute(name, value) {
99
+ if (!this.stateTarget) {
100
+ return;
101
+ }
102
+
103
+ if (name === 'invalid') {
104
+ this._delegateAttribute('aria-invalid', value ? 'true' : false);
105
+ }
106
+
107
+ if (typeof value === 'boolean') {
108
+ this.stateTarget.toggleAttribute(name, value);
109
+ } else if (value) {
110
+ this.stateTarget.setAttribute(name, value);
111
+ } else {
112
+ this.stateTarget.removeAttribute(name);
113
+ }
114
+ }
115
+
116
+ /** @protected */
117
+ _delegateProperty(name, value) {
118
+ if (!this.stateTarget) {
119
+ return;
120
+ }
121
+
122
+ this.stateTarget[name] = value;
123
+ }
124
+ }
125
+ );
@@ -0,0 +1,39 @@
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 { LabelMixin } from './label-mixin.js';
7
+ import { ValidateMixin } from './validate-mixin.js';
8
+
9
+ /**
10
+ * A mixin to provide common field logic: label, error message and helper text.
11
+ */
12
+ declare function FieldMixin<T extends new (...args: any[]) => {}>(base: T): T & FieldMixinConstructor;
13
+
14
+ interface FieldMixinConstructor {
15
+ new (...args: any[]): FieldMixin;
16
+ }
17
+
18
+ interface FieldMixin extends LabelMixin, ValidateMixin {
19
+ /**
20
+ * A target element to which ARIA attributes are set.
21
+ */
22
+ ariaTarget: HTMLElement;
23
+
24
+ /**
25
+ * String used for the helper text.
26
+ *
27
+ * @attr {string} helper-text
28
+ */
29
+ helperText: string | null | undefined;
30
+
31
+ /**
32
+ * Error to show when the field is invalid.
33
+ *
34
+ * @attr {string} error-message
35
+ */
36
+ errorMessage: string;
37
+ }
38
+
39
+ export { FieldMixin, FieldMixinConstructor };
@@ -0,0 +1,317 @@
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 { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
7
+ import { Debouncer } from '@vaadin/component-base/src/debounce.js';
8
+ import { animationFrame } from '@vaadin/component-base/src/async.js';
9
+ import { LabelMixin } from './label-mixin.js';
10
+ import { ValidateMixin } from './validate-mixin.js';
11
+
12
+ /**
13
+ * A mixin to provide common field logic: label, error message and helper text.
14
+ *
15
+ * @polymerMixin
16
+ * @mixes LabelMixin
17
+ * @mixes ValidateMixin
18
+ */
19
+ export const FieldMixin = (superclass) =>
20
+ class FieldMixinClass extends ValidateMixin(LabelMixin(superclass)) {
21
+ static get properties() {
22
+ return {
23
+ /**
24
+ * A target element to which ARIA attributes are set.
25
+ * @protected
26
+ */
27
+ ariaTarget: {
28
+ type: Object,
29
+ observer: '_ariaTargetChanged'
30
+ },
31
+
32
+ /**
33
+ * Error to show when the field is invalid.
34
+ *
35
+ * @attr {string} error-message
36
+ */
37
+ errorMessage: {
38
+ type: String
39
+ },
40
+
41
+ /**
42
+ * String used for the helper text.
43
+ * @attr {string} helper-text
44
+ */
45
+ helperText: {
46
+ type: String,
47
+ observer: '_helperTextChanged'
48
+ },
49
+
50
+ /** @protected */
51
+ _helperId: String
52
+ };
53
+ }
54
+
55
+ /** @protected */
56
+ get slots() {
57
+ return {
58
+ ...super.slots,
59
+ 'error-message': () => {
60
+ const error = document.createElement('div');
61
+ error.textContent = this.errorMessage;
62
+ error.setAttribute('aria-live', 'assertive');
63
+ return error;
64
+ }
65
+ };
66
+ }
67
+
68
+ static get observers() {
69
+ return [
70
+ '__ariaChanged(invalid, _helperId)',
71
+ '__observeOffsetHeight(errorMessage, invalid, label, helperText)',
72
+ '_updateErrorMessage(invalid, errorMessage)'
73
+ ];
74
+ }
75
+
76
+ /** @protected */
77
+ get _errorNode() {
78
+ return this._getDirectSlotChild('error-message');
79
+ }
80
+
81
+ /** @protected */
82
+ get _helperNode() {
83
+ return this._getDirectSlotChild('helper');
84
+ }
85
+
86
+ /** @protected */
87
+ get _ariaAttr() {
88
+ return 'aria-describedby';
89
+ }
90
+
91
+ constructor() {
92
+ super();
93
+
94
+ // Ensure every instance has unique ID
95
+ const uniqueId = (FieldMixinClass._uniqueFieldId = 1 + FieldMixinClass._uniqueFieldId || 0);
96
+ this._errorId = `error-${this.localName}-${uniqueId}`;
97
+ this._helperId = `helper-${this.localName}-${uniqueId}`;
98
+
99
+ // Save generated ID to restore later
100
+ this.__savedHelperId = this._helperId;
101
+ }
102
+
103
+ /** @protected */
104
+ ready() {
105
+ super.ready();
106
+
107
+ const error = this._errorNode;
108
+ if (error) {
109
+ error.id = this._errorId;
110
+
111
+ this.__applyCustomError();
112
+
113
+ this._updateErrorMessage(this.invalid, this.errorMessage);
114
+ }
115
+
116
+ const helper = this._helperNode;
117
+ if (helper) {
118
+ this.__applyCustomHelper(helper);
119
+ }
120
+
121
+ this.__helperSlot = this.shadowRoot.querySelector('[name="helper"]');
122
+
123
+ this.__helperSlotObserver = new FlattenedNodesObserver(this.__helperSlot, (info) => {
124
+ const helper = this._currentHelper;
125
+
126
+ const newHelper = info.addedNodes.find((node) => node !== helper);
127
+ const oldHelper = info.removedNodes.find((node) => node === helper);
128
+
129
+ if (newHelper) {
130
+ // Custom helper is added, remove the previous one.
131
+ if (helper && helper.isConnected) {
132
+ this.removeChild(helper);
133
+ }
134
+
135
+ this.__applyCustomHelper(newHelper);
136
+
137
+ this.__helperIdObserver = new MutationObserver((mutations) => {
138
+ mutations.forEach((mutation) => {
139
+ // only handle helper nodes
140
+ if (
141
+ mutation.type === 'attributes' &&
142
+ mutation.attributeName === 'id' &&
143
+ mutation.target === this._currentHelper &&
144
+ mutation.target.id !== this.__savedHelperId
145
+ ) {
146
+ this.__updateHelperId(mutation.target);
147
+ }
148
+ });
149
+ });
150
+
151
+ this.__helperIdObserver.observe(newHelper, { attributes: true });
152
+ } else if (oldHelper) {
153
+ // The observer does not exist when default helper is removed.
154
+ if (this.__helperIdObserver) {
155
+ this.__helperIdObserver.disconnect();
156
+ }
157
+
158
+ this.__applyDefaultHelper(this.helperText);
159
+ }
160
+ });
161
+ }
162
+
163
+ /** @private */
164
+ __applyCustomError() {
165
+ const error = this.__errorMessage;
166
+ if (error && error !== this.errorMessage) {
167
+ this.errorMessage = error;
168
+ delete this.__errorMessage;
169
+ }
170
+ }
171
+
172
+ /** @private */
173
+ __applyCustomHelper(helper) {
174
+ this.__updateHelperId(helper);
175
+ this._currentHelper = helper;
176
+ this.__toggleHasHelper(helper.children.length > 0 || this.__isNotEmpty(helper.textContent));
177
+ }
178
+
179
+ /** @private */
180
+ __isNotEmpty(helperText) {
181
+ return helperText && helperText.trim() !== '';
182
+ }
183
+
184
+ /** @private */
185
+ __attachDefaultHelper() {
186
+ let helper = this.__defaultHelper;
187
+
188
+ if (!helper) {
189
+ helper = document.createElement('div');
190
+ helper.setAttribute('slot', 'helper');
191
+ this.__defaultHelper = helper;
192
+ }
193
+
194
+ helper.id = this.__savedHelperId;
195
+ this.appendChild(helper);
196
+ this._currentHelper = helper;
197
+
198
+ return helper;
199
+ }
200
+
201
+ /** @private */
202
+ __applyDefaultHelper(helperText) {
203
+ let helper = this._helperNode;
204
+
205
+ const hasHelperText = this.__isNotEmpty(helperText);
206
+ if (hasHelperText && !helper) {
207
+ // Create helper lazily
208
+ helper = this.__attachDefaultHelper();
209
+ }
210
+
211
+ // Only set text content for default helper
212
+ if (helper && helper === this.__defaultHelper) {
213
+ helper.textContent = helperText;
214
+ }
215
+
216
+ this.__toggleHasHelper(hasHelperText);
217
+ }
218
+
219
+ /** @private */
220
+ __toggleHasHelper(hasHelper) {
221
+ this.toggleAttribute('has-helper', hasHelper);
222
+ }
223
+
224
+ /**
225
+ * Dispatch an event if a specific size measurement property has changed.
226
+ * Supporting multiple properties here is needed for `vaadin-text-area`.
227
+ * @protected
228
+ */
229
+ _dispatchIronResizeEventIfNeeded(prop, value) {
230
+ const oldSize = '__old' + prop;
231
+ if (this[oldSize] !== undefined && this[oldSize] !== value) {
232
+ this.dispatchEvent(new CustomEvent('iron-resize', { bubbles: true, composed: true }));
233
+ }
234
+
235
+ this[oldSize] = value;
236
+ }
237
+
238
+ /** @private */
239
+ __observeOffsetHeight() {
240
+ this.__observeOffsetHeightDebouncer = Debouncer.debounce(
241
+ this.__observeOffsetHeightDebouncer,
242
+ animationFrame,
243
+ () => {
244
+ this._dispatchIronResizeEventIfNeeded('Height', this.offsetHeight);
245
+ }
246
+ );
247
+ }
248
+
249
+ /**
250
+ * @param {boolean} invalid
251
+ * @protected
252
+ */
253
+ _updateErrorMessage(invalid, errorMessage) {
254
+ const error = this._errorNode;
255
+ if (!error) {
256
+ return;
257
+ }
258
+
259
+ // save the custom error message content
260
+ if (error.textContent && !errorMessage) {
261
+ this.__errorMessage = error.textContent.trim();
262
+ }
263
+ const hasError = Boolean(invalid && errorMessage);
264
+ error.textContent = hasError ? errorMessage : '';
265
+ this.toggleAttribute('has-error-message', hasError);
266
+ }
267
+
268
+ /** @private */
269
+ __updateHelperId(customHelper) {
270
+ let newId;
271
+
272
+ if (customHelper.id) {
273
+ newId = customHelper.id;
274
+ } else {
275
+ newId = this.__savedHelperId;
276
+ customHelper.id = newId;
277
+ }
278
+
279
+ this._helperId = newId;
280
+ }
281
+
282
+ /** @protected */
283
+ _helperTextChanged(helperText) {
284
+ this.__applyDefaultHelper(helperText);
285
+ }
286
+
287
+ /** @protected */
288
+ _ariaTargetChanged(target) {
289
+ if (target) {
290
+ this._updateAriaAttribute(this.invalid, this._helperId);
291
+ }
292
+ }
293
+
294
+ /** @protected */
295
+ _updateAriaAttribute(invalid, helperId) {
296
+ const attr = this._ariaAttr;
297
+
298
+ if (this.ariaTarget && attr) {
299
+ // For groups, add all IDs to aria-labelledby rather than aria-describedby -
300
+ // that should guarantee that it's announced when the group is entered.
301
+ const ariaIds = attr === 'aria-describedby' ? [helperId] : [this._labelId, helperId];
302
+
303
+ // Error message ID needs to be dynamically added / removed based on the validity
304
+ // Otherwise assistive technologies would announce the error, even if we hide it.
305
+ if (invalid) {
306
+ ariaIds.push(this._errorId);
307
+ }
308
+
309
+ this.ariaTarget.setAttribute(attr, ariaIds.join(' '));
310
+ }
311
+ }
312
+
313
+ /** @private */
314
+ __ariaChanged(invalid, helperId) {
315
+ this._updateAriaAttribute(invalid, helperId);
316
+ }
317
+ };
@@ -0,0 +1,28 @@
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 { DelegateStateMixin } from './delegate-state-mixin.js';
7
+ import { InputMixin } from './input-mixin.js';
8
+ import { ValidateMixin } from './validate-mixin.js';
9
+
10
+ /**
11
+ * A mixin to combine multiple input validation constraints.
12
+ */
13
+ declare function InputConstraintsMixin<T extends new (...args: any[]) => {}>(
14
+ base: T
15
+ ): T & InputConstraintsMixinConstructor;
16
+
17
+ interface InputConstraintsMixinConstructor {
18
+ new (...args: any[]): InputConstraintsMixin;
19
+ }
20
+
21
+ interface InputConstraintsMixin extends DelegateStateMixin, InputMixin, ValidateMixin {
22
+ /**
23
+ * Returns true if the current input value satisfies all constraints (if any).
24
+ */
25
+ checkValidity(): boolean;
26
+ }
27
+
28
+ export { InputConstraintsMixin, InputConstraintsMixinConstructor };
@@ -0,0 +1,126 @@
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 { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
7
+ import { DelegateStateMixin } from './delegate-state-mixin.js';
8
+ import { InputMixin } from './input-mixin.js';
9
+ import { ValidateMixin } from './validate-mixin.js';
10
+
11
+ /**
12
+ * A mixin to combine multiple input validation constraints.
13
+ *
14
+ * @polymerMixin
15
+ * @mixes DelegateStateMixin
16
+ * @mixes InputMixin
17
+ * @mixes ValidateMixin
18
+ */
19
+ export const InputConstraintsMixin = dedupingMixin(
20
+ (superclass) =>
21
+ class InputConstraintsMixinClass extends DelegateStateMixin(ValidateMixin(InputMixin(superclass))) {
22
+ /**
23
+ * An array of attributes which participate in the input validation.
24
+ * Changing these attributes will cause the input to re-validate.
25
+ *
26
+ * IMPORTANT: The attributes should be properly delegated to the input element
27
+ * from the host using `delegateAttrs` getter (see `DelegateStateMixin`).
28
+ * The `required` attribute is already delegated.
29
+ */
30
+ static get constraints() {
31
+ return ['required'];
32
+ }
33
+
34
+ static get delegateAttrs() {
35
+ return [...super.delegateAttrs, 'required'];
36
+ }
37
+
38
+ /** @protected */
39
+ ready() {
40
+ super.ready();
41
+
42
+ this._createConstraintsObserver();
43
+ }
44
+
45
+ /**
46
+ * Returns true if the current input value satisfies all constraints (if any).
47
+ * @return {boolean}
48
+ */
49
+ checkValidity() {
50
+ if (this.inputElement && this._hasValidConstraints(this.constructor.constraints.map((c) => this[c]))) {
51
+ return this.inputElement.checkValidity();
52
+ } else {
53
+ return !this.invalid;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Returns true if some of the provided set of constraints are valid.
59
+ * @param {Array} constraints
60
+ * @return {boolean}
61
+ * @protected
62
+ */
63
+ _hasValidConstraints(constraints) {
64
+ return constraints.some((c) => this.__isValidConstraint(c));
65
+ }
66
+
67
+ /**
68
+ * Override this method to customize setting up constraints observer.
69
+ * @protected
70
+ */
71
+ _createConstraintsObserver() {
72
+ // This complex observer needs to be added dynamically instead of using `static get observers()`
73
+ // to make it possible to tweak this behavior in classes that apply this mixin.
74
+ this._createMethodObserver(`_constraintsChanged(${this.constructor.constraints.join(', ')})`);
75
+ }
76
+
77
+ /**
78
+ * Override this method to implement custom validation constraints.
79
+ * @param {unknown[]} constraints
80
+ * @protected
81
+ */
82
+ _constraintsChanged(...constraints) {
83
+ // Prevent marking field as invalid when setting required state
84
+ // or any other constraint before a user has entered the value.
85
+ if (!this.invalid) {
86
+ return;
87
+ }
88
+
89
+ if (this._hasValidConstraints(constraints)) {
90
+ this.validate();
91
+ } else {
92
+ this.invalid = false;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Override an event listener inherited from `InputMixin`
98
+ * to capture native `change` event and make sure that
99
+ * a new one is dispatched after validation runs.
100
+ * @param {Event} event
101
+ * @protected
102
+ * @override
103
+ */
104
+ _onChange(event) {
105
+ event.stopPropagation();
106
+
107
+ this.validate();
108
+
109
+ this.dispatchEvent(
110
+ new CustomEvent('change', {
111
+ detail: {
112
+ sourceEvent: event
113
+ },
114
+ bubbles: event.bubbles,
115
+ cancelable: event.cancelable
116
+ })
117
+ );
118
+ }
119
+
120
+ /** @private */
121
+ __isValidConstraint(constraint) {
122
+ // 0 is valid for `minlength` and `maxlength`
123
+ return Boolean(constraint) || constraint === 0;
124
+ }
125
+ }
126
+ );
@@ -0,0 +1,52 @@
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 { FieldMixin } from './field-mixin.js';
8
+ import { InputConstraintsMixin } from './input-constraints-mixin.js';
9
+
10
+ /**
11
+ * A mixin to provide shared logic for the editable form input controls.
12
+ */
13
+ declare function InputControlMixin<T extends new (...args: any[]) => {}>(base: T): T & InputControlMixinConstructor;
14
+
15
+ interface InputControlMixinConstructor {
16
+ new (...args: any[]): InputControlMixin;
17
+ }
18
+
19
+ interface InputControlMixin extends KeyboardMixin, InputConstraintsMixin, FieldMixin {
20
+ /**
21
+ * If true, the input text gets fully selected when the field is focused using click or touch / tap.
22
+ */
23
+ autoselect: boolean;
24
+
25
+ /**
26
+ * Set to true to display the clear icon which clears the input.
27
+ * @attr {boolean} clear-button-visible
28
+ */
29
+ clearButtonVisible: boolean;
30
+
31
+ /**
32
+ * The name of this field.
33
+ */
34
+ name: string;
35
+
36
+ /**
37
+ * A hint to the user of what can be entered in the field.
38
+ */
39
+ placeholder: string;
40
+
41
+ /**
42
+ * When present, it specifies that the field is read-only.
43
+ */
44
+ readonly: boolean;
45
+
46
+ /**
47
+ * The text usually displayed in a tooltip popup when the mouse is over the field.
48
+ */
49
+ title: string;
50
+ }
51
+
52
+ export { InputControlMixin, InputControlMixinConstructor };