@vaadin/field-base 23.1.1 → 23.2.0-alpha1
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.
- package/package.json +3 -3
- package/src/field-mixin.js +9 -4
- package/src/input-control-mixin.d.ts +13 -0
- package/src/input-control-mixin.js +135 -0
- package/src/input-controller.js +1 -3
- package/src/input-field-mixin.js +0 -117
- package/src/label-mixin.js +6 -0
- package/src/pattern-mixin.d.ts +1 -0
- package/src/pattern-mixin.js +11 -0
- package/src/slot-target-controller.js +5 -1
- package/src/text-area-controller.js +1 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/field-base",
|
|
3
|
-
"version": "23.
|
|
3
|
+
"version": "23.2.0-alpha1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
34
34
|
"@polymer/polymer": "^3.0.0",
|
|
35
|
-
"@vaadin/component-base": "
|
|
35
|
+
"@vaadin/component-base": "23.2.0-alpha1",
|
|
36
36
|
"lit": "^2.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
41
41
|
"sinon": "^13.0.2"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "f226a2976c270d3d53c824f6e0a740a5d3382d91"
|
|
44
44
|
}
|
package/src/field-mixin.js
CHANGED
|
@@ -89,10 +89,6 @@ export const FieldMixin = (superclass) =>
|
|
|
89
89
|
this._helperController = new HelperController(this);
|
|
90
90
|
this._errorController = new ErrorController(this);
|
|
91
91
|
|
|
92
|
-
this.addController(this._fieldAriaController);
|
|
93
|
-
this.addController(this._helperController);
|
|
94
|
-
this.addController(this._errorController);
|
|
95
|
-
|
|
96
92
|
this._labelController.addEventListener('label-changed', (event) => {
|
|
97
93
|
const { hasLabel, node } = event.detail;
|
|
98
94
|
this.__labelChanged(hasLabel, node);
|
|
@@ -104,6 +100,15 @@ export const FieldMixin = (superclass) =>
|
|
|
104
100
|
});
|
|
105
101
|
}
|
|
106
102
|
|
|
103
|
+
/** @protected */
|
|
104
|
+
ready() {
|
|
105
|
+
super.ready();
|
|
106
|
+
|
|
107
|
+
this.addController(this._fieldAriaController);
|
|
108
|
+
this.addController(this._helperController);
|
|
109
|
+
this.addController(this._errorController);
|
|
110
|
+
}
|
|
111
|
+
|
|
107
112
|
/** @private */
|
|
108
113
|
__helperChanged(hasHelper, helperNode) {
|
|
109
114
|
if (hasHelper) {
|
|
@@ -36,6 +36,19 @@ export declare function InputControlMixin<T extends Constructor<HTMLElement>>(
|
|
|
36
36
|
Constructor<ValidateMixinClass>;
|
|
37
37
|
|
|
38
38
|
export declare class InputControlMixinClass {
|
|
39
|
+
/**
|
|
40
|
+
* A pattern matched against individual characters the user inputs.
|
|
41
|
+
*
|
|
42
|
+
* When set, the field will prevent:
|
|
43
|
+
* - `keydown` events if the entered key doesn't match `/^allowedCharPattern$/`
|
|
44
|
+
* - `paste` events if the pasted text doesn't match `/^allowedCharPattern*$/`
|
|
45
|
+
* - `drop` events if the dropped text doesn't match `/^allowedCharPattern*$/`
|
|
46
|
+
*
|
|
47
|
+
* For example, to allow entering only numbers and minus signs, use:
|
|
48
|
+
* `allowedCharPattern = "[\\d-]"`
|
|
49
|
+
*/
|
|
50
|
+
allowedCharPattern: string;
|
|
51
|
+
|
|
39
52
|
/**
|
|
40
53
|
* If true, the input text gets fully selected when the field is focused using click or touch / tap.
|
|
41
54
|
*/
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { timeOut } from '@vaadin/component-base/src/async.js';
|
|
7
|
+
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
6
8
|
import { KeyboardMixin } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
7
9
|
import { DelegateFocusMixin } from './delegate-focus-mixin.js';
|
|
8
10
|
import { FieldMixin } from './field-mixin.js';
|
|
@@ -23,6 +25,22 @@ export const InputControlMixin = (superclass) =>
|
|
|
23
25
|
) {
|
|
24
26
|
static get properties() {
|
|
25
27
|
return {
|
|
28
|
+
/**
|
|
29
|
+
* A pattern matched against individual characters the user inputs.
|
|
30
|
+
*
|
|
31
|
+
* When set, the field will prevent:
|
|
32
|
+
* - `keydown` events if the entered key doesn't match `/^allowedCharPattern$/`
|
|
33
|
+
* - `paste` events if the pasted text doesn't match `/^allowedCharPattern*$/`
|
|
34
|
+
* - `drop` events if the dropped text doesn't match `/^allowedCharPattern*$/`
|
|
35
|
+
*
|
|
36
|
+
* For example, to allow entering only numbers and minus signs, use:
|
|
37
|
+
* `allowedCharPattern = "[\\d-]"`
|
|
38
|
+
*/
|
|
39
|
+
allowedCharPattern: {
|
|
40
|
+
type: String,
|
|
41
|
+
observer: '_allowedCharPatternChanged',
|
|
42
|
+
},
|
|
43
|
+
|
|
26
44
|
/**
|
|
27
45
|
* If true, the input text gets fully selected when the field is focused using click or touch / tap.
|
|
28
46
|
*/
|
|
@@ -80,6 +98,14 @@ export const InputControlMixin = (superclass) =>
|
|
|
80
98
|
return [...super.delegateAttrs, 'name', 'type', 'placeholder', 'readonly', 'invalid', 'title'];
|
|
81
99
|
}
|
|
82
100
|
|
|
101
|
+
constructor() {
|
|
102
|
+
super();
|
|
103
|
+
|
|
104
|
+
this._boundOnPaste = this._onPaste.bind(this);
|
|
105
|
+
this._boundOnDrop = this._onDrop.bind(this);
|
|
106
|
+
this._boundOnBeforeInput = this._onBeforeInput.bind(this);
|
|
107
|
+
}
|
|
108
|
+
|
|
83
109
|
/**
|
|
84
110
|
* Any element extending this mixin is required to implement this getter.
|
|
85
111
|
* It returns the reference to the clear button element.
|
|
@@ -172,6 +198,115 @@ export const InputControlMixin = (superclass) =>
|
|
|
172
198
|
this.inputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
173
199
|
}
|
|
174
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Override a method from `InputMixin`.
|
|
203
|
+
* @param {!HTMLElement} input
|
|
204
|
+
* @protected
|
|
205
|
+
* @override
|
|
206
|
+
*/
|
|
207
|
+
_addInputListeners(input) {
|
|
208
|
+
super._addInputListeners(input);
|
|
209
|
+
|
|
210
|
+
input.addEventListener('paste', this._boundOnPaste);
|
|
211
|
+
input.addEventListener('drop', this._boundOnDrop);
|
|
212
|
+
input.addEventListener('beforeinput', this._boundOnBeforeInput);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Override a method from `InputMixin`.
|
|
217
|
+
* @param {!HTMLElement} input
|
|
218
|
+
* @protected
|
|
219
|
+
* @override
|
|
220
|
+
*/
|
|
221
|
+
_removeInputListeners(input) {
|
|
222
|
+
super._removeInputListeners(input);
|
|
223
|
+
|
|
224
|
+
input.removeEventListener('paste', this._boundOnPaste);
|
|
225
|
+
input.removeEventListener('drop', this._boundOnDrop);
|
|
226
|
+
input.removeEventListener('beforeinput', this._boundOnBeforeInput);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Override an event listener from `KeyboardMixin`.
|
|
231
|
+
* @param {!KeyboardEvent} event
|
|
232
|
+
* @protected
|
|
233
|
+
* @override
|
|
234
|
+
*/
|
|
235
|
+
_onKeyDown(event) {
|
|
236
|
+
super._onKeyDown(event);
|
|
237
|
+
|
|
238
|
+
if (this.allowedCharPattern && !this.__shouldAcceptKey(event)) {
|
|
239
|
+
event.preventDefault();
|
|
240
|
+
this._markInputPrevented();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** @protected */
|
|
245
|
+
_markInputPrevented() {
|
|
246
|
+
// Add input-prevented attribute for 200ms
|
|
247
|
+
this.setAttribute('input-prevented', '');
|
|
248
|
+
this._preventInputDebouncer = Debouncer.debounce(this._preventInputDebouncer, timeOut.after(200), () => {
|
|
249
|
+
this.removeAttribute('input-prevented');
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** @private */
|
|
254
|
+
__shouldAcceptKey(event) {
|
|
255
|
+
return (
|
|
256
|
+
event.metaKey ||
|
|
257
|
+
event.ctrlKey ||
|
|
258
|
+
!event.key || // Allow typing anything if event.key is not supported
|
|
259
|
+
event.key.length !== 1 || // Allow "Backspace", "ArrowLeft" etc.
|
|
260
|
+
this.__allowedCharRegExp.test(event.key)
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** @private */
|
|
265
|
+
_onPaste(e) {
|
|
266
|
+
if (this.allowedCharPattern) {
|
|
267
|
+
const pastedText = e.clipboardData.getData('text');
|
|
268
|
+
if (!this.__allowedTextRegExp.test(pastedText)) {
|
|
269
|
+
e.preventDefault();
|
|
270
|
+
this._markInputPrevented();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** @private */
|
|
276
|
+
_onDrop(e) {
|
|
277
|
+
if (this.allowedCharPattern) {
|
|
278
|
+
const draggedText = e.dataTransfer.getData('text');
|
|
279
|
+
if (!this.__allowedTextRegExp.test(draggedText)) {
|
|
280
|
+
e.preventDefault();
|
|
281
|
+
this._markInputPrevented();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** @private */
|
|
287
|
+
_onBeforeInput(e) {
|
|
288
|
+
// The `beforeinput` event covers all the cases for `allowedCharPattern`: keyboard, pasting and dropping,
|
|
289
|
+
// but it is still experimental technology so we can't rely on it. It's used here just as an additional check,
|
|
290
|
+
// because it seems to be the only way to detect and prevent specific keys on mobile devices.
|
|
291
|
+
// See https://github.com/vaadin/vaadin-text-field/issues/429
|
|
292
|
+
if (this.allowedCharPattern && e.data && !this.__allowedTextRegExp.test(e.data)) {
|
|
293
|
+
e.preventDefault();
|
|
294
|
+
this._markInputPrevented();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** @private */
|
|
299
|
+
_allowedCharPatternChanged(charPattern) {
|
|
300
|
+
if (charPattern) {
|
|
301
|
+
try {
|
|
302
|
+
this.__allowedCharRegExp = new RegExp(`^${charPattern}$`);
|
|
303
|
+
this.__allowedTextRegExp = new RegExp(`^${charPattern}*$`);
|
|
304
|
+
} catch (e) {
|
|
305
|
+
console.error(e);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
175
310
|
/**
|
|
176
311
|
* Fired when the user commits a value change.
|
|
177
312
|
*
|
package/src/input-controller.js
CHANGED
|
@@ -23,9 +23,7 @@ export class InputController extends SlotController {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
// Ensure every instance has unique ID
|
|
26
|
-
|
|
27
|
-
host._inputId = `${host.localName}-${uniqueId}`;
|
|
28
|
-
node.id = host._inputId;
|
|
26
|
+
node.id = this.defaultId;
|
|
29
27
|
|
|
30
28
|
if (typeof callback === 'function') {
|
|
31
29
|
callback(node);
|
package/src/input-field-mixin.js
CHANGED
|
@@ -47,22 +47,6 @@ export const InputFieldMixin = (superclass) =>
|
|
|
47
47
|
autocapitalize: {
|
|
48
48
|
type: String,
|
|
49
49
|
},
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* A pattern matched against individual characters the user inputs.
|
|
53
|
-
* When set, the field will prevent:
|
|
54
|
-
* - `keyDown` events if the entered key doesn't match `/^_enabledCharPattern$/`
|
|
55
|
-
* - `paste` events if the pasted text doesn't match `/^_enabledCharPattern*$/`
|
|
56
|
-
* - `drop` events if the dropped text doesn't match `/^_enabledCharPattern*$/`
|
|
57
|
-
*
|
|
58
|
-
* For example, to enable entering only numbers and minus signs,
|
|
59
|
-
* `_enabledCharPattern = "[\\d-]"`
|
|
60
|
-
* @protected
|
|
61
|
-
*/
|
|
62
|
-
_enabledCharPattern: {
|
|
63
|
-
type: String,
|
|
64
|
-
observer: '_enabledCharPatternChanged',
|
|
65
|
-
},
|
|
66
50
|
};
|
|
67
51
|
}
|
|
68
52
|
|
|
@@ -70,14 +54,6 @@ export const InputFieldMixin = (superclass) =>
|
|
|
70
54
|
return [...super.delegateAttrs, 'autocapitalize', 'autocomplete', 'autocorrect'];
|
|
71
55
|
}
|
|
72
56
|
|
|
73
|
-
constructor() {
|
|
74
|
-
super();
|
|
75
|
-
|
|
76
|
-
this._boundOnPaste = this._onPaste.bind(this);
|
|
77
|
-
this._boundOnDrop = this._onDrop.bind(this);
|
|
78
|
-
this._boundOnBeforeInput = this._onBeforeInput.bind(this);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
57
|
/**
|
|
82
58
|
* @param {HTMLElement} input
|
|
83
59
|
* @protected
|
|
@@ -149,97 +125,4 @@ export const InputFieldMixin = (superclass) =>
|
|
|
149
125
|
this.validate();
|
|
150
126
|
}
|
|
151
127
|
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Override a method from `InputMixin`.
|
|
155
|
-
* @param {!HTMLElement} input
|
|
156
|
-
* @protected
|
|
157
|
-
* @override
|
|
158
|
-
*/
|
|
159
|
-
_addInputListeners(input) {
|
|
160
|
-
super._addInputListeners(input);
|
|
161
|
-
|
|
162
|
-
input.addEventListener('paste', this._boundOnPaste);
|
|
163
|
-
input.addEventListener('drop', this._boundOnDrop);
|
|
164
|
-
input.addEventListener('beforeinput', this._boundOnBeforeInput);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Override a method from `InputMixin`.
|
|
169
|
-
* @param {!HTMLElement} input
|
|
170
|
-
* @protected
|
|
171
|
-
* @override
|
|
172
|
-
*/
|
|
173
|
-
_removeInputListeners(input) {
|
|
174
|
-
super._removeInputListeners(input);
|
|
175
|
-
|
|
176
|
-
input.removeEventListener('paste', this._boundOnPaste);
|
|
177
|
-
input.removeEventListener('drop', this._boundOnDrop);
|
|
178
|
-
input.removeEventListener('beforeinput', this._boundOnBeforeInput);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Override an event listener from `InputControlMixin`
|
|
183
|
-
* to avoid adding a separate listener.
|
|
184
|
-
* @param {!KeyboardEvent} event
|
|
185
|
-
* @protected
|
|
186
|
-
* @override
|
|
187
|
-
*/
|
|
188
|
-
_onKeyDown(event) {
|
|
189
|
-
if (this._enabledCharPattern && !this.__shouldAcceptKey(event)) {
|
|
190
|
-
event.preventDefault();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
super._onKeyDown(event);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/** @private */
|
|
197
|
-
__shouldAcceptKey(event) {
|
|
198
|
-
return (
|
|
199
|
-
event.metaKey ||
|
|
200
|
-
event.ctrlKey ||
|
|
201
|
-
!event.key || // Allow typing anything if event.key is not supported
|
|
202
|
-
event.key.length !== 1 || // Allow "Backspace", "ArrowLeft" etc.
|
|
203
|
-
this.__enabledCharRegExp.test(event.key)
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** @private */
|
|
208
|
-
_onPaste(e) {
|
|
209
|
-
if (this._enabledCharPattern) {
|
|
210
|
-
const pastedText = (e.clipboardData || window.clipboardData).getData('text');
|
|
211
|
-
if (!this.__enabledTextRegExp.test(pastedText)) {
|
|
212
|
-
e.preventDefault();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** @private */
|
|
218
|
-
_onDrop(e) {
|
|
219
|
-
if (this._enabledCharPattern) {
|
|
220
|
-
const draggedText = e.dataTransfer.getData('text');
|
|
221
|
-
if (!this.__enabledTextRegExp.test(draggedText)) {
|
|
222
|
-
e.preventDefault();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/** @private */
|
|
228
|
-
_onBeforeInput(e) {
|
|
229
|
-
// The `beforeinput` event covers all the cases for `_enabledCharPattern`: keyboard, pasting and dropping,
|
|
230
|
-
// but it is still experimental technology so we can't rely on it. It's used here just as an additional check,
|
|
231
|
-
// because it seems to be the only way to detect and prevent specific keys on mobile devices.
|
|
232
|
-
// See https://github.com/vaadin/vaadin-text-field/issues/429
|
|
233
|
-
if (this._enabledCharPattern && e.data && !this.__enabledTextRegExp.test(e.data)) {
|
|
234
|
-
e.preventDefault();
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/** @private */
|
|
239
|
-
_enabledCharPatternChanged(charPattern) {
|
|
240
|
-
if (charPattern) {
|
|
241
|
-
this.__enabledCharRegExp = new RegExp(`^${charPattern}$`);
|
|
242
|
-
this.__enabledTextRegExp = new RegExp(`^${charPattern}*$`);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
128
|
};
|
package/src/label-mixin.js
CHANGED
package/src/pattern-mixin.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export declare class PatternMixinClass {
|
|
|
34
34
|
* When set to true, user is prevented from typing a value that
|
|
35
35
|
* conflicts with the given `pattern`.
|
|
36
36
|
* @attr {boolean} prevent-invalid-input
|
|
37
|
+
* @deprecated Please use `allowedCharPattern` instead.
|
|
37
38
|
*/
|
|
38
39
|
preventInvalidInput: boolean | null | undefined;
|
|
39
40
|
}
|
package/src/pattern-mixin.js
CHANGED
|
@@ -29,9 +29,11 @@ export const PatternMixin = (superclass) =>
|
|
|
29
29
|
* When set to true, user is prevented from typing a value that
|
|
30
30
|
* conflicts with the given `pattern`.
|
|
31
31
|
* @attr {boolean} prevent-invalid-input
|
|
32
|
+
* @deprecated Please use `allowedCharPattern` instead.
|
|
32
33
|
*/
|
|
33
34
|
preventInvalidInput: {
|
|
34
35
|
type: Boolean,
|
|
36
|
+
observer: '_preventInvalidInputChanged',
|
|
35
37
|
},
|
|
36
38
|
};
|
|
37
39
|
}
|
|
@@ -68,4 +70,13 @@ export const PatternMixin = (superclass) =>
|
|
|
68
70
|
|
|
69
71
|
super._onInput(event);
|
|
70
72
|
}
|
|
73
|
+
|
|
74
|
+
/** @private */
|
|
75
|
+
_preventInvalidInputChanged(preventInvalidInput) {
|
|
76
|
+
if (preventInvalidInput) {
|
|
77
|
+
console.warn(
|
|
78
|
+
`WARNING: Since Vaadin 23.2, "preventInvalidInput" is deprecated. Please use "allowedCharPattern" instead.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
71
82
|
};
|
|
@@ -41,7 +41,11 @@ export class SlotTargetController {
|
|
|
41
41
|
|
|
42
42
|
// Ensure the content is up to date when host is connected
|
|
43
43
|
// to handle e.g. mutating text content while disconnected.
|
|
44
|
-
|
|
44
|
+
// Note, `hostConnected()` is called twice if the controller
|
|
45
|
+
// is initialized in `ready()` when using `ControllerMixin`.
|
|
46
|
+
if (!this.__copying) {
|
|
47
|
+
this.__checkAndCopyNodesToSlotTarget();
|
|
48
|
+
}
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
/**
|
|
@@ -25,10 +25,7 @@ export class TextAreaController extends SlotController {
|
|
|
25
25
|
node.setAttribute('name', name);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
const uniqueId = (TextAreaController._uniqueTextAreaId = 1 + TextAreaController._uniqueTextAreaId || 0);
|
|
30
|
-
host._textareaId = `${host.localName}-${uniqueId}`;
|
|
31
|
-
node.id = host._textareaId;
|
|
28
|
+
node.id = this.defaultId;
|
|
32
29
|
|
|
33
30
|
if (typeof callback === 'function') {
|
|
34
31
|
callback(node);
|