UNPKG

@synergy-design-system/components

Version:

This package provides the base of the Synergy Design System as native web components. It uses [lit](https://www.lit.dev) and parts of [shoelace](https://shoelace.style/). Synergy officially supports the latest two versions of all major browsers (as define

365 lines (361 loc) 11.1 kB
import { alertSizeForInput, getEventNameForElement, isBlurEvent, isInvalidEvent, isSynergyElement, normalizeEventAttribute } from "./chunk.2LRU3I3N.js"; import { validate_styles_default } from "./chunk.MVM3NN6Y.js"; import { SynAlert } from "./chunk.LLOONJ33.js"; import { enableDefaultSettings } from "./chunk.HYFCK7MM.js"; import { watch } from "./chunk.BVZQ6QSY.js"; import { component_styles_default } from "./chunk.NLYVOJGK.js"; import { SynergyElement } from "./chunk.3THJTCRO.js"; import { __decorateClass } from "./chunk.Z4XV3SMG.js"; // src/components/validate/validate.component.ts import { html } from "lit"; import { property, queryAssignedElements, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; var SynValidate = class extends SynergyElement { constructor() { super(...arguments); this.controller = new AbortController(); this.validationMessage = ""; this.eagerFirstMount = true; this.isInternalTriggeredInvalid = false; this.isValid = true; this.variant = "native"; this.hideIcon = false; this.on = ""; this.customValidationMessage = ""; this.eager = false; /** * Set the validation message from the input element * @param e The event that was received */ this.internalRevalidate = (e) => { var _a; const input = e.currentTarget; if ((_a = input.validity) == null ? void 0 : _a.valid) { this.validationMessage = ""; } }; /** * Triggers a validation run, showing the validation message if needed. */ // eslint-disable-next-line complexity this.validate = async (e) => { var _a; if (isInvalidEvent(e.type) && this.variant === "native" && this.isInternalTriggeredInvalid === true) { this.isInternalTriggeredInvalid = false; return; } if (isInvalidEvent(e.type) && this.variant !== "native") { e.preventDefault(); e.stopPropagation(); } const input = e.currentTarget; if (isSynergyElement(input)) { await input.updateComplete; } this.isValid = (_a = input.validity) == null ? void 0 : _a.valid; if (this.eager && this.eagerFirstMount) { this.eagerFirstMount = false; this.setValidationMessage(input); return; } if (!this.isValid && !isBlurEvent(e.type)) { this.handleFocus(input); } this.setValidationMessage(input); if (!isBlurEvent(e.type) && this.variant === "native") { this.updateComplete.then(() => { this.isInternalTriggeredInvalid = true; input.reportValidity(); }); } }; } handleListenerChange() { this.updateEvents(); } async handleEagerChange() { if (this.eager) { const input = this.getInput(); await this.updateComplete; input == null ? void 0 : input.reportValidity(); this.eagerFirstMount = true; } else { this.eagerFirstMount = false; } } handleCustomValidationMessageChange() { const input = this.getInput(); if (input) { this.setCustomValidationMessage(input); this.setValidationMessage(input); } } /** * Returns the validity state of the input component. * `true` for valid and `false` for invalid. */ getValidity() { return this.isValid; } /** * Get the input element to validate. Defined as the first slotted element * @returns The input element or undefined if not found */ getInput() { const input = this.slottedChildren[0]; return input ? input : void 0; } setAlertSize() { this.alertSize = alertSizeForInput(this.getInput()); } /** * Get the event names to listen for. * If the input is a synergy element, will use syn- prefixes. * @returns The event names to listen for */ // eslint-disable-next-line complexity getUsedEventNames() { const input = this.getInput(); if (!input) { return []; } const on = normalizeEventAttribute(this.on); const [...events] = on.filter(Boolean); if (!events.includes("invalid")) { events.push("invalid"); } if (events.includes("live")) { events.push("input"); events.push("blur"); } return Array.from(new Set( events.filter((e) => e !== "live").map((e) => getEventNameForElement(input, e)) )); } /** * Update the events on the input element. */ updateEvents() { this.controller.abort(); this.controller = new AbortController(); const input = this.getInput(); if (!input) { return; } const events = this.getUsedEventNames(); events.forEach((eventName) => { input.addEventListener(eventName, this.validate, { capture: isInvalidEvent(eventName), signal: this.controller.signal }); }); const usedChangeEvent = getEventNameForElement(input, "change"); if (!events.includes(usedChangeEvent)) { input.addEventListener(usedChangeEvent, this.internalRevalidate, { signal: this.controller.signal }); } } setValidationMessage(input) { const { customValidationMessage } = this; const validationMessage = customValidationMessage || input.validationMessage; this.validationMessage = validationMessage; } /** * Set the custom validation message to the input. This will make sure to either: * - use the custom message if one is set or * - use the default message if the custom message is empty */ setCustomValidationMessage(input) { input.setCustomValidity(this.customValidationMessage); } /** * Handle the blur event during validation */ // eslint-disable-next-line class-methods-use-this handleFocus(input) { var _a; const activeElement = document.activeElement; const activeElementIsWrapped = activeElement.closest("syn-validate"); if (!((_a = activeElement.validity) == null ? void 0 : _a.valid) && activeElementIsWrapped) { return; } input.scrollIntoView({ block: "nearest" }); input.focus(); } async firstUpdated(changedProperties) { var _a, _b; super.firstUpdated(changedProperties); this.updateEvents(); const input = this.getInput(); if (this.customValidationMessage) { if (isSynergyElement(input)) { await input.updateComplete; } input == null ? void 0 : input.setCustomValidity(this.customValidationMessage); } if (this.eager) { await this.updateComplete; this.isValid = (_b = (_a = input == null ? void 0 : input.validity) == null ? void 0 : _a.valid) != null ? _b : false; input == null ? void 0 : input.reportValidity(); } } connectedCallback() { super.connectedCallback(); this.sizeObserver = new MutationObserver((entries) => { const input = this.getInput(); if (!input) { return; } const hasSizeChanged = entries.filter(({ target }) => target === input).every( (entry) => entry.attributeName === "size" ); if (hasSizeChanged) { this.setAlertSize(); } }); this.sizeObserver.observe(this, { attributeFilter: ["size"], attributes: true, subtree: true }); this.observer = new MutationObserver((entries) => { const input = this.getInput(); if (!input) { return; } const hasDisabledOrReadonly = entries.filter(({ target }) => target === input).every((entry) => { const target = entry.target; return target.hasAttribute("disabled") || target.hasAttribute("readonly"); }); if (hasDisabledOrReadonly) { this.isValid = true; this.validationMessage = ""; } else { const waitForPromise = isSynergyElement(input) ? input.updateComplete : Promise.resolve(); waitForPromise.then(() => { var _a, _b, _c; this.isValid = (_b = (_a = input == null ? void 0 : input.validity) == null ? void 0 : _a.valid) != null ? _b : false; this.validationMessage = (_c = input == null ? void 0 : input.validationMessage) != null ? _c : ""; }); } }); this.observer.observe(this, { attributeFilter: ["disabled", "readonly"], attributes: true, subtree: true }); } disconnectedCallback() { var _a, _b; super.disconnectedCallback(); this.controller.abort(); (_a = this == null ? void 0 : this.observer) == null ? void 0 : _a.disconnect(); (_b = this == null ? void 0 : this.sizeObserver) == null ? void 0 : _b.disconnect(); } renderInlineValidation() { if (this.variant !== "inline" || !this.validationMessage) { return ""; } return html` <syn-alert open exportparts="base:alert__base,message:alert__message,icon:alert__icon" part="alert" size=${ifDefined(this.alertSize)} variant="danger" > ${!this.hideIcon ? html`<syn-icon slot="icon" name="status-error" library="system"></syn-icon>` : ""} ${this.validationMessage} </syn-alert> `; } render() { return html` <div class="validate" part="base" > <slot class="validate__input-wrapper" part="input-wrapper" ></slot> ${this.renderInlineValidation()} </div> `; } }; SynValidate.styles = [component_styles_default, validate_styles_default]; SynValidate.dependencies = { "syn-alert": SynAlert }; __decorateClass([ queryAssignedElements() ], SynValidate.prototype, "slottedChildren", 2); __decorateClass([ state() ], SynValidate.prototype, "validationMessage", 2); __decorateClass([ state() ], SynValidate.prototype, "eagerFirstMount", 2); __decorateClass([ state() ], SynValidate.prototype, "isInternalTriggeredInvalid", 2); __decorateClass([ state() ], SynValidate.prototype, "isValid", 2); __decorateClass([ state() ], SynValidate.prototype, "alertSize", 2); __decorateClass([ property({ reflect: true }) ], SynValidate.prototype, "variant", 2); __decorateClass([ property({ attribute: "hide-icon", reflect: true, type: Boolean }) ], SynValidate.prototype, "hideIcon", 2); __decorateClass([ property({ reflect: true }) ], SynValidate.prototype, "on", 2); __decorateClass([ property({ attribute: "custom-validation-message", type: String }) ], SynValidate.prototype, "customValidationMessage", 2); __decorateClass([ property({ type: Boolean }) ], SynValidate.prototype, "eager", 2); __decorateClass([ watch("on", { waitUntilFirstUpdate: true }) ], SynValidate.prototype, "handleListenerChange", 1); __decorateClass([ watch("eager", { waitUntilFirstUpdate: false }) ], SynValidate.prototype, "handleEagerChange", 1); __decorateClass([ watch("customValidationMessage", { waitUntilFirstUpdate: true }) ], SynValidate.prototype, "handleCustomValidationMessageChange", 1); SynValidate = __decorateClass([ enableDefaultSettings("SynValidate") ], SynValidate); export { SynValidate }; //# sourceMappingURL=chunk.F3KGIXQV.js.map