@vaadin/field-base 23.2.0-dev.8a7678b70 → 23.2.0-rc1

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 (37) hide show
  1. package/package.json +3 -3
  2. package/src/checked-mixin.d.ts +7 -7
  3. package/src/checked-mixin.js +11 -1
  4. package/src/delegate-focus-mixin.d.ts +7 -7
  5. package/src/delegate-state-mixin.d.ts +2 -2
  6. package/src/error-controller.js +1 -0
  7. package/src/field-aria-controller.js +2 -2
  8. package/src/field-mixin.d.ts +7 -7
  9. package/src/field-mixin.js +1 -1
  10. package/src/helper-controller.d.ts +1 -1
  11. package/src/helper-controller.js +2 -2
  12. package/src/input-constraints-mixin.d.ts +8 -8
  13. package/src/input-constraints-mixin.js +14 -8
  14. package/src/input-control-mixin.d.ts +15 -15
  15. package/src/input-controller.js +1 -0
  16. package/src/input-field-mixin.d.ts +18 -18
  17. package/src/input-field-mixin.js +17 -9
  18. package/src/input-mixin.d.ts +9 -3
  19. package/src/input-mixin.js +64 -10
  20. package/src/label-controller.js +1 -0
  21. package/src/label-mixin.d.ts +3 -3
  22. package/src/labelled-input-controller.d.ts +1 -1
  23. package/src/pattern-mixin.d.ts +9 -9
  24. package/src/pattern-mixin.js +1 -0
  25. package/src/shadow-focus-mixin.d.ts +9 -9
  26. package/src/slot-styles-mixin.d.ts +2 -2
  27. package/src/slot-target-controller.d.ts +1 -1
  28. package/src/styles/clear-button-styles.d.ts +1 -1
  29. package/src/styles/field-shared-styles.d.ts +1 -1
  30. package/src/styles/input-field-container-styles.d.ts +1 -1
  31. package/src/styles/input-field-shared-styles.d.ts +1 -1
  32. package/src/text-area-controller.js +1 -0
  33. package/src/validate-mixin.d.ts +10 -2
  34. package/src/validate-mixin.js +36 -2
  35. package/src/virtual-keyboard-controller.d.ts +2 -2
  36. package/src/utils.d.ts +0 -16
  37. package/src/utils.js +0 -56
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/field-base",
3
- "version": "23.2.0-dev.8a7678b70",
3
+ "version": "23.2.0-rc1",
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": "23.2.0-dev.8a7678b70",
35
+ "@vaadin/component-base": "23.2.0-rc1",
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": "85b403f96d8282f262322b56c0ff4289f843d02a"
43
+ "gitHead": "e78a1f2fe6f42d78cefa3f48085b09a3033c9588"
44
44
  }
@@ -3,21 +3,21 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { DelegateStateMixinClass } from './delegate-state-mixin.js';
9
- import { InputMixinClass } from './input-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { DelegateStateMixinClass } from './delegate-state-mixin.js';
9
+ import type { InputMixinClass } from './input-mixin.js';
10
10
 
11
11
  /**
12
12
  * A mixin to manage the checked state.
13
13
  */
14
14
  export declare function CheckedMixin<T extends Constructor<object>>(
15
15
  base: T,
16
- ): T &
17
- Constructor<CheckedMixinClass> &
16
+ ): Constructor<CheckedMixinClass> &
18
17
  Constructor<DelegateStateMixinClass> &
19
18
  Constructor<DisabledMixinClass> &
20
- Constructor<InputMixinClass>;
19
+ Constructor<InputMixinClass> &
20
+ T;
21
21
 
22
22
  export declare class CheckedMixinClass {
23
23
  /**
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
7
7
  import { DisabledMixin } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import { isElementFocused } from '@vaadin/component-base/src/focus-utils.js';
8
9
  import { DelegateStateMixin } from './delegate-state-mixin.js';
9
10
  import { InputMixin } from './input-mixin.js';
10
11
 
@@ -39,11 +40,20 @@ export const CheckedMixin = dedupingMixin(
39
40
  }
40
41
 
41
42
  /**
43
+ * @param {Event} event
42
44
  * @protected
43
45
  * @override
44
46
  */
45
47
  _onChange(event) {
46
- this._toggleChecked(event.target.checked);
48
+ const input = event.target;
49
+
50
+ this._toggleChecked(input.checked);
51
+
52
+ // Clicking the checkbox or radio-button in Safari
53
+ // does not make it focused, so we do it manually.
54
+ if (!isElementFocused(input)) {
55
+ input.focus();
56
+ }
47
57
  }
48
58
 
49
59
  /** @protected */
@@ -3,21 +3,21 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
9
- import { TabindexMixinClass } from '@vaadin/component-base/src/tabindex-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
9
+ import type { TabindexMixinClass } from '@vaadin/component-base/src/tabindex-mixin.js';
10
10
 
11
11
  /**
12
12
  * A mixin to forward focus to an element in the light DOM.
13
13
  */
14
14
  export declare function DelegateFocusMixin<T extends Constructor<HTMLElement>>(
15
15
  base: T,
16
- ): T &
17
- Constructor<DelegateFocusMixinClass> &
16
+ ): Constructor<DelegateFocusMixinClass> &
18
17
  Constructor<DisabledMixinClass> &
19
18
  Constructor<FocusMixinClass> &
20
- Constructor<TabindexMixinClass>;
19
+ Constructor<TabindexMixinClass> &
20
+ T;
21
21
 
22
22
  export declare class DelegateFocusMixinClass {
23
23
  /**
@@ -3,14 +3,14 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
 
8
8
  /**
9
9
  * A mixin to delegate properties and attributes to a target element.
10
10
  */
11
11
  export declare function DelegateStateMixin<T extends Constructor<HTMLElement>>(
12
12
  base: T,
13
- ): T & Constructor<DelegateStateMixinClass>;
13
+ ): Constructor<DelegateStateMixinClass> & T;
14
14
 
15
15
  export declare class DelegateStateMixinClass {
16
16
  /**
@@ -19,6 +19,7 @@ export class ErrorController extends SlotController {
19
19
 
20
20
  this.__updateHasError();
21
21
  },
22
+ true,
22
23
  );
23
24
  }
24
25
 
@@ -3,7 +3,7 @@
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 { addValueToAttribute, removeValueFromAttribute } from './utils.js';
6
+ import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js';
7
7
 
8
8
  /**
9
9
  * A controller for managing ARIA attributes for a field element:
@@ -139,7 +139,7 @@ export class FieldAriaController {
139
139
  return;
140
140
  }
141
141
 
142
- if (!this.__isGroupField) {
142
+ if (['input', 'textarea'].includes(this.__target.localName)) {
143
143
  // Native <input> or <textarea>, required is enough
144
144
  return;
145
145
  }
@@ -3,21 +3,21 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
- import { LabelMixinClass } from './label-mixin.js';
9
- import { ValidateMixinClass } from './validate-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
+ import type { LabelMixinClass } from './label-mixin.js';
9
+ import type { ValidateMixinClass } from './validate-mixin.js';
10
10
 
11
11
  /**
12
12
  * A mixin to provide common field logic: label, error message and helper text.
13
13
  */
14
14
  export declare function FieldMixin<T extends Constructor<HTMLElement>>(
15
15
  superclass: T,
16
- ): T &
17
- Constructor<ControllerMixinClass> &
16
+ ): Constructor<ControllerMixinClass> &
18
17
  Constructor<FieldMixinClass> &
19
18
  Constructor<LabelMixinClass> &
20
- Constructor<ValidateMixinClass>;
19
+ Constructor<ValidateMixinClass> &
20
+ T;
21
21
 
22
22
  export declare class FieldMixinClass {
23
23
  /**
@@ -164,7 +164,7 @@ export const FieldMixin = (superclass) =>
164
164
  }
165
165
 
166
166
  /**
167
- * @param {boolean} required
167
+ * @param {boolean} invalid
168
168
  * @protected
169
169
  */
170
170
  _invalidChanged(invalid) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
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
6
  import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
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
6
  import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
@@ -11,7 +11,7 @@ import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
11
11
  export class HelperController extends SlotController {
12
12
  constructor(host) {
13
13
  // Do not provide slot factory, as only create helper lazily.
14
- super(host, 'helper');
14
+ super(host, 'helper', null, null, true);
15
15
  }
16
16
 
17
17
  get helperId() {
@@ -3,23 +3,23 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { DelegateStateMixinClass } from './delegate-state-mixin.js';
9
- import { InputMixinClass } from './input-mixin.js';
10
- import { ValidateMixinClass } from './validate-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { DelegateStateMixinClass } from './delegate-state-mixin.js';
9
+ import type { InputMixinClass } from './input-mixin.js';
10
+ import type { ValidateMixinClass } from './validate-mixin.js';
11
11
 
12
12
  /**
13
13
  * A mixin to combine multiple input validation constraints.
14
14
  */
15
15
  export declare function InputConstraintsMixin<T extends Constructor<HTMLElement>>(
16
16
  base: T,
17
- ): T &
18
- Constructor<DelegateStateMixinClass> &
17
+ ): Constructor<DelegateStateMixinClass> &
19
18
  Constructor<DisabledMixinClass> &
20
19
  Constructor<InputConstraintsMixinClass> &
21
20
  Constructor<InputMixinClass> &
22
- Constructor<ValidateMixinClass>;
21
+ Constructor<ValidateMixinClass> &
22
+ T;
23
23
 
24
24
  export declare class InputConstraintsMixinClass {
25
25
  /**
@@ -70,26 +70,32 @@ export const InputConstraintsMixin = dedupingMixin(
70
70
  _createConstraintsObserver() {
71
71
  // This complex observer needs to be added dynamically instead of using `static get observers()`
72
72
  // to make it possible to tweak this behavior in classes that apply this mixin.
73
- this._createMethodObserver(`_constraintsChanged(${this.constructor.constraints.join(', ')})`);
73
+ this._createMethodObserver(`_constraintsChanged(stateTarget, ${this.constructor.constraints.join(', ')})`);
74
74
  }
75
75
 
76
76
  /**
77
77
  * Override this method to implement custom validation constraints.
78
+ * @param {HTMLElement | undefined} stateTarget
78
79
  * @param {unknown[]} constraints
79
80
  * @protected
80
81
  */
81
- _constraintsChanged(...constraints) {
82
- // Prevent marking field as invalid when setting required state
83
- // or any other constraint before a user has entered the value.
84
- if (!this.invalid) {
82
+ _constraintsChanged(stateTarget, ...constraints) {
83
+ // The input element's validity cannot be determined until
84
+ // all the necessary constraint attributes aren't set on it.
85
+ if (!stateTarget) {
85
86
  return;
86
87
  }
87
88
 
88
- if (this._hasValidConstraints(constraints)) {
89
+ const hasConstraints = this._hasValidConstraints(constraints);
90
+ const isLastConstraintRemoved = this.__previousHasConstraints && !hasConstraints;
91
+
92
+ if ((this._hasValue || this.invalid) && hasConstraints) {
89
93
  this.validate();
90
- } else {
91
- this.invalid = false;
94
+ } else if (isLastConstraintRemoved) {
95
+ this._setInvalid(false);
92
96
  }
97
+
98
+ this.__previousHasConstraints = hasConstraints;
93
99
  }
94
100
 
95
101
  /**
@@ -3,26 +3,25 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
9
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
- import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
- import { DelegateFocusMixinClass } from './delegate-focus-mixin.js';
12
- import { DelegateStateMixinClass } from './delegate-state-mixin.js';
13
- import { FieldMixinClass } from './field-mixin.js';
14
- import { InputConstraintsMixinClass } from './input-constraints-mixin.js';
15
- import { InputMixinClass } from './input-mixin.js';
16
- import { LabelMixinClass } from './label-mixin.js';
17
- import { ValidateMixinClass } from './validate-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
9
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
+ import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
+ import type { DelegateFocusMixinClass } from './delegate-focus-mixin.js';
12
+ import type { DelegateStateMixinClass } from './delegate-state-mixin.js';
13
+ import type { FieldMixinClass } from './field-mixin.js';
14
+ import type { InputConstraintsMixinClass } from './input-constraints-mixin.js';
15
+ import type { InputMixinClass } from './input-mixin.js';
16
+ import type { LabelMixinClass } from './label-mixin.js';
17
+ import type { ValidateMixinClass } from './validate-mixin.js';
18
18
 
19
19
  /**
20
20
  * A mixin to provide shared logic for the editable form input controls.
21
21
  */
22
22
  export declare function InputControlMixin<T extends Constructor<HTMLElement>>(
23
23
  base: T,
24
- ): T &
25
- Constructor<ControllerMixinClass> &
24
+ ): Constructor<ControllerMixinClass> &
26
25
  Constructor<DelegateFocusMixinClass> &
27
26
  Constructor<DelegateStateMixinClass> &
28
27
  Constructor<DisabledMixinClass> &
@@ -33,7 +32,8 @@ export declare function InputControlMixin<T extends Constructor<HTMLElement>>(
33
32
  Constructor<InputMixinClass> &
34
33
  Constructor<KeyboardMixinClass> &
35
34
  Constructor<LabelMixinClass> &
36
- Constructor<ValidateMixinClass>;
35
+ Constructor<ValidateMixinClass> &
36
+ T;
37
37
 
38
38
  export declare class InputControlMixinClass {
39
39
  /**
@@ -29,6 +29,7 @@ export class InputController extends SlotController {
29
29
  callback(node);
30
30
  }
31
31
  },
32
+ true,
32
33
  );
33
34
  }
34
35
  }
@@ -3,27 +3,26 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
9
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
- import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
- import { DelegateFocusMixinClass } from './delegate-focus-mixin.js';
12
- import { DelegateStateMixinClass } from './delegate-state-mixin.js';
13
- import { FieldMixinClass } from './field-mixin.js';
14
- import { InputConstraintsMixinClass } from './input-constraints-mixin.js';
15
- import { InputControlMixinClass } from './input-control-mixin.js';
16
- import { InputMixinClass } from './input-mixin.js';
17
- import { LabelMixinClass } from './label-mixin.js';
18
- import { ValidateMixinClass } from './validate-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
9
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
+ import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
+ import type { DelegateFocusMixinClass } from './delegate-focus-mixin.js';
12
+ import type { DelegateStateMixinClass } from './delegate-state-mixin.js';
13
+ import type { FieldMixinClass } from './field-mixin.js';
14
+ import type { InputConstraintsMixinClass } from './input-constraints-mixin.js';
15
+ import type { InputControlMixinClass } from './input-control-mixin.js';
16
+ import type { InputMixinClass } from './input-mixin.js';
17
+ import type { LabelMixinClass } from './label-mixin.js';
18
+ import type { ValidateMixinClass } from './validate-mixin.js';
19
19
 
20
20
  /**
21
21
  * A mixin to provide logic for vaadin-text-field and related components.
22
22
  */
23
23
  export declare function InputFieldMixin<T extends Constructor<HTMLElement>>(
24
24
  base: T,
25
- ): T &
26
- Constructor<ControllerMixinClass> &
25
+ ): Constructor<ControllerMixinClass> &
27
26
  Constructor<DelegateFocusMixinClass> &
28
27
  Constructor<DelegateStateMixinClass> &
29
28
  Constructor<DisabledMixinClass> &
@@ -35,7 +34,8 @@ export declare function InputFieldMixin<T extends Constructor<HTMLElement>>(
35
34
  Constructor<InputMixinClass> &
36
35
  Constructor<KeyboardMixinClass> &
37
36
  Constructor<LabelMixinClass> &
38
- Constructor<ValidateMixinClass>;
37
+ Constructor<ValidateMixinClass> &
38
+ T;
39
39
 
40
40
  export declare class InputFieldMixinClass {
41
41
  /**
@@ -52,7 +52,7 @@ export declare class InputFieldMixinClass {
52
52
  * on: Enable autocorrection.
53
53
  * off: Disable autocorrection.
54
54
  */
55
- autocorrect: 'on' | 'off' | undefined;
55
+ autocorrect: 'off' | 'on' | undefined;
56
56
 
57
57
  /**
58
58
  * This is a property supported by Safari and Chrome that is used to control whether
@@ -63,5 +63,5 @@ export declare class InputFieldMixinClass {
63
63
  * sentences: Sentences capitalization.
64
64
  * none: No capitalization.
65
65
  */
66
- autocapitalize: 'on' | 'off' | 'none' | 'characters' | 'words' | 'sentences' | undefined;
66
+ autocapitalize: 'characters' | 'none' | 'off' | 'on' | 'sentences' | 'words' | undefined;
67
67
  }
@@ -85,15 +85,17 @@ export const InputFieldMixin = (superclass) =>
85
85
  }
86
86
 
87
87
  /**
88
- * Override an event listener from `DelegateFocusMixin`.
89
- * @param {FocusEvent} event
88
+ * Override an event listener from `FocusMixin`.
89
+ * @param {boolean} focused
90
90
  * @protected
91
91
  * @override
92
92
  */
93
- _onBlur(event) {
94
- super._onBlur(event);
93
+ _setFocused(focused) {
94
+ super._setFocused(focused);
95
95
 
96
- this.validate();
96
+ if (!focused) {
97
+ this.validate();
98
+ }
97
99
  }
98
100
 
99
101
  /**
@@ -112,14 +114,20 @@ export const InputFieldMixin = (superclass) =>
112
114
  }
113
115
 
114
116
  /**
115
- * Override a method from `InputMixin` to validate the field
117
+ * Override an observer from `InputMixin` to validate the field
116
118
  * when a new value is set programmatically.
117
- * @param {string} value
119
+ *
120
+ * @param {string | undefined} newValue
121
+ * @param {string | undefined} oldValue
118
122
  * @protected
119
123
  * @override
120
124
  */
121
- _forwardInputValue(value) {
122
- super._forwardInputValue(value);
125
+ _valueChanged(newValue, oldValue) {
126
+ super._valueChanged(newValue, oldValue);
127
+
128
+ if (oldValue === undefined) {
129
+ return;
130
+ }
123
131
 
124
132
  if (this.invalid) {
125
133
  this.validate();
@@ -3,13 +3,13 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
 
8
8
  /**
9
9
  * A mixin to store the reference to an input element
10
10
  * and add input and change event listeners to it.
11
11
  */
12
- export declare function InputMixin<T extends Constructor<HTMLElement>>(base: T): T & Constructor<InputMixinClass>;
12
+ export declare function InputMixin<T extends Constructor<HTMLElement>>(base: T): Constructor<InputMixinClass> & T;
13
13
 
14
14
  export declare class InputMixinClass {
15
15
  /**
@@ -28,6 +28,12 @@ export declare class InputMixinClass {
28
28
  */
29
29
  value: string;
30
30
 
31
+ /**
32
+ * Indicates whether the value is different from the default one.
33
+ * Override if the `value` property has a type other than `string`.
34
+ */
35
+ protected readonly _hasValue: boolean;
36
+
31
37
  /**
32
38
  * Clear the value of the field.
33
39
  */
@@ -47,7 +53,7 @@ export declare class InputMixinClass {
47
53
 
48
54
  protected _setInputElement(input: HTMLElement): void;
49
55
 
50
- protected _toggleHasValue(value: boolean): void;
56
+ protected _toggleHasValue(hasValue: boolean): void;
51
57
 
52
58
  protected _valueChanged(value?: string, oldValue?: string): void;
53
59
  }
@@ -52,13 +52,23 @@ export const InputMixin = dedupingMixin(
52
52
  observer: '_valueChanged',
53
53
  notify: true,
54
54
  },
55
+
56
+ /**
57
+ * When true, the input element has a non-empty value entered by the user.
58
+ * @protected
59
+ */
60
+ _hasInputValue: {
61
+ type: Boolean,
62
+ value: false,
63
+ observer: '_hasInputValueChanged',
64
+ },
55
65
  };
56
66
  }
57
67
 
58
68
  constructor() {
59
69
  super();
60
70
 
61
- this._boundOnInput = this._onInput.bind(this);
71
+ this._boundOnInput = this.__onInput.bind(this);
62
72
  this._boundOnChange = this._onChange.bind(this);
63
73
  }
64
74
 
@@ -73,6 +83,7 @@ export const InputMixin = dedupingMixin(
73
83
  * Add event listeners to the input element instance.
74
84
  * Override this method to add custom listeners.
75
85
  * @param {!HTMLElement} input
86
+ * @protected
76
87
  */
77
88
  _addInputListeners(input) {
78
89
  input.addEventListener('input', this._boundOnInput);
@@ -82,6 +93,7 @@ export const InputMixin = dedupingMixin(
82
93
  /**
83
94
  * Remove event listeners from the input element instance.
84
95
  * @param {!HTMLElement} input
96
+ * @protected
85
97
  */
86
98
  _removeInputListeners(input) {
87
99
  input.removeEventListener('input', this._boundOnInput);
@@ -95,7 +107,6 @@ export const InputMixin = dedupingMixin(
95
107
  * for example to skip this in certain conditions.
96
108
  * @param {string} value
97
109
  * @protected
98
- * @override
99
110
  */
100
111
  _forwardInputValue(value) {
101
112
  // Value might be set before an input element is initialized.
@@ -112,7 +123,11 @@ export const InputMixin = dedupingMixin(
112
123
  }
113
124
  }
114
125
 
115
- /** @protected */
126
+ /**
127
+ * @param {HTMLElement | undefined} input
128
+ * @param {HTMLElement | undefined} oldInput
129
+ * @protected
130
+ */
116
131
  _inputElementChanged(input, oldInput) {
117
132
  if (input) {
118
133
  this._addInputListeners(input);
@@ -121,17 +136,47 @@ export const InputMixin = dedupingMixin(
121
136
  }
122
137
  }
123
138
 
139
+ /**
140
+ * Observer to notify about the change of private property.
141
+ *
142
+ * @private
143
+ */
144
+ _hasInputValueChanged(hasValue, oldHasValue) {
145
+ if (hasValue || oldHasValue) {
146
+ this.dispatchEvent(new CustomEvent('has-input-value-changed'));
147
+ }
148
+ }
149
+
150
+ /**
151
+ * An input event listener used to update `_hasInputValue` property.
152
+ * Do not override this method.
153
+ *
154
+ * @param {Event} event
155
+ * @private
156
+ */
157
+ __onInput(event) {
158
+ // In the case a custom web component is passed as `inputElement`,
159
+ // the actual native input element, on which the event occurred,
160
+ // can be inside shadow trees.
161
+ const target = event.composedPath()[0];
162
+ this._hasInputValue = target.value.length > 0;
163
+ this._onInput(event);
164
+ }
165
+
124
166
  /**
125
167
  * An input event listener used to update the field value.
126
- * Override this method with an actual implementation.
127
- * @param {Event} _event
168
+ *
169
+ * @param {Event} event
128
170
  * @protected
129
- * @override
130
171
  */
131
172
  _onInput(event) {
173
+ // In the case a custom web component is passed as `inputElement`,
174
+ // the actual native input element, on which the event occurred,
175
+ // can be inside shadow trees.
176
+ const target = event.composedPath()[0];
132
177
  // Ignore fake input events e.g. used by clear button.
133
178
  this.__userInput = event.isTrusted;
134
- this.value = event.target.value;
179
+ this.value = target.value;
135
180
  this.__userInput = false;
136
181
  }
137
182
 
@@ -140,12 +185,12 @@ export const InputMixin = dedupingMixin(
140
185
  * Override this method with an actual implementation.
141
186
  * @param {Event} _event
142
187
  * @protected
143
- * @override
144
188
  */
145
189
  _onChange(_event) {}
146
190
 
147
191
  /**
148
192
  * Toggle the has-value attribute based on the value property.
193
+ *
149
194
  * @param {boolean} hasValue
150
195
  * @protected
151
196
  */
@@ -158,10 +203,9 @@ export const InputMixin = dedupingMixin(
158
203
  * @param {string | undefined} newVal
159
204
  * @param {string | undefined} oldVal
160
205
  * @protected
161
- * @override
162
206
  */
163
207
  _valueChanged(newVal, oldVal) {
164
- this._toggleHasValue(newVal !== '' && newVal != null);
208
+ this._toggleHasValue(this._hasValue);
165
209
 
166
210
  // Setting initial value to empty string, do nothing.
167
211
  if (newVal === '' && oldVal === undefined) {
@@ -176,5 +220,15 @@ export const InputMixin = dedupingMixin(
176
220
  // Setting a value programmatically, sync it to input element.
177
221
  this._forwardInputValue(newVal);
178
222
  }
223
+
224
+ /**
225
+ * Indicates whether the value is different from the default one.
226
+ * Override if the `value` property has a type other than `string`.
227
+ *
228
+ * @protected
229
+ */
230
+ get _hasValue() {
231
+ return this.value != null && this.value !== '';
232
+ }
179
233
  },
180
234
  );
@@ -23,6 +23,7 @@ export class LabelController extends SlotController {
23
23
 
24
24
  this.__observeLabel(node);
25
25
  },
26
+ true,
26
27
  );
27
28
  }
28
29
 
@@ -3,13 +3,13 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { LabelController } from './label-controller.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { LabelController } from './label-controller.js';
8
8
 
9
9
  /**
10
10
  * A mixin to provide label via corresponding property or named slot.
11
11
  */
12
- export declare function LabelMixin<T extends Constructor<HTMLElement>>(base: T): T & Constructor<LabelMixinClass>;
12
+ export declare function LabelMixin<T extends Constructor<HTMLElement>>(base: T): Constructor<LabelMixinClass> & T;
13
13
 
14
14
  export declare class LabelMixinClass {
15
15
  /**
@@ -3,7 +3,7 @@
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 { ReactiveController } from 'lit';
6
+ import type { ReactiveController } from 'lit';
7
7
 
8
8
  /**
9
9
  * A controller for linking a `<label>` element with an `<input>` element.
@@ -3,25 +3,25 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { DelegateStateMixinClass } from './delegate-state-mixin.js';
9
- import { InputConstraintsMixinClass } from './input-constraints-mixin.js';
10
- import { InputMixinClass } from './input-mixin.js';
11
- import { ValidateMixinClass } from './validate-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { DelegateStateMixinClass } from './delegate-state-mixin.js';
9
+ import type { InputConstraintsMixinClass } from './input-constraints-mixin.js';
10
+ import type { InputMixinClass } from './input-mixin.js';
11
+ import type { ValidateMixinClass } from './validate-mixin.js';
12
12
 
13
13
  /**
14
14
  * A mixin to provide `pattern` and `preventInvalidInput` properties.
15
15
  */
16
16
  export declare function PatternMixin<T extends Constructor<HTMLElement>>(
17
17
  base: T,
18
- ): T &
19
- Constructor<DelegateStateMixinClass> &
18
+ ): Constructor<DelegateStateMixinClass> &
20
19
  Constructor<DisabledMixinClass> &
21
20
  Constructor<InputConstraintsMixinClass> &
22
21
  Constructor<InputMixinClass> &
23
22
  Constructor<PatternMixinClass> &
24
- Constructor<ValidateMixinClass>;
23
+ Constructor<ValidateMixinClass> &
24
+ T;
25
25
 
26
26
  export declare class PatternMixinClass {
27
27
  /**
@@ -64,6 +64,7 @@ export const PatternMixin = (superclass) =>
64
64
  /**
65
65
  * @param {Event} event
66
66
  * @protected
67
+ * @override
67
68
  */
68
69
  _onInput(event) {
69
70
  this._checkInputValue();
@@ -3,21 +3,21 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
9
- import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
10
- import { TabindexMixinClass } from '@vaadin/component-base/src/tabindex-mixin.js';
11
- import { DelegateFocusMixinClass } from './delegate-focus-mixin.js';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
9
+ import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
10
+ import type { TabindexMixinClass } from '@vaadin/component-base/src/tabindex-mixin.js';
11
+ import type { DelegateFocusMixinClass } from './delegate-focus-mixin.js';
12
12
 
13
13
  /**
14
14
  * A mixin to forward focus to an element in the shadow DOM.
15
15
  */
16
16
  export declare function ShadowFocusMixin<T extends Constructor<HTMLElement>>(
17
17
  base: T,
18
- ): T &
19
- Constructor<DelegateFocusMixinClass> &
18
+ ): Constructor<DelegateFocusMixinClass> &
20
19
  Constructor<DisabledMixinClass> &
21
20
  Constructor<FocusMixinClass> &
22
21
  Constructor<KeyboardMixinClass> &
23
- Constructor<TabindexMixinClass>;
22
+ Constructor<TabindexMixinClass> &
23
+ T;
@@ -3,7 +3,7 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
 
8
8
  /**
9
9
  * Mixin to insert styles into the outer scope to handle slotted components.
@@ -11,7 +11,7 @@ import { Constructor } from '@open-wc/dedupe-mixin';
11
11
  */
12
12
  export declare function SlotStylesMixin<T extends Constructor<HTMLElement>>(
13
13
  base: T,
14
- ): T & Constructor<SlotStylesMixinClass>;
14
+ ): Constructor<SlotStylesMixinClass> & T;
15
15
 
16
16
  export declare class SlotStylesMixinClass {
17
17
  /**
@@ -3,7 +3,7 @@
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 { ReactiveController } from 'lit';
6
+ import type { ReactiveController } from 'lit';
7
7
 
8
8
  export class SlotTargetController implements ReactiveController {
9
9
  /**
@@ -3,6 +3,6 @@
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 { CSSResult } from 'lit';
6
+ import type { CSSResult } from 'lit';
7
7
 
8
8
  export const clearButton: CSSResult;
@@ -3,6 +3,6 @@
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 { CSSResult } from 'lit';
6
+ import type { CSSResult } from 'lit';
7
7
 
8
8
  export const fieldShared: CSSResult;
@@ -3,6 +3,6 @@
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 { CSSResult } from 'lit';
6
+ import type { CSSResult } from 'lit';
7
7
 
8
8
  export const inputFieldContainer: CSSResult;
@@ -3,6 +3,6 @@
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 { CSSResult } from 'lit';
6
+ import type { CSSResult } from 'lit';
7
7
 
8
8
  export const inputFieldShared: CSSResult;
@@ -31,6 +31,7 @@ export class TextAreaController extends SlotController {
31
31
  callback(node);
32
32
  }
33
33
  },
34
+ true,
34
35
  );
35
36
  }
36
37
  }
@@ -3,12 +3,12 @@
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 { Constructor } from '@open-wc/dedupe-mixin';
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
 
8
8
  /**
9
9
  * A mixin to provide required state and validation logic.
10
10
  */
11
- export declare function ValidateMixin<T extends Constructor<HTMLElement>>(base: T): T & Constructor<ValidateMixinClass>;
11
+ export declare function ValidateMixin<T extends Constructor<HTMLElement>>(base: T): Constructor<ValidateMixinClass> & T;
12
12
 
13
13
  export declare class ValidateMixinClass {
14
14
  /**
@@ -30,4 +30,12 @@ export declare class ValidateMixinClass {
30
30
  * Returns true if the field value satisfies all constraints (if any).
31
31
  */
32
32
  checkValidity(): boolean;
33
+
34
+ /**
35
+ * Fired whenever the field is validated.
36
+ *
37
+ * @event validated
38
+ * @param {Object} detail
39
+ * @param {boolean} detail.valid the result of the validation.
40
+ */
33
41
  }
@@ -36,12 +36,17 @@ export const ValidateMixin = dedupingMixin(
36
36
  }
37
37
 
38
38
  /**
39
- * Returns true if field is valid, and sets `invalid` based on the field validity.
39
+ * Validates the field and sets the `invalid` property based on the result.
40
+ *
41
+ * The method fires a `validated` event with the result of the validation.
40
42
  *
41
43
  * @return {boolean} True if the value is valid.
42
44
  */
43
45
  validate() {
44
- return !(this.invalid = !this.checkValidity());
46
+ const isValid = this.checkValidity();
47
+ this._setInvalid(!isValid);
48
+ this.dispatchEvent(new CustomEvent('validated', { detail: { valid: isValid } }));
49
+ return isValid;
45
50
  }
46
51
 
47
52
  /**
@@ -52,5 +57,34 @@ export const ValidateMixin = dedupingMixin(
52
57
  checkValidity() {
53
58
  return !this.required || !!this.value;
54
59
  }
60
+
61
+ /**
62
+ * @param {boolean} invalid
63
+ * @protected
64
+ */
65
+ _setInvalid(invalid) {
66
+ if (this._shouldSetInvalid(invalid)) {
67
+ this.invalid = invalid;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Override this method to define whether the given `invalid` state should be set.
73
+ *
74
+ * @param {boolean} _invalid
75
+ * @return {boolean}
76
+ * @protected
77
+ */
78
+ _shouldSetInvalid(_invalid) {
79
+ return true;
80
+ }
81
+
82
+ /**
83
+ * Fired whenever the field is validated.
84
+ *
85
+ * @event validated
86
+ * @param {Object} detail
87
+ * @param {boolean} detail.valid the result of the validation.
88
+ */
55
89
  },
56
90
  );
@@ -3,12 +3,12 @@
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 { ReactiveController } from 'lit';
6
+ import type { ReactiveController } from 'lit';
7
7
 
8
8
  /**
9
9
  * A controller which prevents the virtual keyboard from showing up on mobile devices
10
10
  * when the field's overlay is closed.
11
11
  */
12
12
  export class VirtualKeyboardController implements ReactiveController {
13
- constructor(host: { inputElement?: HTMLElement; opened: boolean } & HTMLElement);
13
+ constructor(host: HTMLElement & { inputElement?: HTMLElement; opened: boolean });
14
14
  }
package/src/utils.d.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
- */
6
-
7
- /**
8
- * Adds a value to an attribute containing space-delimited values.
9
- */
10
- export declare function addValueToAttribute(element: HTMLElement, attr: string, value: string): void;
11
-
12
- /**
13
- * Removes a value from an attribute containing space-delimited values.
14
- * If the value is the last one, the whole attribute is removed.
15
- */
16
- export declare function removeValueFromAttribute(element: HTMLElement, attr: string, value: string): void;
package/src/utils.js DELETED
@@ -1,56 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
- */
6
-
7
- /**
8
- * @param {string} value
9
- * @return {Set<string>}
10
- */
11
- function deserializeAttributeValue(value) {
12
- if (!value) {
13
- return new Set();
14
- }
15
-
16
- return new Set(value.split(' '));
17
- }
18
-
19
- /**
20
- * @param {Set<string>} values
21
- * @return {string}
22
- */
23
- function serializeAttributeValue(values) {
24
- return [...values].join(' ');
25
- }
26
-
27
- /**
28
- * Adds a value to an attribute containing space-delimited values.
29
- *
30
- * @param {HTMLElement} element
31
- * @param {string} attr
32
- * @param {string} value
33
- */
34
- export function addValueToAttribute(element, attr, value) {
35
- const values = deserializeAttributeValue(element.getAttribute(attr));
36
- values.add(value);
37
- element.setAttribute(attr, serializeAttributeValue(values));
38
- }
39
-
40
- /**
41
- * Removes a value from an attribute containing space-delimited values.
42
- * If the value is the last one, the whole attribute is removed.
43
- *
44
- * @param {HTMLElement} element
45
- * @param {string} attr
46
- * @param {string} value
47
- */
48
- export function removeValueFromAttribute(element, attr, value) {
49
- const values = deserializeAttributeValue(element.getAttribute(attr));
50
- values.delete(value);
51
- if (values.size === 0) {
52
- element.removeAttribute(attr);
53
- return;
54
- }
55
- element.setAttribute(attr, serializeAttributeValue(values));
56
- }