UNPKG

@material/web

Version:
131 lines 4.93 kB
/** * @license * Copyright 2023 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { isServer } from 'lit'; import { internals } from './element-internals.js'; /** * A symbol property used to create a constraint validation `Validator`. * Required for all `mixinConstraintValidation()` elements. */ export const createValidator = Symbol('createValidator'); /** * A symbol property used to return an anchor for constraint validation popups. * Required for all `mixinConstraintValidation()` elements. */ export const getValidityAnchor = Symbol('getValidityAnchor'); // Private symbol members, used to avoid name clashing. const privateValidator = Symbol('privateValidator'); const privateSyncValidity = Symbol('privateSyncValidity'); const privateCustomValidationMessage = Symbol('privateCustomValidationMessage'); /** * Mixes in constraint validation APIs for an element. * * See https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation * for more details. * * Implementations must provide a validator to cache and compute its validity, * along with a shadow root element to anchor validation popups to. * * @example * ```ts * const baseClass = mixinConstraintValidation( * mixinFormAssociated(mixinElementInternals(LitElement)) * ); * * class MyCheckbox extends baseClass { * \@property({type: Boolean}) checked = false; * \@property({type: Boolean}) required = false; * * [createValidator]() { * return new CheckboxValidator(() => this); * } * * [getValidityAnchor]() { * return this.renderRoot.querySelector('.root'); * } * } * ``` * * @param base The class to mix functionality into. * @return The provided class with `ConstraintValidation` mixed in. */ export function mixinConstraintValidation(base) { var _a; class ConstraintValidationElement extends base { constructor() { super(...arguments); /** * Needed for Safari, see https://bugs.webkit.org/show_bug.cgi?id=261432 * Replace with this[internals].validity.customError when resolved. */ this[_a] = ''; } get validity() { this[privateSyncValidity](); return this[internals].validity; } get validationMessage() { this[privateSyncValidity](); return this[internals].validationMessage; } get willValidate() { this[privateSyncValidity](); return this[internals].willValidate; } checkValidity() { this[privateSyncValidity](); return this[internals].checkValidity(); } reportValidity() { this[privateSyncValidity](); return this[internals].reportValidity(); } setCustomValidity(error) { this[privateCustomValidationMessage] = error; this[privateSyncValidity](); } requestUpdate(name, oldValue, options) { super.requestUpdate(name, oldValue, options); this[privateSyncValidity](); } firstUpdated(changed) { super.firstUpdated(changed); // Sync the validity again when the element first renders, since the // validity anchor is now available. // // Elements that `delegatesFocus: true` to an `<input>` will throw an // error in Chrome and Safari when a form tries to submit or call // `form.reportValidity()`: // "An invalid form control with name='' is not focusable" // // The validity anchor MUST be provided in `internals.setValidity()` and // MUST be the `<input>` element rendered. // // See https://lit.dev/playground/#gist=6c26e418e0010f7a5aac15005cde8bde // for a reproduction. this[privateSyncValidity](); } [(_a = privateCustomValidationMessage, privateSyncValidity)]() { if (isServer) { return; } if (!this[privateValidator]) { this[privateValidator] = this[createValidator](); } const { validity, validationMessage: nonCustomValidationMessage } = this[privateValidator].getValidity(); const customError = !!this[privateCustomValidationMessage]; const validationMessage = this[privateCustomValidationMessage] || nonCustomValidationMessage; this[internals].setValidity({ ...validity, customError }, validationMessage, this[getValidityAnchor]() ?? undefined); } [createValidator]() { throw new Error('Implement [createValidator]'); } [getValidityAnchor]() { throw new Error('Implement [getValidityAnchor]'); } } return ConstraintValidationElement; } //# sourceMappingURL=constraint-validation.js.map