@material/web 1.0.2-nightly.f7a66a8.0 → 1.1.1
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/checkbox/internal/checkbox.d.ts +1 -0
- package/checkbox/internal/checkbox.js +6 -1
- package/checkbox/internal/checkbox.js.map +1 -1
- package/chips/internal/_shared.scss +16 -3
- package/chips/internal/_trailing-icon.scss +2 -1
- package/chips/internal/assist-styles.css.js +1 -1
- package/chips/internal/assist-styles.css.js.map +1 -1
- package/chips/internal/chip-set.js +2 -6
- package/chips/internal/chip-set.js.map +1 -1
- package/chips/internal/chip.d.ts +8 -0
- package/chips/internal/chip.js +17 -2
- package/chips/internal/chip.js.map +1 -1
- package/chips/internal/filter-chip.d.ts +8 -0
- package/chips/internal/filter-chip.js +17 -4
- package/chips/internal/filter-chip.js.map +1 -1
- package/chips/internal/filter-styles.css.js +1 -1
- package/chips/internal/filter-styles.css.js.map +1 -1
- package/chips/internal/input-styles.css.js +1 -1
- package/chips/internal/input-styles.css.js.map +1 -1
- package/chips/internal/shared-styles.css.js +1 -1
- package/chips/internal/shared-styles.css.js.map +1 -1
- package/chips/internal/suggestion-styles.css.js +1 -1
- package/chips/internal/suggestion-styles.css.js.map +1 -1
- package/chips/internal/trailing-icon-styles.css.js +1 -1
- package/chips/internal/trailing-icon-styles.css.js.map +1 -1
- package/chips/internal/trailing-icons.js +8 -4
- package/chips/internal/trailing-icons.js.map +1 -1
- package/fab/internal/_shared.scss +1 -0
- package/fab/internal/shared-styles.css.js +1 -1
- package/fab/internal/shared-styles.css.js.map +1 -1
- package/field/internal/_content.scss +3 -1
- package/field/internal/shared-styles.css.js +1 -1
- package/field/internal/shared-styles.css.js.map +1 -1
- package/internal/aria/aria.d.ts +0 -29
- package/internal/aria/aria.js +0 -141
- package/internal/aria/aria.js.map +1 -1
- package/internal/controller/form-submitter.js +2 -2
- package/internal/controller/form-submitter.js.map +1 -1
- package/labs/behaviors/constraint-validation.d.ts +2 -2
- package/labs/behaviors/constraint-validation.js +18 -1
- package/labs/behaviors/constraint-validation.js.map +1 -1
- package/labs/behaviors/element-internals.js +1 -5
- package/labs/behaviors/element-internals.js.map +1 -1
- package/labs/behaviors/focusable.js +20 -7
- package/labs/behaviors/focusable.js.map +1 -1
- package/labs/behaviors/form-associated.js +31 -11
- package/labs/behaviors/form-associated.js.map +1 -1
- package/labs/behaviors/on-report-validity.d.ts +70 -0
- package/labs/behaviors/on-report-validity.js +185 -0
- package/labs/behaviors/on-report-validity.js.map +1 -0
- package/labs/behaviors/validators/checkbox-validator.d.ts +6 -3
- package/labs/behaviors/validators/checkbox-validator.js.map +1 -1
- package/labs/behaviors/validators/radio-validator.d.ts +38 -0
- package/labs/behaviors/validators/radio-validator.js +65 -0
- package/labs/behaviors/validators/radio-validator.js.map +1 -0
- package/labs/behaviors/validators/select-validator.d.ts +35 -0
- package/labs/behaviors/validators/select-validator.js +33 -0
- package/labs/behaviors/validators/select-validator.js.map +1 -0
- package/labs/behaviors/validators/text-field-validator.d.ts +110 -0
- package/labs/behaviors/validators/text-field-validator.js +146 -0
- package/labs/behaviors/validators/text-field-validator.js.map +1 -0
- package/labs/behaviors/validators/validator.d.ts +4 -0
- package/labs/behaviors/validators/validator.js.map +1 -1
- package/labs/card/internal/_outlined-card.scss +1 -1
- package/labs/card/internal/_shared.scss +10 -2
- package/labs/card/internal/outlined-styles.css.js +1 -1
- package/labs/card/internal/outlined-styles.css.js.map +1 -1
- package/labs/card/internal/shared-styles.css.js +1 -1
- package/labs/card/internal/shared-styles.css.js.map +1 -1
- package/labs/segmentedbutton/internal/_shared.scss +1 -0
- package/labs/segmentedbutton/internal/shared-styles.css.js +1 -1
- package/labs/segmentedbutton/internal/shared-styles.css.js.map +1 -1
- package/list/internal/list.js +2 -6
- package/list/internal/list.js.map +1 -1
- package/list/internal/listitem/_list-item.scss +2 -0
- package/list/internal/listitem/list-item-styles.css.js +1 -1
- package/list/internal/listitem/list-item-styles.css.js.map +1 -1
- package/menu/internal/controllers/menuItemController.d.ts +13 -1
- package/menu/internal/controllers/menuItemController.js +32 -6
- package/menu/internal/controllers/menuItemController.js.map +1 -1
- package/menu/internal/menu.js +7 -8
- package/menu/internal/menu.js.map +1 -1
- package/menu/internal/menuitem/menu-item.d.ts +2 -0
- package/menu/internal/menuitem/menu-item.js +13 -1
- package/menu/internal/menuitem/menu-item.js.map +1 -1
- package/package.json +1 -1
- package/radio/internal/radio.d.ts +11 -1
- package/radio/internal/radio.js +28 -2
- package/radio/internal/radio.js.map +1 -1
- package/radio/internal/single-selection-controller.d.ts +5 -5
- package/radio/internal/single-selection-controller.js +16 -14
- package/radio/internal/single-selection-controller.js.map +1 -1
- package/select/internal/_shared.scss +5 -0
- package/select/internal/select.d.ts +21 -72
- package/select/internal/select.js +106 -184
- package/select/internal/select.js.map +1 -1
- package/select/internal/selectoption/select-option.d.ts +2 -0
- package/select/internal/selectoption/select-option.js +13 -1
- package/select/internal/selectoption/select-option.js.map +1 -1
- package/select/internal/selectoption/selectOptionController.d.ts +7 -3
- package/select/internal/selectoption/selectOptionController.js +8 -11
- package/select/internal/selectoption/selectOptionController.js.map +1 -1
- package/select/internal/shared-styles.css.js +1 -1
- package/select/internal/shared-styles.css.js.map +1 -1
- package/switch/internal/_icon.scss +14 -10
- package/switch/internal/switch-styles.css.js +1 -1
- package/switch/internal/switch-styles.css.js.map +1 -1
- package/switch/internal/switch.js +12 -8
- package/switch/internal/switch.js.map +1 -1
- package/tabs/internal/tab.js +2 -6
- package/tabs/internal/tab.js.map +1 -1
- package/tabs/internal/tabs.js +2 -6
- package/tabs/internal/tabs.js.map +1 -1
- package/textfield/internal/text-field.d.ts +9 -74
- package/textfield/internal/text-field.js +34 -150
- package/textfield/internal/text-field.js.map +1 -1
- package/tokens/_md-comp-assist-chip.scss +11 -0
- package/tokens/_md-comp-filter-chip.scss +14 -0
- package/tokens/_md-comp-input-chip.scss +14 -0
- package/tokens/_md-comp-suggestion-chip.scss +11 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { isServer } from 'lit';
|
|
7
|
+
/**
|
|
8
|
+
* A symbol property used for a callback when validity has been reported.
|
|
9
|
+
*/
|
|
10
|
+
export const onReportValidity = Symbol('onReportValidity');
|
|
11
|
+
// Private symbol members, used to avoid name clashing.
|
|
12
|
+
const privateCleanupFormListeners = Symbol('privateCleanupFormListeners');
|
|
13
|
+
const privateDoNotReportInvalid = Symbol('privateDoNotReportInvalid');
|
|
14
|
+
/**
|
|
15
|
+
* Mixes in a callback for constraint validation when validity should be
|
|
16
|
+
* styled and reported to the user.
|
|
17
|
+
*
|
|
18
|
+
* This is commonly used in text-field-like controls that display error styles
|
|
19
|
+
* and error messages.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const baseClass = mixinOnReportValidity(
|
|
24
|
+
* mixinConstraintValidation(
|
|
25
|
+
* mixinFormAssociated(mixinElementInternals(LitElement)),
|
|
26
|
+
* ),
|
|
27
|
+
* );
|
|
28
|
+
*
|
|
29
|
+
* class MyField extends baseClass {
|
|
30
|
+
* \@property({type: Boolean}) error = false;
|
|
31
|
+
* \@property() errorMessage = '';
|
|
32
|
+
*
|
|
33
|
+
* [onReportValidity](invalidEvent: Event | null) {
|
|
34
|
+
* this.error = !!invalidEvent;
|
|
35
|
+
* this.errorMessage = this.validationMessage;
|
|
36
|
+
*
|
|
37
|
+
* // Optionally prevent platform popup from displaying
|
|
38
|
+
* invalidEvent?.preventDefault();
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @param base The class to mix functionality into.
|
|
44
|
+
* @return The provided class with `OnReportValidity` mixed in.
|
|
45
|
+
*/
|
|
46
|
+
export function mixinOnReportValidity(base) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
class OnReportValidityElement extends base {
|
|
49
|
+
// Mixins must have a constructor with `...args: any[]`
|
|
50
|
+
// tslint:disable-next-line:no-any
|
|
51
|
+
constructor(...args) {
|
|
52
|
+
super(...args);
|
|
53
|
+
/**
|
|
54
|
+
* Used to clean up event listeners when a new form is associated.
|
|
55
|
+
*/
|
|
56
|
+
this[_a] = new AbortController();
|
|
57
|
+
/**
|
|
58
|
+
* Used to determine if an invalid event should report validity. Invalid
|
|
59
|
+
* events from `checkValidity()` do not trigger reporting.
|
|
60
|
+
*/
|
|
61
|
+
this[_b] = false;
|
|
62
|
+
if (isServer) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.addEventListener('invalid', (invalidEvent) => {
|
|
66
|
+
// Listen for invalid events dispatched by a `<form>` when it tries to
|
|
67
|
+
// submit and the element is invalid. We ignore events dispatched when
|
|
68
|
+
// calling `checkValidity()` as well as untrusted events, since the
|
|
69
|
+
// `reportValidity()` and `<form>`-dispatched events are always
|
|
70
|
+
// trusted.
|
|
71
|
+
if (this[privateDoNotReportInvalid] || !invalidEvent.isTrusted) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.addEventListener('invalid', () => {
|
|
75
|
+
// A normal bubbling phase event listener. By adding it here, we
|
|
76
|
+
// ensure it's the last event listener that is called during the
|
|
77
|
+
// bubbling phase.
|
|
78
|
+
if (!invalidEvent.defaultPrevented) {
|
|
79
|
+
this[onReportValidity](invalidEvent);
|
|
80
|
+
}
|
|
81
|
+
}, { once: true });
|
|
82
|
+
}, {
|
|
83
|
+
// Listen during the capture phase, which will happen before the
|
|
84
|
+
// bubbling phase. That way, we can add a final event listener that
|
|
85
|
+
// will run after other event listeners, and we can check if it was
|
|
86
|
+
// default prevented. This works because invalid does not bubble.
|
|
87
|
+
capture: true,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
checkValidity() {
|
|
91
|
+
this[privateDoNotReportInvalid] = true;
|
|
92
|
+
const valid = super.checkValidity();
|
|
93
|
+
this[privateDoNotReportInvalid] = false;
|
|
94
|
+
return valid;
|
|
95
|
+
}
|
|
96
|
+
reportValidity() {
|
|
97
|
+
const valid = super.reportValidity();
|
|
98
|
+
// Constructor's invalid listener will handle reporting invalid events.
|
|
99
|
+
if (valid) {
|
|
100
|
+
this[onReportValidity](null);
|
|
101
|
+
}
|
|
102
|
+
return valid;
|
|
103
|
+
}
|
|
104
|
+
[(_a = privateCleanupFormListeners, _b = privateDoNotReportInvalid, onReportValidity)](invalidEvent) {
|
|
105
|
+
throw new Error('Implement [onReportValidity]');
|
|
106
|
+
}
|
|
107
|
+
formAssociatedCallback(form) {
|
|
108
|
+
// can't use super.formAssociatedCallback?.() due to closure
|
|
109
|
+
if (super.formAssociatedCallback) {
|
|
110
|
+
super.formAssociatedCallback(form);
|
|
111
|
+
}
|
|
112
|
+
// Clean up previous submit listener
|
|
113
|
+
this[privateCleanupFormListeners].abort();
|
|
114
|
+
if (!form) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
this[privateCleanupFormListeners] = new AbortController();
|
|
118
|
+
// If the element's form submits, then all controls are valid. This lets
|
|
119
|
+
// the element remove its error styles that may have been set when
|
|
120
|
+
// `reportValidity()` was called.
|
|
121
|
+
form.addEventListener('submit', () => {
|
|
122
|
+
this[onReportValidity](null);
|
|
123
|
+
}, {
|
|
124
|
+
signal: this[privateCleanupFormListeners].signal,
|
|
125
|
+
});
|
|
126
|
+
// Inject a callback when `form.reportValidity()` is called and the form
|
|
127
|
+
// is valid. There isn't an event that is dispatched to alert us (unlike
|
|
128
|
+
// the 'invalid' event), and we need to remove error styles when
|
|
129
|
+
// `form.reportValidity()` is called and returns true.
|
|
130
|
+
let reportedInvalidEventFromForm = false;
|
|
131
|
+
let formReportValidityCleanup = new AbortController();
|
|
132
|
+
injectFormReportValidityHooks({
|
|
133
|
+
form,
|
|
134
|
+
cleanup: this[privateCleanupFormListeners].signal,
|
|
135
|
+
beforeReportValidity: () => {
|
|
136
|
+
reportedInvalidEventFromForm = false;
|
|
137
|
+
this.addEventListener('invalid', (invalidEvent) => {
|
|
138
|
+
reportedInvalidEventFromForm = true;
|
|
139
|
+
if (!invalidEvent.defaultPrevented) {
|
|
140
|
+
this[onReportValidity](invalidEvent);
|
|
141
|
+
}
|
|
142
|
+
}, { signal: formReportValidityCleanup.signal });
|
|
143
|
+
},
|
|
144
|
+
afterReportValidity: () => {
|
|
145
|
+
formReportValidityCleanup.abort();
|
|
146
|
+
formReportValidityCleanup = new AbortController();
|
|
147
|
+
if (reportedInvalidEventFromForm) {
|
|
148
|
+
reportedInvalidEventFromForm = false;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Report successful form validation if an invalid event wasn't
|
|
152
|
+
// fired.
|
|
153
|
+
this[onReportValidity](null);
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return OnReportValidityElement;
|
|
159
|
+
}
|
|
160
|
+
const FORM_REPORT_VALIDITY_HOOKS = new WeakMap();
|
|
161
|
+
function injectFormReportValidityHooks({ form, beforeReportValidity, afterReportValidity, cleanup, }) {
|
|
162
|
+
if (!FORM_REPORT_VALIDITY_HOOKS.has(form)) {
|
|
163
|
+
// Patch form.reportValidity() to add an event target that can be used to
|
|
164
|
+
// react when the method is called.
|
|
165
|
+
// We should only patch this method once, since multiple controls and other
|
|
166
|
+
// forces may want to patch this method. We cannot reliably clean it up by
|
|
167
|
+
// resetting the method to "superReportValidity", which may be a patched
|
|
168
|
+
// function.
|
|
169
|
+
// Instead, we never clean up the patch but add and clean up event listener
|
|
170
|
+
// hooks once it's patched.
|
|
171
|
+
const hooks = new EventTarget();
|
|
172
|
+
const superReportValidity = form.reportValidity;
|
|
173
|
+
form.reportValidity = function () {
|
|
174
|
+
hooks.dispatchEvent(new Event('before'));
|
|
175
|
+
const valid = superReportValidity.call(this);
|
|
176
|
+
hooks.dispatchEvent(new Event('after'));
|
|
177
|
+
return valid;
|
|
178
|
+
};
|
|
179
|
+
FORM_REPORT_VALIDITY_HOOKS.set(form, hooks);
|
|
180
|
+
}
|
|
181
|
+
const hooks = FORM_REPORT_VALIDITY_HOOKS.get(form);
|
|
182
|
+
hooks.addEventListener('before', beforeReportValidity, { signal: cleanup });
|
|
183
|
+
hooks.addEventListener('after', afterReportValidity, { signal: cleanup });
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=on-report-validity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-report-validity.js","sourceRoot":"","sources":["on-report-validity.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {LitElement, isServer} from 'lit';\n\nimport {ConstraintValidation} from './constraint-validation.js';\nimport {MixinBase, MixinReturn} from './mixin.js';\n\n/**\n * A constraint validation element that has a callback for when the element\n * should report validity styles and error messages to the user.\n *\n * This is commonly used in text-field-like controls that display error styles\n * and error messages.\n */\nexport interface OnReportValidity extends ConstraintValidation {\n /**\n * A callback that is invoked when validity should be reported. Components\n * that can display their own error state can use this and update their\n * styles.\n *\n * If an invalid event is provided, the element is invalid. If `null`, the\n * element is valid.\n *\n * The invalid event's `preventDefault()` may be called to stop the platform\n * popup from displaying.\n *\n * @param invalidEvent The `invalid` event dispatched when an element is\n * invalid, or `null` if the element is valid.\n */\n [onReportValidity](invalidEvent: Event | null): void;\n\n // `mixinOnReportValidity()` implements this optional method. If overriden,\n // call `super.formAssociatedCallback(form)`.\n // (inherit jsdoc from `FormAssociated`)\n formAssociatedCallback(form: HTMLFormElement | null): void;\n}\n\n/**\n * A symbol property used for a callback when validity has been reported.\n */\nexport const onReportValidity = Symbol('onReportValidity');\n\n// Private symbol members, used to avoid name clashing.\nconst privateCleanupFormListeners = Symbol('privateCleanupFormListeners');\nconst privateDoNotReportInvalid = Symbol('privateDoNotReportInvalid');\n\n/**\n * Mixes in a callback for constraint validation when validity should be\n * styled and reported to the user.\n *\n * This is commonly used in text-field-like controls that display error styles\n * and error messages.\n *\n * @example\n * ```ts\n * const baseClass = mixinOnReportValidity(\n * mixinConstraintValidation(\n * mixinFormAssociated(mixinElementInternals(LitElement)),\n * ),\n * );\n *\n * class MyField extends baseClass {\n * \\@property({type: Boolean}) error = false;\n * \\@property() errorMessage = '';\n *\n * [onReportValidity](invalidEvent: Event | null) {\n * this.error = !!invalidEvent;\n * this.errorMessage = this.validationMessage;\n *\n * // Optionally prevent platform popup from displaying\n * invalidEvent?.preventDefault();\n * }\n * }\n * ```\n *\n * @param base The class to mix functionality into.\n * @return The provided class with `OnReportValidity` mixed in.\n */\nexport function mixinOnReportValidity<\n T extends MixinBase<LitElement & ConstraintValidation>,\n>(base: T): MixinReturn<T, OnReportValidity> {\n abstract class OnReportValidityElement\n extends base\n implements OnReportValidity\n {\n /**\n * Used to clean up event listeners when a new form is associated.\n */\n [privateCleanupFormListeners] = new AbortController();\n\n /**\n * Used to determine if an invalid event should report validity. Invalid\n * events from `checkValidity()` do not trigger reporting.\n */\n [privateDoNotReportInvalid] = false;\n\n // Mixins must have a constructor with `...args: any[]`\n // tslint:disable-next-line:no-any\n constructor(...args: any[]) {\n super(...args);\n if (isServer) {\n return;\n }\n\n this.addEventListener(\n 'invalid',\n (invalidEvent) => {\n // Listen for invalid events dispatched by a `<form>` when it tries to\n // submit and the element is invalid. We ignore events dispatched when\n // calling `checkValidity()` as well as untrusted events, since the\n // `reportValidity()` and `<form>`-dispatched events are always\n // trusted.\n if (this[privateDoNotReportInvalid] || !invalidEvent.isTrusted) {\n return;\n }\n\n this.addEventListener(\n 'invalid',\n () => {\n // A normal bubbling phase event listener. By adding it here, we\n // ensure it's the last event listener that is called during the\n // bubbling phase.\n if (!invalidEvent.defaultPrevented) {\n this[onReportValidity](invalidEvent);\n }\n },\n {once: true},\n );\n },\n {\n // Listen during the capture phase, which will happen before the\n // bubbling phase. That way, we can add a final event listener that\n // will run after other event listeners, and we can check if it was\n // default prevented. This works because invalid does not bubble.\n capture: true,\n },\n );\n }\n\n override checkValidity() {\n this[privateDoNotReportInvalid] = true;\n const valid = super.checkValidity();\n this[privateDoNotReportInvalid] = false;\n return valid;\n }\n\n override reportValidity() {\n const valid = super.reportValidity();\n // Constructor's invalid listener will handle reporting invalid events.\n if (valid) {\n this[onReportValidity](null);\n }\n\n return valid;\n }\n\n [onReportValidity](invalidEvent: Event | null) {\n throw new Error('Implement [onReportValidity]');\n }\n\n override formAssociatedCallback(form: HTMLFormElement | null) {\n // can't use super.formAssociatedCallback?.() due to closure\n if (super.formAssociatedCallback) {\n super.formAssociatedCallback(form);\n }\n\n // Clean up previous submit listener\n this[privateCleanupFormListeners].abort();\n if (!form) {\n return;\n }\n\n this[privateCleanupFormListeners] = new AbortController();\n // If the element's form submits, then all controls are valid. This lets\n // the element remove its error styles that may have been set when\n // `reportValidity()` was called.\n form.addEventListener(\n 'submit',\n () => {\n this[onReportValidity](null);\n },\n {\n signal: this[privateCleanupFormListeners].signal,\n },\n );\n\n // Inject a callback when `form.reportValidity()` is called and the form\n // is valid. There isn't an event that is dispatched to alert us (unlike\n // the 'invalid' event), and we need to remove error styles when\n // `form.reportValidity()` is called and returns true.\n let reportedInvalidEventFromForm = false;\n let formReportValidityCleanup = new AbortController();\n injectFormReportValidityHooks({\n form,\n cleanup: this[privateCleanupFormListeners].signal,\n beforeReportValidity: () => {\n reportedInvalidEventFromForm = false;\n this.addEventListener(\n 'invalid',\n (invalidEvent) => {\n reportedInvalidEventFromForm = true;\n if (!invalidEvent.defaultPrevented) {\n this[onReportValidity](invalidEvent);\n }\n },\n {signal: formReportValidityCleanup.signal},\n );\n },\n afterReportValidity: () => {\n formReportValidityCleanup.abort();\n formReportValidityCleanup = new AbortController();\n if (reportedInvalidEventFromForm) {\n reportedInvalidEventFromForm = false;\n return;\n }\n\n // Report successful form validation if an invalid event wasn't\n // fired.\n this[onReportValidity](null);\n },\n });\n }\n }\n\n return OnReportValidityElement;\n}\n\nconst FORM_REPORT_VALIDITY_HOOKS = new WeakMap<HTMLFormElement, EventTarget>();\n\nfunction injectFormReportValidityHooks({\n form,\n beforeReportValidity,\n afterReportValidity,\n cleanup,\n}: {\n form: HTMLFormElement;\n beforeReportValidity: () => void;\n afterReportValidity: () => void;\n cleanup: AbortSignal;\n}) {\n if (!FORM_REPORT_VALIDITY_HOOKS.has(form)) {\n // Patch form.reportValidity() to add an event target that can be used to\n // react when the method is called.\n // We should only patch this method once, since multiple controls and other\n // forces may want to patch this method. We cannot reliably clean it up by\n // resetting the method to \"superReportValidity\", which may be a patched\n // function.\n // Instead, we never clean up the patch but add and clean up event listener\n // hooks once it's patched.\n const hooks = new EventTarget();\n const superReportValidity = form.reportValidity;\n form.reportValidity = function (this: HTMLFormElement) {\n hooks.dispatchEvent(new Event('before'));\n const valid = superReportValidity.call(this);\n hooks.dispatchEvent(new Event('after'));\n return valid;\n };\n\n FORM_REPORT_VALIDITY_HOOKS.set(form, hooks);\n }\n\n const hooks = FORM_REPORT_VALIDITY_HOOKS.get(form)!;\n hooks.addEventListener('before', beforeReportValidity, {signal: cleanup});\n hooks.addEventListener('after', afterReportValidity, {signal: cleanup});\n}\n"]}
|
|
@@ -11,11 +11,11 @@ export interface CheckboxState {
|
|
|
11
11
|
/**
|
|
12
12
|
* Whether the checkbox is checked.
|
|
13
13
|
*/
|
|
14
|
-
checked: boolean;
|
|
14
|
+
readonly checked: boolean;
|
|
15
15
|
/**
|
|
16
16
|
* Whether the checkbox is required.
|
|
17
17
|
*/
|
|
18
|
-
required: boolean;
|
|
18
|
+
readonly required: boolean;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* A validator that provides constraint validation that emulates
|
|
@@ -28,5 +28,8 @@ export declare class CheckboxValidator extends Validator<CheckboxState> {
|
|
|
28
28
|
validationMessage: string;
|
|
29
29
|
};
|
|
30
30
|
protected equals(prev: CheckboxState, next: CheckboxState): boolean;
|
|
31
|
-
protected copy({ checked, required }: CheckboxState):
|
|
31
|
+
protected copy({ checked, required }: CheckboxState): {
|
|
32
|
+
checked: boolean;
|
|
33
|
+
required: boolean;
|
|
34
|
+
};
|
|
32
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox-validator.js","sourceRoot":"","sources":["checkbox-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAiBzC;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,SAAwB;IAG1C,eAAe,CAAC,KAAoB;QACrD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;YACzB,mCAAmC;YACnC,IAAI,CAAC,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,UAAU,CAAC;SACxC;QAED,IAAI,CAAC,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC7C,IAAI,CAAC,eAAe,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/C,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ;YACvC,iBAAiB,EAAE,IAAI,CAAC,eAAe,CAAC,iBAAiB;SAC1D,CAAC;IACJ,CAAC;IAEkB,MAAM,CAAC,IAAmB,EAAE,IAAmB;QAChE,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,CAAC;IAC1E,CAAC;IAEkB,IAAI,CAAC,EAAC,OAAO,EAAE,QAAQ,EAAgB;QACxD,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAC,CAAC;IAC7B,CAAC;CACF","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {Validator} from './validator.js';\n\n/**\n * Constraint validation properties for a checkbox.\n */\nexport interface CheckboxState {\n /**\n * Whether the checkbox is checked.\n */\n checked: boolean;\n\n /**\n * Whether the checkbox is required.\n */\n required: boolean;\n}\n\n/**\n * A validator that provides constraint validation that emulates\n * `<input type=\"checkbox\">` validation.\n */\nexport class CheckboxValidator extends Validator<CheckboxState> {\n private checkboxControl?: HTMLInputElement;\n\n protected override computeValidity(state: CheckboxState) {\n if (!this.checkboxControl) {\n // Lazily create the platform input\n this.checkboxControl = document.createElement('input');\n this.checkboxControl.type = 'checkbox';\n }\n\n this.checkboxControl.checked = state.checked;\n this.checkboxControl.required = state.required;\n return {\n validity: this.checkboxControl.validity,\n validationMessage: this.checkboxControl.validationMessage,\n };\n }\n\n protected override equals(prev: CheckboxState, next: CheckboxState) {\n return prev.checked === next.checked && prev.required === next.required;\n }\n\n protected override copy({checked, required}: CheckboxState)
|
|
1
|
+
{"version":3,"file":"checkbox-validator.js","sourceRoot":"","sources":["checkbox-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAiBzC;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,SAAwB;IAG1C,eAAe,CAAC,KAAoB;QACrD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;YACzB,mCAAmC;YACnC,IAAI,CAAC,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,UAAU,CAAC;SACxC;QAED,IAAI,CAAC,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC7C,IAAI,CAAC,eAAe,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/C,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ;YACvC,iBAAiB,EAAE,IAAI,CAAC,eAAe,CAAC,iBAAiB;SAC1D,CAAC;IACJ,CAAC;IAEkB,MAAM,CAAC,IAAmB,EAAE,IAAmB;QAChE,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,CAAC;IAC1E,CAAC;IAEkB,IAAI,CAAC,EAAC,OAAO,EAAE,QAAQ,EAAgB;QACxD,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAC,CAAC;IAC7B,CAAC;CACF","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {Validator} from './validator.js';\n\n/**\n * Constraint validation properties for a checkbox.\n */\nexport interface CheckboxState {\n /**\n * Whether the checkbox is checked.\n */\n readonly checked: boolean;\n\n /**\n * Whether the checkbox is required.\n */\n readonly required: boolean;\n}\n\n/**\n * A validator that provides constraint validation that emulates\n * `<input type=\"checkbox\">` validation.\n */\nexport class CheckboxValidator extends Validator<CheckboxState> {\n private checkboxControl?: HTMLInputElement;\n\n protected override computeValidity(state: CheckboxState) {\n if (!this.checkboxControl) {\n // Lazily create the platform input\n this.checkboxControl = document.createElement('input');\n this.checkboxControl.type = 'checkbox';\n }\n\n this.checkboxControl.checked = state.checked;\n this.checkboxControl.required = state.required;\n return {\n validity: this.checkboxControl.validity,\n validationMessage: this.checkboxControl.validationMessage,\n };\n }\n\n protected override equals(prev: CheckboxState, next: CheckboxState) {\n return prev.checked === next.checked && prev.required === next.required;\n }\n\n protected override copy({checked, required}: CheckboxState) {\n return {checked, required};\n }\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Validator } from './validator.js';
|
|
7
|
+
/**
|
|
8
|
+
* Constraint validation properties for a radio.
|
|
9
|
+
*/
|
|
10
|
+
export interface RadioState {
|
|
11
|
+
/**
|
|
12
|
+
* Whether the radio is checked.
|
|
13
|
+
*/
|
|
14
|
+
readonly checked: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Whether the radio is required.
|
|
17
|
+
*/
|
|
18
|
+
readonly required: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Radio constraint validation properties for a single radio and its siblings.
|
|
22
|
+
*/
|
|
23
|
+
export type RadioGroupState = readonly [RadioState, ...RadioState[]];
|
|
24
|
+
/**
|
|
25
|
+
* A validator that provides constraint validation that emulates
|
|
26
|
+
* `<input type="radio">` validation.
|
|
27
|
+
*/
|
|
28
|
+
export declare class RadioValidator extends Validator<RadioGroupState> {
|
|
29
|
+
private radioElement?;
|
|
30
|
+
protected computeValidity(states: RadioGroupState): {
|
|
31
|
+
validity: {
|
|
32
|
+
valueMissing: boolean;
|
|
33
|
+
};
|
|
34
|
+
validationMessage: string;
|
|
35
|
+
};
|
|
36
|
+
protected equals(prevGroup: RadioGroupState, nextGroup: RadioGroupState): boolean;
|
|
37
|
+
protected copy(states: RadioGroupState): RadioGroupState;
|
|
38
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Validator } from './validator.js';
|
|
7
|
+
/**
|
|
8
|
+
* A validator that provides constraint validation that emulates
|
|
9
|
+
* `<input type="radio">` validation.
|
|
10
|
+
*/
|
|
11
|
+
export class RadioValidator extends Validator {
|
|
12
|
+
computeValidity(states) {
|
|
13
|
+
if (!this.radioElement) {
|
|
14
|
+
// Lazily create the radio element
|
|
15
|
+
this.radioElement = document.createElement('input');
|
|
16
|
+
this.radioElement.type = 'radio';
|
|
17
|
+
// A name is required for validation to run
|
|
18
|
+
this.radioElement.name = 'group';
|
|
19
|
+
}
|
|
20
|
+
let isRequired = false;
|
|
21
|
+
let isChecked = false;
|
|
22
|
+
for (const { checked, required } of states) {
|
|
23
|
+
if (required) {
|
|
24
|
+
isRequired = true;
|
|
25
|
+
}
|
|
26
|
+
if (checked) {
|
|
27
|
+
isChecked = true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Firefox v119 doesn't compute grouped radio validation correctly while
|
|
31
|
+
// they are detached from the DOM, which is why we don't render multiple
|
|
32
|
+
// virtual <input>s. Instead, we can check the required/checked states and
|
|
33
|
+
// grab the i18n'd validation message if the value is missing.
|
|
34
|
+
this.radioElement.checked = isChecked;
|
|
35
|
+
this.radioElement.required = isRequired;
|
|
36
|
+
return {
|
|
37
|
+
validity: {
|
|
38
|
+
valueMissing: isRequired && !isChecked,
|
|
39
|
+
},
|
|
40
|
+
validationMessage: this.radioElement.validationMessage,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
equals(prevGroup, nextGroup) {
|
|
44
|
+
if (prevGroup.length !== nextGroup.length) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
for (let i = 0; i < prevGroup.length; i++) {
|
|
48
|
+
const prev = prevGroup[i];
|
|
49
|
+
const next = nextGroup[i];
|
|
50
|
+
if (prev.checked !== next.checked || prev.required !== next.required) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
copy(states) {
|
|
57
|
+
// Cast as unknown since typescript does not have enough information to
|
|
58
|
+
// infer that the array always has at least one element.
|
|
59
|
+
return states.map(({ checked, required }) => ({
|
|
60
|
+
checked,
|
|
61
|
+
required,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=radio-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio-validator.js","sourceRoot":"","sources":["radio-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAsBzC;;;GAGG;AACH,MAAM,OAAO,cAAe,SAAQ,SAA0B;IAGzC,eAAe,CAAC,MAAuB;QACxD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YACtB,kCAAkC;YAClC,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACpD,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC;YACjC,2CAA2C;YAC3C,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC;SAClC;QAED,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,MAAM,EAAC,OAAO,EAAE,QAAQ,EAAC,IAAI,MAAM,EAAE;YACxC,IAAI,QAAQ,EAAE;gBACZ,UAAU,GAAG,IAAI,CAAC;aACnB;YAED,IAAI,OAAO,EAAE;gBACX,SAAS,GAAG,IAAI,CAAC;aAClB;SACF;QAED,wEAAwE;QACxE,wEAAwE;QACxE,0EAA0E;QAC1E,8DAA8D;QAC9D,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC;QACtC,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,UAAU,CAAC;QACxC,OAAO;YACL,QAAQ,EAAE;gBACR,YAAY,EAAE,UAAU,IAAI,CAAC,SAAS;aACvC;YACD,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,iBAAiB;SACvD,CAAC;IACJ,CAAC;IAEkB,MAAM,CACvB,SAA0B,EAC1B,SAA0B;QAE1B,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE;YACzC,OAAO,KAAK,CAAC;SACd;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACzC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,EAAE;gBACpE,OAAO,KAAK,CAAC;aACd;SACF;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEkB,IAAI,CAAC,MAAuB;QAC7C,uEAAuE;QACvE,wDAAwD;QACxD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAC,OAAO,EAAE,QAAQ,EAAC,EAAE,EAAE,CAAC,CAAC;YAC1C,OAAO;YACP,QAAQ;SACT,CAAC,CAA+B,CAAC;IACpC,CAAC;CACF","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {Validator} from './validator.js';\n\n/**\n * Constraint validation properties for a radio.\n */\nexport interface RadioState {\n /**\n * Whether the radio is checked.\n */\n readonly checked: boolean;\n\n /**\n * Whether the radio is required.\n */\n readonly required: boolean;\n}\n\n/**\n * Radio constraint validation properties for a single radio and its siblings.\n */\nexport type RadioGroupState = readonly [RadioState, ...RadioState[]];\n\n/**\n * A validator that provides constraint validation that emulates\n * `<input type=\"radio\">` validation.\n */\nexport class RadioValidator extends Validator<RadioGroupState> {\n private radioElement?: HTMLInputElement;\n\n protected override computeValidity(states: RadioGroupState) {\n if (!this.radioElement) {\n // Lazily create the radio element\n this.radioElement = document.createElement('input');\n this.radioElement.type = 'radio';\n // A name is required for validation to run\n this.radioElement.name = 'group';\n }\n\n let isRequired = false;\n let isChecked = false;\n for (const {checked, required} of states) {\n if (required) {\n isRequired = true;\n }\n\n if (checked) {\n isChecked = true;\n }\n }\n\n // Firefox v119 doesn't compute grouped radio validation correctly while\n // they are detached from the DOM, which is why we don't render multiple\n // virtual <input>s. Instead, we can check the required/checked states and\n // grab the i18n'd validation message if the value is missing.\n this.radioElement.checked = isChecked;\n this.radioElement.required = isRequired;\n return {\n validity: {\n valueMissing: isRequired && !isChecked,\n },\n validationMessage: this.radioElement.validationMessage,\n };\n }\n\n protected override equals(\n prevGroup: RadioGroupState,\n nextGroup: RadioGroupState,\n ) {\n if (prevGroup.length !== nextGroup.length) {\n return false;\n }\n\n for (let i = 0; i < prevGroup.length; i++) {\n const prev = prevGroup[i];\n const next = nextGroup[i];\n if (prev.checked !== next.checked || prev.required !== next.required) {\n return false;\n }\n }\n\n return true;\n }\n\n protected override copy(states: RadioGroupState): RadioGroupState {\n // Cast as unknown since typescript does not have enough information to\n // infer that the array always has at least one element.\n return states.map(({checked, required}) => ({\n checked,\n required,\n })) as unknown as RadioGroupState;\n }\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Validator } from './validator.js';
|
|
7
|
+
/**
|
|
8
|
+
* Constraint validation properties for a select dropdown.
|
|
9
|
+
*/
|
|
10
|
+
export interface SelectState {
|
|
11
|
+
/**
|
|
12
|
+
* The current selected value.
|
|
13
|
+
*/
|
|
14
|
+
readonly value: string;
|
|
15
|
+
/**
|
|
16
|
+
* Whether the select is required.
|
|
17
|
+
*/
|
|
18
|
+
readonly required: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A validator that provides constraint validation that emulates `<select>`
|
|
22
|
+
* validation.
|
|
23
|
+
*/
|
|
24
|
+
export declare class SelectValidator extends Validator<SelectState> {
|
|
25
|
+
private selectControl?;
|
|
26
|
+
protected computeValidity(state: SelectState): {
|
|
27
|
+
validity: ValidityState;
|
|
28
|
+
validationMessage: string;
|
|
29
|
+
};
|
|
30
|
+
protected equals(prev: SelectState, next: SelectState): boolean;
|
|
31
|
+
protected copy({ value, required }: SelectState): {
|
|
32
|
+
value: string;
|
|
33
|
+
required: boolean;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { html, render } from 'lit';
|
|
7
|
+
import { Validator } from './validator.js';
|
|
8
|
+
/**
|
|
9
|
+
* A validator that provides constraint validation that emulates `<select>`
|
|
10
|
+
* validation.
|
|
11
|
+
*/
|
|
12
|
+
export class SelectValidator extends Validator {
|
|
13
|
+
computeValidity(state) {
|
|
14
|
+
if (!this.selectControl) {
|
|
15
|
+
// Lazily create the platform select
|
|
16
|
+
this.selectControl = document.createElement('select');
|
|
17
|
+
}
|
|
18
|
+
render(html `<option value=${state.value}></option>`, this.selectControl);
|
|
19
|
+
this.selectControl.value = state.value;
|
|
20
|
+
this.selectControl.required = state.required;
|
|
21
|
+
return {
|
|
22
|
+
validity: this.selectControl.validity,
|
|
23
|
+
validationMessage: this.selectControl.validationMessage,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
equals(prev, next) {
|
|
27
|
+
return prev.value === next.value && prev.required === next.required;
|
|
28
|
+
}
|
|
29
|
+
copy({ value, required }) {
|
|
30
|
+
return { value, required };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=select-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-validator.js","sourceRoot":"","sources":["select-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,IAAI,EAAE,MAAM,EAAC,MAAM,KAAK,CAAC;AAEjC,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAiBzC;;;GAGG;AACH,MAAM,OAAO,eAAgB,SAAQ,SAAsB;IAGtC,eAAe,CAAC,KAAkB;QACnD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YACvB,oCAAoC;YACpC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;SACvD;QAED,MAAM,CAAC,IAAI,CAAA,iBAAiB,KAAK,CAAC,KAAK,YAAY,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAEzE,IAAI,CAAC,aAAa,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QACvC,IAAI,CAAC,aAAa,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC7C,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ;YACrC,iBAAiB,EAAE,IAAI,CAAC,aAAa,CAAC,iBAAiB;SACxD,CAAC;IACJ,CAAC;IAEkB,MAAM,CAAC,IAAiB,EAAE,IAAiB;QAC5D,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,CAAC;IACtE,CAAC;IAEkB,IAAI,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAc;QACpD,OAAO,EAAC,KAAK,EAAE,QAAQ,EAAC,CAAC;IAC3B,CAAC;CACF","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {html, render} from 'lit';\n\nimport {Validator} from './validator.js';\n\n/**\n * Constraint validation properties for a select dropdown.\n */\nexport interface SelectState {\n /**\n * The current selected value.\n */\n readonly value: string;\n\n /**\n * Whether the select is required.\n */\n readonly required: boolean;\n}\n\n/**\n * A validator that provides constraint validation that emulates `<select>`\n * validation.\n */\nexport class SelectValidator extends Validator<SelectState> {\n private selectControl?: HTMLSelectElement;\n\n protected override computeValidity(state: SelectState) {\n if (!this.selectControl) {\n // Lazily create the platform select\n this.selectControl = document.createElement('select');\n }\n\n render(html`<option value=${state.value}></option>`, this.selectControl);\n\n this.selectControl.value = state.value;\n this.selectControl.required = state.required;\n return {\n validity: this.selectControl.validity,\n validationMessage: this.selectControl.validationMessage,\n };\n }\n\n protected override equals(prev: SelectState, next: SelectState) {\n return prev.value === next.value && prev.required === next.required;\n }\n\n protected override copy({value, required}: SelectState) {\n return {value, required};\n }\n}\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Validator } from './validator.js';
|
|
7
|
+
/**
|
|
8
|
+
* Constraint validation for a text field.
|
|
9
|
+
*/
|
|
10
|
+
export interface TextFieldState {
|
|
11
|
+
/**
|
|
12
|
+
* The input or textarea state to validate.
|
|
13
|
+
*/
|
|
14
|
+
state: InputState | TextAreaState;
|
|
15
|
+
/**
|
|
16
|
+
* The `<input>` or `<textarea>` that is rendered on the page.
|
|
17
|
+
*
|
|
18
|
+
* `minlength` and `maxlength` validation do not apply until a user has
|
|
19
|
+
* interacted with the control and the element is internally marked as dirty.
|
|
20
|
+
* This is a spec quirk, the two properties behave differently from other
|
|
21
|
+
* constraint validation.
|
|
22
|
+
*
|
|
23
|
+
* This means we need an actual rendered element instead of a virtual one,
|
|
24
|
+
* since the virtual element will never be marked as dirty.
|
|
25
|
+
*
|
|
26
|
+
* This can be `null` if the element has not yet rendered, and the validator
|
|
27
|
+
* will fall back to virtual elements for other constraint validation
|
|
28
|
+
* properties, which do apply even if the control is not dirty.
|
|
29
|
+
*/
|
|
30
|
+
renderedControl: HTMLInputElement | HTMLTextAreaElement | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Constraint validation properties for an `<input>`.
|
|
34
|
+
*/
|
|
35
|
+
export interface InputState extends SharedInputAndTextAreaState {
|
|
36
|
+
/**
|
|
37
|
+
* The `<input>` type.
|
|
38
|
+
*
|
|
39
|
+
* Not all constraint validation properties apply to every type. See
|
|
40
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#validation-related_attributes
|
|
41
|
+
* for which properties will apply to which types.
|
|
42
|
+
*/
|
|
43
|
+
readonly type: string;
|
|
44
|
+
/**
|
|
45
|
+
* The regex pattern a value must match.
|
|
46
|
+
*/
|
|
47
|
+
readonly pattern: string;
|
|
48
|
+
/**
|
|
49
|
+
* The minimum value.
|
|
50
|
+
*/
|
|
51
|
+
readonly min: string;
|
|
52
|
+
/**
|
|
53
|
+
* The maximum value.
|
|
54
|
+
*/
|
|
55
|
+
readonly max: string;
|
|
56
|
+
/**
|
|
57
|
+
* The step interval of the value.
|
|
58
|
+
*/
|
|
59
|
+
readonly step: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Constraint validation properties for a `<textarea>`.
|
|
63
|
+
*/
|
|
64
|
+
export interface TextAreaState extends SharedInputAndTextAreaState {
|
|
65
|
+
/**
|
|
66
|
+
* The type, must be "textarea" to inform the validator to use `<textarea>`
|
|
67
|
+
* instead of `<input>`.
|
|
68
|
+
*/
|
|
69
|
+
readonly type: 'textarea';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Constraint validation properties shared between an `<input>` and
|
|
73
|
+
* `<textarea>`.
|
|
74
|
+
*/
|
|
75
|
+
interface SharedInputAndTextAreaState {
|
|
76
|
+
/**
|
|
77
|
+
* The current value.
|
|
78
|
+
*/
|
|
79
|
+
readonly value: string;
|
|
80
|
+
/**
|
|
81
|
+
* Whether the textarea is required.
|
|
82
|
+
*/
|
|
83
|
+
readonly required: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The minimum length of the value.
|
|
86
|
+
*/
|
|
87
|
+
readonly minLength: number;
|
|
88
|
+
/**
|
|
89
|
+
* The maximum length of the value.
|
|
90
|
+
*/
|
|
91
|
+
readonly maxLength: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A validator that provides constraint validation that emulates `<input>` and
|
|
95
|
+
* `<textarea>` validation.
|
|
96
|
+
*/
|
|
97
|
+
export declare class TextFieldValidator extends Validator<TextFieldState> {
|
|
98
|
+
private inputControl?;
|
|
99
|
+
private textAreaControl?;
|
|
100
|
+
protected computeValidity({ state, renderedControl }: TextFieldState): {
|
|
101
|
+
validity: ValidityState;
|
|
102
|
+
validationMessage: string;
|
|
103
|
+
};
|
|
104
|
+
protected equals({ state: prev }: TextFieldState, { state: next }: TextFieldState): boolean;
|
|
105
|
+
protected copy({ state }: TextFieldState): TextFieldState;
|
|
106
|
+
private copyInput;
|
|
107
|
+
private copyTextArea;
|
|
108
|
+
private copySharedState;
|
|
109
|
+
}
|
|
110
|
+
export {};
|