@felleslosninger/minid-elements 0.0.135 → 0.0.137
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/dist/components/code-input.component.d.ts.map +1 -1
- package/dist/components/code-input.js +1 -0
- package/dist/components/code-input.js.map +1 -1
- package/dist/components/textfield.component.d.ts.map +1 -1
- package/dist/components/textfield.js +1 -0
- package/dist/components/textfield.js.map +1 -1
- package/dist/mixins/form-control.mixin.d.ts.map +1 -1
- package/dist/mixins/form-control.mixin.js +4 -2
- package/dist/mixins/form-control.mixin.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-input.component.d.ts","sourceRoot":"","sources":["../../src/components/code-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAQ5D,OAAO,0BAA0B,CAAC;AASlC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,cAAc,CAAC;KAClC;CACF;;AAyFD;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,cAAe,SAAQ,mBAEnC;IACC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IAGpE,OAAO,CAAC,YAAY,CAAoB;IAGxC,KAAK,SAAM;IAGX,KAAK,SAAM;IAGX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAY;IAEnC;;OAEG;IAEH,SAAS,EAAE,SAAS,GAAG,MAAM,CAAa;IAE1C;;OAEG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;OAEG;IAEH,MAAM,SAAK;IAGX,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,cAAc,SAAM;IAEpB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,KAAK,qBAAqB,qDAO/B;IAED,IAAI,gBAAgB,qBAEnB;IAED,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAIhE,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAgCnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;IAiBrB,KAAK;
|
|
1
|
+
{"version":3,"file":"code-input.component.d.ts","sourceRoot":"","sources":["../../src/components/code-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAQ5D,OAAO,0BAA0B,CAAC;AASlC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,cAAc,CAAC;KAClC;CACF;;AAyFD;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,cAAe,SAAQ,mBAEnC;IACC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IAGpE,OAAO,CAAC,YAAY,CAAoB;IAGxC,KAAK,SAAM;IAGX,KAAK,SAAM;IAGX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAY;IAEnC;;OAEG;IAEH,SAAS,EAAE,SAAS,GAAG,MAAM,CAAa;IAE1C;;OAEG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;OAEG;IAEH,MAAM,SAAK;IAGX,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,cAAc,SAAM;IAEpB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,KAAK,qBAAqB,qDAO/B;IAED,IAAI,gBAAgB,qBAEnB;IAED,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAIhE,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAgCnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;IAiBrB,KAAK;IAML,gBAAgB;IAKhB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;IAKnC,kBAAkB;IAOT,MAAM;CA8FhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-input.js","sources":["../../src/components/code-input.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch.ts';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { HasSlotController } from '../internal/slot.ts';\nimport './icon/icon.component.ts';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators.ts';\nimport { webOtpApiInit } from '../utilities/web-otp-api.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n .input-wrapper {\n position: relative;\n cursor: text;\n }\n\n .character-boxes {\n display: inline-flex;\n gap: 0.5rem; /* Corresponds to gap-2 in tailwind */\n }\n\n .character-box {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n }\n\n .hidden-input {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n margin: 0;\n background: transparent;\n border: none;\n color: transparent;\n /* Hide the real caret */\n caret-color: transparent;\n font-size: 16px; /* Must be at least 16px to prevent ios from zooming in */\n /* Allow clicks to pass through to elements underneath */\n pointer-events: none;\n }\n\n .hidden-input:focus {\n outline: none;\n }\n\n .hidden-input:disabled {\n cursor: not-allowed;\n }\n\n /* Fake caret using a CSS animation */\n @keyframes blink {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n }\n\n .character-box--caret::after {\n content: '';\n position: absolute;\n width: 2px;\n height: 60%;\n background-color: var(--color-accent-base, blue);\n animation: blink 1s step-end infinite;\n }\n\n /* Hide placeholder circle when the caret is present */\n .character-box--caret.character-box--empty {\n color: transparent;\n }\n\n /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n `,\n];\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-complete - Emitted when all characters have been entered.\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.\n *\n * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.\n * @csspart character-boxes - The container for the visual character boxes.\n * @csspart character-box - An individual character box.\n *\n * @method focus - Focuses the input element\n * @method clear - Clears the input\n */\n@customElement('mid-code-input')\nexport class MinidCodeInput extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private readonly labelId = `mid-code-input-label-${nextUniqueId++}`;\n\n @query('.hidden-input')\n private inputElement!: HTMLInputElement;\n\n @property({ reflect: true })\n value = '';\n\n @property()\n label = '';\n\n @property()\n type: 'number' | 'text' = 'number';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode: 'numeric' | 'text' = 'numeric';\n\n /**\n * Adjusts the font-size of the code inputs\n */\n @property()\n size: 'sm' | 'md' | 'lg' = 'sm';\n\n /**\n * Number of input characters or digits\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: Boolean })\n disabled = false;\n\n /**\n * Focuses the first input element on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n /**\n * Visually hides `label` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n @state()\n private isFocused = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n get validationTarget() {\n return this.inputElement;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n webOtpApiInit(this.renderRoot);\n }\n\n private handleBoxClick(index: number) {\n if (this.disabled) {\n return;\n }\n\n // Truncate the value to the clicked position\n this.value = this.value.substring(0, index);\n\n // Focus the input to move the caret\n this.focus();\n }\n\n private handleFocus() {\n this.isFocused = true;\n }\n\n private handleBlur() {\n this.isFocused = false;\n }\n\n private handleInput(event: InputEvent) {\n const input = event.target as HTMLInputElement;\n let value = input.value;\n\n if (this.type === 'number') {\n value = value.replace(/[^0-9]/g, '');\n }\n\n value = value.substring(0, this.length);\n\n if (input.value !== value) {\n input.value = value;\n }\n\n // Update the component's public `value` property if it has changed.\n if (this.value !== value) {\n this.value = value;\n this.setValue(value);\n }\n\n this.inputElement.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true }),\n );\n\n if (this.value.length === this.length && this.value.length > 0) {\n this.inputElement.dispatchEvent(\n new Event('mid-complete', { bubbles: true, composed: true }),\n );\n }\n\n }\n\n private handleChange() {\n this.inputElement.dispatchEvent(\n new Event('mid-change', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n if (event.key === 'Enter' && !hasModifier) {\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n setTimeout(() => {\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form?.requestSubmit();\n }\n });\n }\n }\n\n clear() {\n this.value = '';\n this.setValue('');\n }\n\n resetFormControl() {\n this.clear();\n }\n\n\n focus(options?: FocusOptions): void {\n this.inputElement?.focus(options);\n }\n\n @watch('length')\n handleLengthChange() {\n if (this.value.length > this.length) {\n this.value = this.value.substring(0, this.length);\n }\n }\n\n\n override render() {\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n\n const chars = this.value.split('');\n const displayValues = Array.from(\n { length: this.length },\n (_, i) => chars[i] || '',\n );\n const caretIndex = this.disabled ? -1 : this.value.length;\n\n return html`\n <label\n id=\"${this.labelId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n 'opacity-disabled': this.disabled,\n })} mb-2 block items-center gap-1 font-medium\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n <div\n part=\"input-container\"\n class=\"input-wrapper ${classMap({\n 'text-heading-sm': this.size === 'sm',\n 'text-heading-md': this.size === 'md',\n 'text-heading-lg': this.size === 'lg',\n 'opacity-disabled': this.disabled,\n })}\"\n @click=${() => this.focus()}\n >\n <div part=\"character-boxes\" class=\"character-boxes\">\n ${displayValues.map((char, index) => {\n const hasCaret = this.isFocused && index === caretIndex;\n return html`\n <div\n part=\"character-box\"\n class=\"character-box ${classMap({\n 'border': !this.invalidmessage,\n 'border-2': this.invalidmessage,\n 'border-neutral': !this.invalidmessage,\n 'border-danger': this.invalidmessage,\n 'bg-neutral': !this.invalidmessage,\n 'bg-danger-tinted': this.invalidmessage,\n 'text-neutral-surface-active':\n !char && !this.invalidmessage,\n 'text-danger-surface-active': !char && this.invalidmessage,\n 'character-box--caret': hasCaret,\n 'character-box--empty': !char,\n 'focus-ring-sm': hasCaret,\n })} size-9 rounded-md text-center font-mono\"\n @click=${(e: MouseEvent) => {\n e.stopPropagation();\n this.handleBoxClick(index);\n }}\n >\n ${char || '○'}\n </div>\n `;\n })}\n </div>\n <input\n class=\"hidden-input\"\n .value=\"${live(this.value)}\"\n id=\"mid-code-input-hidden\"\n type=\"${this.type}\"\n aria-labelledby=\"${this.labelId}\"\n maxlength=\"${this.length}\"\n ?autofocus=\"${this.autofocus}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n .pattern=\"${this.pattern}\"\n inputmode=\"${this.inputmode}\"\n autocomplete=\"one-time-code\"\n @input=\"${this.handleInput}\"\n @change=\"${this.handleChange}\"\n @keydown=\"${this.handleKeydown}\"\n @focus=\"${this.handleFocus}\"\n @blur=\"${this.handleBlur}\"\n />\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"code-input.js","sources":["../../src/components/code-input.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch.ts';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { HasSlotController } from '../internal/slot.ts';\nimport './icon/icon.component.ts';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators.ts';\nimport { webOtpApiInit } from '../utilities/web-otp-api.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n .input-wrapper {\n position: relative;\n cursor: text;\n }\n\n .character-boxes {\n display: inline-flex;\n gap: 0.5rem; /* Corresponds to gap-2 in tailwind */\n }\n\n .character-box {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n }\n\n .hidden-input {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n margin: 0;\n background: transparent;\n border: none;\n color: transparent;\n /* Hide the real caret */\n caret-color: transparent;\n font-size: 16px; /* Must be at least 16px to prevent ios from zooming in */\n /* Allow clicks to pass through to elements underneath */\n pointer-events: none;\n }\n\n .hidden-input:focus {\n outline: none;\n }\n\n .hidden-input:disabled {\n cursor: not-allowed;\n }\n\n /* Fake caret using a CSS animation */\n @keyframes blink {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n }\n\n .character-box--caret::after {\n content: '';\n position: absolute;\n width: 2px;\n height: 60%;\n background-color: var(--color-accent-base, blue);\n animation: blink 1s step-end infinite;\n }\n\n /* Hide placeholder circle when the caret is present */\n .character-box--caret.character-box--empty {\n color: transparent;\n }\n\n /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n `,\n];\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-complete - Emitted when all characters have been entered.\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.\n *\n * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.\n * @csspart character-boxes - The container for the visual character boxes.\n * @csspart character-box - An individual character box.\n *\n * @method focus - Focuses the input element\n * @method clear - Clears the input\n */\n@customElement('mid-code-input')\nexport class MinidCodeInput extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private readonly labelId = `mid-code-input-label-${nextUniqueId++}`;\n\n @query('.hidden-input')\n private inputElement!: HTMLInputElement;\n\n @property({ reflect: true })\n value = '';\n\n @property()\n label = '';\n\n @property()\n type: 'number' | 'text' = 'number';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode: 'numeric' | 'text' = 'numeric';\n\n /**\n * Adjusts the font-size of the code inputs\n */\n @property()\n size: 'sm' | 'md' | 'lg' = 'sm';\n\n /**\n * Number of input characters or digits\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: Boolean })\n disabled = false;\n\n /**\n * Focuses the first input element on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n /**\n * Visually hides `label` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n @state()\n private isFocused = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n get validationTarget() {\n return this.inputElement;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n webOtpApiInit(this.renderRoot);\n }\n\n private handleBoxClick(index: number) {\n if (this.disabled) {\n return;\n }\n\n // Truncate the value to the clicked position\n this.value = this.value.substring(0, index);\n\n // Focus the input to move the caret\n this.focus();\n }\n\n private handleFocus() {\n this.isFocused = true;\n }\n\n private handleBlur() {\n this.isFocused = false;\n }\n\n private handleInput(event: InputEvent) {\n const input = event.target as HTMLInputElement;\n let value = input.value;\n\n if (this.type === 'number') {\n value = value.replace(/[^0-9]/g, '');\n }\n\n value = value.substring(0, this.length);\n\n if (input.value !== value) {\n input.value = value;\n }\n\n // Update the component's public `value` property if it has changed.\n if (this.value !== value) {\n this.value = value;\n this.setValue(value);\n }\n\n this.inputElement.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true }),\n );\n\n if (this.value.length === this.length && this.value.length > 0) {\n this.inputElement.dispatchEvent(\n new Event('mid-complete', { bubbles: true, composed: true }),\n );\n }\n\n }\n\n private handleChange() {\n this.inputElement.dispatchEvent(\n new Event('mid-change', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n if (event.key === 'Enter' && !hasModifier) {\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n setTimeout(() => {\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form?.requestSubmit();\n }\n });\n }\n }\n\n clear() {\n this.value = '';\n this.setValue('');\n this.invalidmessage = '';\n }\n\n resetFormControl() {\n this.clear();\n }\n\n\n focus(options?: FocusOptions): void {\n this.inputElement?.focus(options);\n }\n\n @watch('length')\n handleLengthChange() {\n if (this.value.length > this.length) {\n this.value = this.value.substring(0, this.length);\n }\n }\n\n\n override render() {\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n\n const chars = this.value.split('');\n const displayValues = Array.from(\n { length: this.length },\n (_, i) => chars[i] || '',\n );\n const caretIndex = this.disabled ? -1 : this.value.length;\n\n return html`\n <label\n id=\"${this.labelId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n 'opacity-disabled': this.disabled,\n })} mb-2 block items-center gap-1 font-medium\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n <div\n part=\"input-container\"\n class=\"input-wrapper ${classMap({\n 'text-heading-sm': this.size === 'sm',\n 'text-heading-md': this.size === 'md',\n 'text-heading-lg': this.size === 'lg',\n 'opacity-disabled': this.disabled,\n })}\"\n @click=${() => this.focus()}\n >\n <div part=\"character-boxes\" class=\"character-boxes\">\n ${displayValues.map((char, index) => {\n const hasCaret = this.isFocused && index === caretIndex;\n return html`\n <div\n part=\"character-box\"\n class=\"character-box ${classMap({\n 'border': !this.invalidmessage,\n 'border-2': this.invalidmessage,\n 'border-neutral': !this.invalidmessage,\n 'border-danger': this.invalidmessage,\n 'bg-neutral': !this.invalidmessage,\n 'bg-danger-tinted': this.invalidmessage,\n 'text-neutral-surface-active':\n !char && !this.invalidmessage,\n 'text-danger-surface-active': !char && this.invalidmessage,\n 'character-box--caret': hasCaret,\n 'character-box--empty': !char,\n 'focus-ring-sm': hasCaret,\n })} size-9 rounded-md text-center font-mono\"\n @click=${(e: MouseEvent) => {\n e.stopPropagation();\n this.handleBoxClick(index);\n }}\n >\n ${char || '○'}\n </div>\n `;\n })}\n </div>\n <input\n class=\"hidden-input\"\n .value=\"${live(this.value)}\"\n id=\"mid-code-input-hidden\"\n type=\"${this.type}\"\n aria-labelledby=\"${this.labelId}\"\n maxlength=\"${this.length}\"\n ?autofocus=\"${this.autofocus}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n .pattern=\"${this.pattern}\"\n inputmode=\"${this.inputmode}\"\n autocomplete=\"one-time-code\"\n @input=\"${this.handleInput}\"\n @change=\"${this.handleChange}\"\n @keydown=\"${this.handleKeydown}\"\n @focus=\"${this.handleFocus}\"\n @blur=\"${this.handleBlur}\"\n />\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textfield.component.d.ts","sourceRoot":"","sources":["../../src/components/textfield.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAgBrD,OAAO,0BAA0B,CAAC;AAClC,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,cAAc,CAAC;KACjC;CACF;;AAqBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,cAAe,SAAQ,mBAEnC;IACC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IACzE,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,YAAY,CAAM;IAG1B,KAAK,EAAG,gBAAgB,CAAC;IAGzB,KAAK,SAAM;IAGX,WAAW,SAAM;IAGjB,KAAK,SAAM;IAGX,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAGhC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,YAAY,CAAC,EAAE,QAAQ,CAAC;IAExB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IAEH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IAEH,cAAc,SAAM;IAGpB,IAAI,EACF,MAAM,GACJ,gBAAgB,GAChB,OAAO,GACP,MAAM,GACN,OAAO,GACP,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,MAAM,CAAU;IAEpB;;OAEG;IAEH,SAAS,EACP,MAAM,GACJ,MAAM,GACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,SAAS,GACT,SAAS,CAAU;IAEvB;;SAEK;IAEL,SAAS,UAAS;IAElB;;;OAGG;IAEH,cAAc,UAAS;IAEvB;;;OAGG;IAEH,eAAe,UAAS;IAGxB,QAAQ,UAAS;IAGjB,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;;;;;OAMG;IAEH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAGhB,QAAQ,UAAS;IAEjB,MAAM,KAAK,qBAAqB,qDAO/B;;
|
|
1
|
+
{"version":3,"file":"textfield.component.d.ts","sourceRoot":"","sources":["../../src/components/textfield.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAgBrD,OAAO,0BAA0B,CAAC;AAClC,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,cAAc,CAAC;KACjC;CACF;;AAqBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,cAAe,SAAQ,mBAEnC;IACC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IACzE,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,YAAY,CAAM;IAG1B,KAAK,EAAG,gBAAgB,CAAC;IAGzB,KAAK,SAAM;IAGX,WAAW,SAAM;IAGjB,KAAK,SAAM;IAGX,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAGhC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,YAAY,CAAC,EAAE,QAAQ,CAAC;IAExB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IAEH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IAEH,cAAc,SAAM;IAGpB,IAAI,EACF,MAAM,GACJ,gBAAgB,GAChB,OAAO,GACP,MAAM,GACN,OAAO,GACP,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,MAAM,CAAU;IAEpB;;OAEG;IAEH,SAAS,EACP,MAAM,GACJ,MAAM,GACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,SAAS,GACT,SAAS,CAAU;IAEvB;;SAEK;IAEL,SAAS,UAAS;IAElB;;;OAGG;IAEH,cAAc,UAAS;IAEvB;;;OAGG;IAEH,eAAe,UAAS;IAGxB,QAAQ,UAAS;IAGjB,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;;;;;OAMG;IAEH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAGhB,QAAQ,UAAS;IAEjB,MAAM,KAAK,qBAAqB,qDAO/B;;IAWQ,iBAAiB,IAAI,IAAI;IAKlC,oBAAoB,IAAI,IAAI;IAI5B,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,gBAAgB;IAmBxB,KAAK;IAKL,gBAAgB;IAKhB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAKlC,iBAAiB;IAKX,gBAAgB;IAUb,MAAM;CAiKhB"}
|
|
@@ -65,6 +65,7 @@ let MinidTextfield = class extends FormControlMixin(
|
|
|
65
65
|
this.inputId = `mid-textfield-input-${nextUniqueId}`;
|
|
66
66
|
this.descriptionId = `mid-textfield-description-${nextUniqueId}`;
|
|
67
67
|
this.validationId = `mid-textfield-validation-${nextUniqueId}`;
|
|
68
|
+
this.setValue(this.value);
|
|
68
69
|
}
|
|
69
70
|
static get formControlValidators() {
|
|
70
71
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textfield.js","sources":["../../src/components/textfield.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport { stringConverter } from '../internal/string-converter';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HasSlotController } from '../internal/slot';\nimport { FormControlMixin } from '../mixins/form-control.mixin';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators';\nimport { watch } from '../internal/watch';\nimport './icon/icon.component.ts';\nimport { MaskInput, type MaskType } from 'maska';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-textfield': MinidTextfield;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n \n /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n `,\n];\n\nlet nextUniqueId = 0;\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-clear - Emitted when the input value is cleared\n * @event mid-focus - Emitted when input element is focused\n * @event mid-blur - Emitted when focus moves away from input element\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot prefix - Used for decoration to the left of the input\n * @slot suffix - Used for decoration to the right of the input\n * @slot label - The input's label. Alternatively, you can use the `label` attribute.\n *\n * @csspart base - The input's wrapper that has the input field styling.\n * @csspart input - The internal `<input>` element.\n * @csspart field - The element that wraps the label, input, and help text.\n * @csspart clear-button - The clear button\n * @csspart password-toggle-button - The button for toggling password visibility\n */\n@customElement('mid-textfield')\nexport class MinidTextfield extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly inputId!: string;\n private readonly descriptionId!: string;\n private readonly validationId!: string;\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private inputMask?: MaskInput;\n private initialValue = '';\n\n @query('.input')\n input!: HTMLInputElement;\n\n @property()\n label = '';\n\n @property()\n description = '';\n\n @property()\n value = '';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ converter: stringConverter })\n placeholder?: string;\n\n /**\n * Autofocus the input field on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * User agent autocomplete hint\n */\n @property()\n autocomplete?: AutoFill;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * The maximum length of input that will be considered valid.\n */\n @property({ type: Number })\n maxlength?: number;\n\n /**\n * The input's minimum value. Only applies to date and number input types.\n */\n @property()\n min?: number | string;\n\n /**\n * The input's maximum value. Only applies to date and number input types.\n */\n @property()\n max?: number | string;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n @property()\n type:\n 'date'\n | 'datetime-local'\n | 'email'\n | 'file'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week' = 'text';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode:\n 'none'\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'numeric'\n | 'decimal' = 'text';\n\n /**\n * Adds a clear button when the input is not empty.\n * */\n @property({ type: Boolean })\n clearable = false;\n\n /**\n * Adds a button to toggle the password's visibility.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordtoggle = false;\n\n /**\n * Determines wether the password is currently visible.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordvisible = false;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * Visually hides `label` and `description` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Modify input value based on mask e.g: `\"##:##\"` = 12:34.\n * `#`: /[0-9]/\n * `@`: /[a-zA-Z]/\n * `*`: /[a-zA-Z0-9]/\n * For more information go to https://beholdr.github.io/maska\n */\n @property()\n mask?: MaskType;\n\n @state()\n hasFocus = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n constructor() {\n super();\n nextUniqueId++;\n this.inputId = `mid-textfield-input-${nextUniqueId}`;\n this.descriptionId = `mid-textfield-description-${nextUniqueId}`;\n this.validationId = `mid-textfield-validation-${nextUniqueId}`;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.initialValue = this.value;\n }\n\n disconnectedCallback(): void {\n this.inputMask?.destroy();\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\n //\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form.requestSubmit();\n }\n });\n }\n }\n\n private handleBlur() {\n this.hasFocus = false;\n this.dispatchEvent(\n new Event('mid-blur', { bubbles: true, composed: true })\n );\n }\n\n private handleChange() {\n this.value = this.input.value;\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n }\n\n private handleInput() {\n let tmp_value = this.input.value;\n\n if (this.type === 'number') {\n tmp_value = tmp_value.replace(/[^0-9]/g, '');\n }\n\n this.value = tmp_value;\n this.setValue(this.value);\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n\n private handleFocus() {\n this.hasFocus = true;\n this.dispatchEvent(\n new Event('mid-focus', { composed: true, bubbles: true })\n );\n }\n\n private handlePasswordToggle() {\n this.passwordvisible = !this.passwordvisible;\n }\n\n private handleClearClick(event: MouseEvent) {\n event.preventDefault();\n\n if (this.value !== '') {\n this.value = '';\n this.dispatchEvent(\n new Event('mid-clear', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-change', { composed: true, bubbles: true })\n );\n }\n\n this.input.focus();\n }\n\n focus() {\n this.hasFocus = true;\n this.input.focus();\n }\n\n resetFormControl() {\n this.invalidmessage = '';\n this.value = this.initialValue;\n }\n\n forceError(message?: string): void {\n super.forceError(message);\n }\n\n @watch('value')\n handleValueUpdate() {\n this.setValue(this.value);\n }\n\n @watch('mask')\n async handleMaskUpdate() {\n if (!this.mask) return;\n await this.updateComplete;\n this.inputMask?.destroy();\n this.inputMask = new MaskInput(this.input, {\n mask: this.mask,\n eager: true,\n });\n }\n\n override render() {\n const lg = this.size === 'lg';\n const md = this.size === 'md';\n const sm = this.size === 'sm';\n\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasClearIcon = this.clearable && !this.disabled && !this.readonly;\n const isClearIconVisible =\n hasClearIcon && (typeof this.value === 'number' || this.value.length > 0);\n\n return html`\n <div\n part=\"field\"\n class=\"${classMap({\n 'opacity-disabled': this.disabled,\n 'text-body-sm': sm,\n 'text-body-md': md,\n 'text-body-lg': lg,\n })} max-w-full\"\n >\n <label\n for=\"${this.inputId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n })} mb-2 inline-flex items-center gap-1 font-medium\"\n >\n ${this.readonly\n ? html`<mid-icon\n class=\"size-5\"\n library=\"system\"\n name=\"padlock-locked-fill\"\n ></mid-icon>`\n : nothing}\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${this.description\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n })} text-neutral-subtle mb-2\"\n >\n ${this.description}\n </div>\n `\n : nothing}\n <div\n part=\"base\"\n class=\"${classMap({\n 'border-neutral': !this.invalidmessage && !this.readonly,\n 'border-danger': this.invalidmessage && !this.readonly,\n 'border-neutral-subtle': this.readonly,\n 'bg-neutral-surface-tinted': this.readonly,\n 'bg-neutral-surface': !this.readonly,\n border: !this.invalidmessage,\n 'border-2': this.invalidmessage,\n })} focus-within:focus-ring flex h-12 items-center rounded-md px-3\"\n >\n <span class=\"slotted:!mr-2 slotted:rounded flex items-center\">\n <slot name=\"prefix\"></slot>\n </span>\n <input\n id=\"${this.inputId}\"\n class=\"${classMap({\n 'w-full': !isClearIconVisible,\n 'w-[calc(100%-var(--spacing)*7)]': isClearIconVisible,\n '[&::-webkit-search-cancel-button]:appearance-none':\n this.type === 'search',\n })} input grow overflow-clip focus-visible:outline-0\"\n part=\"input\"\n .value=${live(this.value)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?autofocus=${this.autofocus}\n autocomplete=${ifDefined(this.autocomplete as any)}\n type=${this.type === 'password' && this.passwordvisible\n ? 'text'\n : this.type}\n aria-describedby=\"${ifDefined(\n (this.description && this.descriptionId) || undefined\n )}\"\n aria-errormessage=\"${this.validationId}\"\n placeholder=${ifDefined(this.placeholder)}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n pattern=${ifDefined(this.pattern)}\n @input=${this.handleInput}\n @change=${this.handleChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n @keydown=${this.handleKeydown}\n />\n ${isClearIconVisible\n ? html`\n <button\n part=\"clear-button\"\n type=\"button\"\n class=\"focus-visible:focus-ring ml-2 flex items-center justify-center rounded-sm\"\n aria-label=\"Tøm\"\n @click=${this.handleClearClick}\n >\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"xmark\"\n ></mid-icon>\n </button>\n `\n : ''}\n ${this.passwordtoggle && !this.disabled\n ? html`\n <button\n part=\"password-toggle-button\"\n type=\"button\"\n class=\"ml-2 flex items-center justify-center rounded-sm\"\n aria-label=${this.passwordvisible\n ? 'skjul passord'\n : 'vis passord'}\n @click=${this.handlePasswordToggle}\n tabindex=\"-1\"\n >\n ${this.passwordvisible\n ? html` <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye-slash\"\n ></mid-icon>`\n : html`\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye\"\n ></mid-icon>\n `}\n </button>\n `\n : ''}\n <span part=\"suffix\" class=\"slotted:!ml-2 slotted:rounded\">\n <slot name=\"suffix\"></slot>\n </span>\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textfield.js","sources":["../../src/components/textfield.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport { stringConverter } from '../internal/string-converter';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HasSlotController } from '../internal/slot';\nimport { FormControlMixin } from '../mixins/form-control.mixin';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators';\nimport { watch } from '../internal/watch';\nimport './icon/icon.component.ts';\nimport { MaskInput, type MaskType } from 'maska';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-textfield': MinidTextfield;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n \n /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n `,\n];\n\nlet nextUniqueId = 0;\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-clear - Emitted when the input value is cleared\n * @event mid-focus - Emitted when input element is focused\n * @event mid-blur - Emitted when focus moves away from input element\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot prefix - Used for decoration to the left of the input\n * @slot suffix - Used for decoration to the right of the input\n * @slot label - The input's label. Alternatively, you can use the `label` attribute.\n *\n * @csspart base - The input's wrapper that has the input field styling.\n * @csspart input - The internal `<input>` element.\n * @csspart field - The element that wraps the label, input, and help text.\n * @csspart clear-button - The clear button\n * @csspart password-toggle-button - The button for toggling password visibility\n */\n@customElement('mid-textfield')\nexport class MinidTextfield extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly inputId!: string;\n private readonly descriptionId!: string;\n private readonly validationId!: string;\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private inputMask?: MaskInput;\n private initialValue = '';\n\n @query('.input')\n input!: HTMLInputElement;\n\n @property()\n label = '';\n\n @property()\n description = '';\n\n @property()\n value = '';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ converter: stringConverter })\n placeholder?: string;\n\n /**\n * Autofocus the input field on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * User agent autocomplete hint\n */\n @property()\n autocomplete?: AutoFill;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * The maximum length of input that will be considered valid.\n */\n @property({ type: Number })\n maxlength?: number;\n\n /**\n * The input's minimum value. Only applies to date and number input types.\n */\n @property()\n min?: number | string;\n\n /**\n * The input's maximum value. Only applies to date and number input types.\n */\n @property()\n max?: number | string;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n @property()\n type:\n 'date'\n | 'datetime-local'\n | 'email'\n | 'file'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week' = 'text';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode:\n 'none'\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'numeric'\n | 'decimal' = 'text';\n\n /**\n * Adds a clear button when the input is not empty.\n * */\n @property({ type: Boolean })\n clearable = false;\n\n /**\n * Adds a button to toggle the password's visibility.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordtoggle = false;\n\n /**\n * Determines wether the password is currently visible.\n * Only applies if type is password\n */\n @property({ type: Boolean })\n passwordvisible = false;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * Visually hides `label` and `description` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Modify input value based on mask e.g: `\"##:##\"` = 12:34.\n * `#`: /[0-9]/\n * `@`: /[a-zA-Z]/\n * `*`: /[a-zA-Z0-9]/\n * For more information go to https://beholdr.github.io/maska\n */\n @property()\n mask?: MaskType;\n\n @state()\n hasFocus = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n constructor() {\n super();\n nextUniqueId++;\n this.inputId = `mid-textfield-input-${nextUniqueId}`;\n this.descriptionId = `mid-textfield-description-${nextUniqueId}`;\n this.validationId = `mid-textfield-validation-${nextUniqueId}`;\n this.setValue(this.value);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.initialValue = this.value;\n }\n\n disconnectedCallback(): void {\n this.inputMask?.destroy();\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\n //\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form.requestSubmit();\n }\n });\n }\n }\n\n private handleBlur() {\n this.hasFocus = false;\n this.dispatchEvent(\n new Event('mid-blur', { bubbles: true, composed: true })\n );\n }\n\n private handleChange() {\n this.value = this.input.value;\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n }\n\n private handleInput() {\n let tmp_value = this.input.value;\n\n if (this.type === 'number') {\n tmp_value = tmp_value.replace(/[^0-9]/g, '');\n }\n\n this.value = tmp_value;\n this.setValue(this.value);\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n\n private handleFocus() {\n this.hasFocus = true;\n this.dispatchEvent(\n new Event('mid-focus', { composed: true, bubbles: true })\n );\n }\n\n private handlePasswordToggle() {\n this.passwordvisible = !this.passwordvisible;\n }\n\n private handleClearClick(event: MouseEvent) {\n event.preventDefault();\n\n if (this.value !== '') {\n this.value = '';\n this.dispatchEvent(\n new Event('mid-clear', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { composed: true, bubbles: true })\n );\n this.dispatchEvent(\n new Event('mid-change', { composed: true, bubbles: true })\n );\n }\n\n this.input.focus();\n }\n\n focus() {\n this.hasFocus = true;\n this.input.focus();\n }\n\n resetFormControl() {\n this.invalidmessage = '';\n this.value = this.initialValue;\n }\n\n forceError(message?: string): void {\n super.forceError(message);\n }\n\n @watch('value')\n handleValueUpdate() {\n this.setValue(this.value);\n }\n\n @watch('mask')\n async handleMaskUpdate() {\n if (!this.mask) return;\n await this.updateComplete;\n this.inputMask?.destroy();\n this.inputMask = new MaskInput(this.input, {\n mask: this.mask,\n eager: true,\n });\n }\n\n override render() {\n const lg = this.size === 'lg';\n const md = this.size === 'md';\n const sm = this.size === 'sm';\n\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n const hasClearIcon = this.clearable && !this.disabled && !this.readonly;\n const isClearIconVisible =\n hasClearIcon && (typeof this.value === 'number' || this.value.length > 0);\n\n return html`\n <div\n part=\"field\"\n class=\"${classMap({\n 'opacity-disabled': this.disabled,\n 'text-body-sm': sm,\n 'text-body-md': md,\n 'text-body-lg': lg,\n })} max-w-full\"\n >\n <label\n for=\"${this.inputId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n })} mb-2 inline-flex items-center gap-1 font-medium\"\n >\n ${this.readonly\n ? html`<mid-icon\n class=\"size-5\"\n library=\"system\"\n name=\"padlock-locked-fill\"\n ></mid-icon>`\n : nothing}\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n ${this.description\n ? html`\n <div\n id=\"${this.descriptionId}\"\n part=\"description\"\n class=\"${classMap({\n 'sr-only': this.hidelabel,\n })} text-neutral-subtle mb-2\"\n >\n ${this.description}\n </div>\n `\n : nothing}\n <div\n part=\"base\"\n class=\"${classMap({\n 'border-neutral': !this.invalidmessage && !this.readonly,\n 'border-danger': this.invalidmessage && !this.readonly,\n 'border-neutral-subtle': this.readonly,\n 'bg-neutral-surface-tinted': this.readonly,\n 'bg-neutral-surface': !this.readonly,\n border: !this.invalidmessage,\n 'border-2': this.invalidmessage,\n })} focus-within:focus-ring flex h-12 items-center rounded-md px-3\"\n >\n <span class=\"slotted:!mr-2 slotted:rounded flex items-center\">\n <slot name=\"prefix\"></slot>\n </span>\n <input\n id=\"${this.inputId}\"\n class=\"${classMap({\n 'w-full': !isClearIconVisible,\n 'w-[calc(100%-var(--spacing)*7)]': isClearIconVisible,\n '[&::-webkit-search-cancel-button]:appearance-none':\n this.type === 'search',\n })} input grow overflow-clip focus-visible:outline-0\"\n part=\"input\"\n .value=${live(this.value)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?autofocus=${this.autofocus}\n autocomplete=${ifDefined(this.autocomplete as any)}\n type=${this.type === 'password' && this.passwordvisible\n ? 'text'\n : this.type}\n aria-describedby=\"${ifDefined(\n (this.description && this.descriptionId) || undefined\n )}\"\n aria-errormessage=\"${this.validationId}\"\n placeholder=${ifDefined(this.placeholder)}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n pattern=${ifDefined(this.pattern)}\n @input=${this.handleInput}\n @change=${this.handleChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n @keydown=${this.handleKeydown}\n />\n ${isClearIconVisible\n ? html`\n <button\n part=\"clear-button\"\n type=\"button\"\n class=\"focus-visible:focus-ring ml-2 flex items-center justify-center rounded-sm\"\n aria-label=\"Tøm\"\n @click=${this.handleClearClick}\n >\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"xmark\"\n ></mid-icon>\n </button>\n `\n : ''}\n ${this.passwordtoggle && !this.disabled\n ? html`\n <button\n part=\"password-toggle-button\"\n type=\"button\"\n class=\"ml-2 flex items-center justify-center rounded-sm\"\n aria-label=${this.passwordvisible\n ? 'skjul passord'\n : 'vis passord'}\n @click=${this.handlePasswordToggle}\n tabindex=\"-1\"\n >\n ${this.passwordvisible\n ? html` <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye-slash\"\n ></mid-icon>`\n : html`\n <mid-icon\n class=\"size-7\"\n library=\"system\"\n name=\"eye\"\n ></mid-icon>\n `}\n </button>\n `\n : ''}\n <span part=\"suffix\" class=\"slotted:!ml-2 slotted:rounded\">\n <slot name=\"suffix\"></slot>\n </span>\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-control.mixin.d.ts","sourceRoot":"","sources":["../../src/mixins/form-control.mixin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAO9D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,SAAS,WAAW,CAAC,UAAU,GAAG,YAAY,CAAC,GAAG;IACrD,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,EACD,UAAU,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"form-control.mixin.d.ts","sourceRoot":"","sources":["../../src/mixins/form-control.mixin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAO9D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,SAAS,WAAW,CAAC,UAAU,GAAG,YAAY,CAAC,GAAG;IACrD,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,EACD,UAAU,EAAE,KAAK,GAwmBgB,WAAW,CAAC,oBAAoB,CAAC,GAAG,KAAK,CAC3E"}
|
|
@@ -39,7 +39,6 @@ function FormControlMixin(SuperClass) {
|
|
|
39
39
|
__privateSet(this, _awaitingValidationTarget, true);
|
|
40
40
|
__privateSet(this, _value, "");
|
|
41
41
|
__privateSet(this, _onFocus, () => {
|
|
42
|
-
__privateSet(this, _touched, true);
|
|
43
42
|
__privateSet(this, _focused, true);
|
|
44
43
|
__privateMethod(this, _FormControl_instances, shouldShowError_fn).call(this);
|
|
45
44
|
});
|
|
@@ -184,11 +183,14 @@ function FormControlMixin(SuperClass) {
|
|
|
184
183
|
/** PUBLIC LIFECYCLE METHODS */
|
|
185
184
|
/**
|
|
186
185
|
* Sets the control's form value if the call to `shouldFormValueUpdate`
|
|
187
|
-
* returns `true`.
|
|
186
|
+
* returns `true`. Set this[touch] if connected and value changed.
|
|
188
187
|
* @param value {FormValue} - The value to pass to the form
|
|
189
188
|
* @ignore
|
|
190
189
|
*/
|
|
191
190
|
setValue(value) {
|
|
191
|
+
if (this.isConnected && __privateGet(this, _value) !== value) {
|
|
192
|
+
__privateSet(this, _touched, true);
|
|
193
|
+
}
|
|
192
194
|
__privateSet(this, _forceError, false);
|
|
193
195
|
this.validationMessageCallback?.("");
|
|
194
196
|
__privateSet(this, _value, value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-control.mixin.js","sources":["../../src/mixins/form-control.mixin.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport type { IControlHost } from '../types/control-host';\nimport type { FormControlInterface } from '../types/form-control';\nimport type { FormValue } from '../types/form-value';\nimport type { Constructor } from '../types/mixin-constructor';\nimport type {\n CustomValidityState,\n validationMessageCallback,\n Validator,\n} from '../types/validator.type';\n\n/**\n *\n * https://github.com/open-wc/form-participation/tree/main/packages/form-control\n */\nexport function FormControlMixin<\n TBase extends Constructor<LitElement & IControlHost> & {\n observedAttributes?: string[];\n },\n>(SuperClass: TBase) {\n class FormControl extends SuperClass {\n /**\n * Wires up control instances to be form associated\n * @ignore\n */\n static get formAssociated(): boolean {\n return true;\n }\n\n /**\n * A list of Validator objects that will be evaluated when a control's form\n * value is modified or optionally when a given attribute changes.\n *\n * When a Validator's callback returns false, the entire form control will\n * be set to an invalid state.\n * @ignore\n */\n declare static formControlValidators: Validator[];\n\n /**\n * If set to true the control described should be evaluated and validated\n * as part of a group. Like a radio, if any member of the group's validity\n * changes the the other members should update as well.\n * @ignore\n */\n declare static formControlValidationGroup: boolean;\n\n /**\n * @ignore\n */\n private static get validators(): Validator[] {\n return this.formControlValidators || [];\n }\n\n /**\n * Allows the FormControl instance to respond to Validator attributes.\n * For instance, if a given Validator has a `required` attribute, that\n * validator will be evaluated whenever the host's required attribute\n * is updated.\n * @ignore\n */\n static get observedAttributes(): string[] {\n const validatorAttributes = this.validators\n .map((validator) => validator.attribute)\n .flat();\n\n const observedAttributes = super.observedAttributes || [];\n\n /** Make sure there are no duplicates inside the attributes list */\n const attributeSet = new Set([\n ...observedAttributes,\n ...validatorAttributes,\n ]);\n return [...attributeSet] as string[];\n }\n\n /**\n * Return the validator associated with a given attribute. If no\n * Validator is associated with the attribute, it will return null.\n * @ignore\n */\n static getValidator(attribute: string): Validator | null {\n return (\n this.validators.find(\n (validator) => validator.attribute === attribute\n ) || null\n );\n }\n\n /**\n * Get all validators that are set to react to a given attribute\n * @param {string} attribute - The attribute that has changed\n * @returns {Validator[]}\n * @ignore\n */\n static getValidators(attribute: string): Validator[] | null {\n return this.validators.filter((validator) => {\n if (\n validator.attribute === attribute ||\n validator.attribute?.includes(attribute)\n ) {\n return true;\n }\n });\n }\n\n /**\n * The ElementInternals instance for the control.\n * @ignore\n */\n internals = this.attachInternals();\n\n /**\n * Keep track of if the control has focus\n * @private\n * @ignore\n */\n #focused = false;\n\n /**\n * Exists to control when an error should be displayed\n * @private\n * @ignore\n */\n #forceError = false;\n\n /**\n * Toggles to true whenever the element has been focused. This property\n * will reset whenever the control's formResetCallback is called.\n * @private\n * @ignore\n */\n #touched = false;\n\n /**\n * An internal abort controller for cancelling pending async validation\n * @ignore\n */\n #abortController?: AbortController;\n\n /**\n * Used for tracking if a validation target has been set to manage focus\n * when the control's validity is reported\n * @ignore\n */\n #awaitingValidationTarget = true;\n\n /**\n * Acts as a cache for the current value so the value can be re-evaluated\n * whenever an attribute changes or on some other event.\n * @ignore\n */\n #value: FormValue = '';\n\n /**\n * Set this[touched] and this[focused]\n * to true when the element is focused\n * @private\n * @ignore\n */\n #onFocus = (): void => {\n this.#touched = true;\n this.#focused = true;\n this.#shouldShowError();\n };\n\n /**\n * Reset this[focused] on blur\n * @private\n * @ignore\n */\n #onBlur = (): void => {\n this.#focused = false;\n\n this.#runValidators(this.shouldFormValueUpdate() ? this.#value : '');\n\n /**\n * Set forceError to ensure error messages persist until\n * the value is changed.\n */\n if (!this.validity.valid && this.#touched) {\n this.#forceError = true;\n }\n const showError = this.#shouldShowError();\n\n if (this.validationMessageCallback) {\n this.validationMessageCallback(showError ? this.validationMessage : '');\n }\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * For the show error state on invalid\n * @private\n * @ignore\n */\n #onInvalid = (event?: Event): void => {\n event?.preventDefault();\n event?.stopImmediatePropagation();\n\n if (this.#awaitingValidationTarget && this.validationTarget) {\n this.internals.setValidity(\n this.validity,\n this.validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n }\n this.#touched = true;\n this.#forceError = true;\n const showError = this.#shouldShowError();\n this?.validationMessageCallback?.(\n showError ? this.validationMessage : ''\n );\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * Return a reference to the control's form\n * @ignore\n */\n get form(): HTMLFormElement {\n return this.internals.form as HTMLFormElement;\n }\n\n /**\n * Will return true if it is recommended that the control shows an internal\n * error. If using this property, it is wise to listen for 'invalid' events\n * on the element host and call preventDefault on the event. Doing this will\n * prevent browsers from showing a validation popup.\n * @ignore\n */\n get showError(): boolean {\n return this.#shouldShowError();\n }\n\n /**\n * Forward the internals checkValidity method\n * will return the valid state of the control.\n * @ignore\n */\n checkValidity(): boolean {\n return this.internals.checkValidity();\n }\n\n /**\n * The element's validity state\n * @ignore\n */\n get validity(): ValidityState {\n return this.internals.validity;\n }\n\n /**\n * The validation message shown by a given Validator object. If the control\n * is in a valid state this should be falsy.\n * @ignore\n */\n get validationMessage(): string {\n return this.internals.validationMessage;\n }\n\n constructor(...args: any[]) {\n super(...args);\n this.addEventListener?.('focus', this.#onFocus);\n this.addEventListener?.('blur', this.#onBlur);\n this.addEventListener?.('invalid', this.#onInvalid);\n this.setValue(null);\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string,\n newValue: string\n ): void {\n super.attributeChangedCallback?.(name, oldValue, newValue);\n\n /**\n * Check to see if a Validator is associated with the changed attribute.\n * If one exists, call control's validate function which will perform\n * control validation.\n * @ignore\n */\n const proto = this.constructor as typeof FormControl;\n const validators = proto.getValidators(name);\n\n if (validators?.length && this.validationTarget) {\n this.setValue(this.#value);\n }\n }\n\n /** PUBLIC LIFECYCLE METHODS */\n\n /**\n * Sets the control's form value if the call to `shouldFormValueUpdate`\n * returns `true`.\n * @param value {FormValue} - The value to pass to the form\n * @ignore\n */\n setValue(value: FormValue): void {\n this.#forceError = false;\n this.validationMessageCallback?.('');\n this.#value = value;\n const valueShouldUpdate = this.shouldFormValueUpdate();\n const valueToUpdate = valueShouldUpdate ? value : null;\n this.internals.setFormValue(valueToUpdate as string);\n this.#runValidators(valueToUpdate);\n if (this.valueChangedCallback) {\n this.valueChangedCallback(valueToUpdate);\n }\n const showError = this.#shouldShowError();\n this.#dispatchInvalidEvent(showError);\n }\n\n /**\n * Forces the control to show an error state. If a message is passed in,\n * it will be set as the control's internal validity state message.\n * @param message { string | undefined } - The message for internals validity state\n */\n forceError(message?: string) {\n if (message) {\n this.#setValidityWithOptionalTarget({ customError: true }, message);\n }\n this.#forceError = true;\n this.#shouldShowError();\n }\n\n /**\n * This method can be overridden to determine if the control's form value\n * should be set on a call to `setValue`. An example of when a user might want\n * to skip this step is when implementing checkbox-like behavior, first checking\n * to see if `this.checked` is set to a truthy value. By default this returns\n * `true`.\n * @ignore\n */\n shouldFormValueUpdate(): boolean {\n return true;\n }\n\n /**\n * Save a reference to the validation complete resolver\n * @ignore\n */\n #validationCompleteResolver?: (value: void | PromiseLike<void>) => void;\n\n /**\n * When true validation will be pending\n * @ignore\n */\n #isValidationPending = false;\n\n /**\n * @ignore\n */\n #validationComplete = Promise.resolve();\n\n /**\n * A promise that will resolve when all pending validations are complete\n * @ignore\n */\n get validationComplete(): Promise<void> {\n return new Promise((resolve) => resolve(this.#validationComplete));\n }\n\n /** DECLARED INSTANCE METHODS AND PROPERTIES*/\n\n /**\n * Resets a form control to its initial state\n * @ignore\n */\n declare resetFormControl: () => void;\n\n /**\n * This method is used to override the controls' validity message\n * for a given Validator key. This has the highest level of priority when\n * setting a validationMessage, so use this method wisely.\n *\n * The returned value will be used as the validationMessage for the given key.\n * @param validationKey {string} - The key that has returned invalid\n * @ignore\n */\n declare validityCallback: (validationKey: string) => string | void;\n\n /**\n * Called when the control's validationMessage should be changed\n * @param message { string } - The new validation message\n * @ignore\n */\n declare validationMessageCallback: (message: string) => void;\n\n /**\n * A callback for when the controls' form value changes. The value\n * passed to this function should not be confused with the control's\n * value property, this is the value that will appear on the form.\n *\n * In cases where `checked` did not exist on the control's prototype\n * upon initialization, this value and the value property will be identical;\n * in cases where `checked` is present upon initialization, this will be\n * effectively `this.checked && this.value`.\n * @ignore\n */\n declare valueChangedCallback: (value: FormValue) => void;\n\n /**\n * The element that will receive focus when the control's validity\n * state is reported either by a form submission or via API\n *\n * We use declare since this is optional and we don't particularly\n * care how the consuming component implements this (as a field, member\n * or getter/setter)\n * @ignore\n */\n declare validationTarget: HTMLElement | null;\n\n /** PRIVATE LIFECYCLE METHODS */\n\n /**\n * Check to see if an error should be shown. This method will also\n * update the internals state object with the --show-error state\n * if necessary.\n * @private\n * @ignore\n */\n #shouldShowError(): boolean {\n if (this.hasAttribute('disabled')) {\n return false;\n }\n\n const showError =\n this.#forceError ||\n (this.#touched && !this.validity.valid && !this.#focused);\n\n if (showError && this.internals.states) {\n this.internals.states.add('--show-error');\n this.internals.states.add('--invalid');\n } else if (this.internals.states) {\n this.internals.states.delete('--show-error');\n this.internals.states.delete('--invalid');\n }\n\n return showError;\n }\n\n #runValidators(value: FormValue): void {\n const proto = this.constructor as typeof FormControl;\n const validity: CustomValidityState = {};\n const validators = proto.validators;\n const asyncValidators: Promise<boolean | void>[] = [];\n const hasAsyncValidators = validators.some(\n (validator) => validator.isValid instanceof Promise\n );\n\n if (!this.#isValidationPending) {\n this.#validationComplete = new Promise((resolve) => {\n this.#validationCompleteResolver = resolve;\n });\n this.#isValidationPending = true;\n }\n\n /**\n * If an abort controller exists from a previous validation step\n * notify still-running async validators that we are requesting they\n * discontinue any work.\n */\n if (this.#abortController) {\n this.#abortController.abort();\n }\n\n /**\n * Create a new abort controller and replace the instance reference\n * so we can clean it up for next time\n */\n const abortController = new AbortController();\n this.#abortController = abortController;\n let validationMessage: string | undefined = undefined;\n\n /** Track to see if any validity key has changed */\n let hasChange = false;\n\n if (!validators.length) {\n return;\n }\n\n validators.forEach((validator) => {\n const key = validator.key || 'customError';\n const isValid = validator.isValid(this, value, abortController.signal);\n const isAsyncValidator = isValid instanceof Promise;\n\n if (isAsyncValidator) {\n asyncValidators.push(isValid);\n\n isValid.then((isValidatorValid) => {\n if (isValidatorValid === undefined || isValidatorValid === null) {\n return;\n }\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValidatorValid;\n\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n });\n } else {\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValid;\n\n if (this.validity[key] !== !isValid) {\n hasChange = true;\n }\n\n // only update the validationMessage for the first invalid scenario\n // so that earlier invalid validators dont get their messages overwritten by later ones\n // in the validators array\n if (!isValid && !validationMessage) {\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n }\n }\n });\n\n /** Once all the async validators have settled, resolve validationComplete */\n Promise.allSettled(asyncValidators).then(() => {\n /** Don't resolve validations if the signal is aborted */\n if (!abortController?.signal.aborted) {\n this.#isValidationPending = false;\n this.#validationCompleteResolver?.();\n }\n });\n\n /**\n * If async validators are present:\n * Only run updates when a sync validator has a change. This is to prevent\n * situations where running sync validators can override async validators\n * that are still in progress\n *\n * If async validators are not present, always update validity\n */\n if (hasChange || !hasAsyncValidators) {\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n }\n }\n\n /**\n * If the validationTarget is not set, the user can decide how they would\n * prefer to handle focus when the field is validated.\n * @ignore\n */\n #setValidityWithOptionalTarget(\n validity: Partial<ValidityState>,\n validationMessage: string | undefined\n ): void {\n if (this.validationTarget) {\n this.internals.setValidity(\n validity,\n validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n } else {\n this.internals.setValidity(validity, validationMessage);\n\n if (this.internals.validity.valid) {\n return;\n }\n\n /**\n * Sets mark the component as awaiting a validation target\n * if the element dispatches an invalid event, the #onInvalid listener\n * will check to see if the validation target has been set since this call\n * has run. This useful in cases like Lit's use of the query\n * decorator for setting the validationTarget or any scenario\n * where the validationTarget isn't available upon construction\n */\n this.#awaitingValidationTarget = true;\n }\n }\n\n /**\n * Process the validator message attribute\n * @ignore\n */\n #getValidatorMessageForValue(\n validator: Validator,\n value: FormValue\n ): string {\n /** If the validity callback exists and returns, use that as the result */\n\n if (this.validityCallback) {\n const message = this.validityCallback(validator.key || 'customError');\n\n if (message) {\n return message;\n }\n }\n\n if (validator.message instanceof Function) {\n return (validator.message as validationMessageCallback)(this, value);\n } else {\n return validator.message as string;\n }\n }\n\n /**\n * Reset control state when the form is reset\n */\n formResetCallback() {\n this.#touched = false;\n this.#forceError = false;\n this.#shouldShowError();\n this.resetFormControl?.();\n const showError = this.#shouldShowError();\n this.validationMessageCallback?.(showError ? this.validationMessage : '');\n this.#dispatchInvalidEvent(showError);\n }\n\n #dispatchInvalidEvent(showError: boolean) {\n const event = showError ? 'mid-invalid-show' : 'mid-invalid-hide';\n this.dispatchEvent(\n new CustomEvent(event, {\n bubbles: true,\n composed: true,\n detail: {\n validity: this.validity,\n },\n })\n );\n }\n }\n\n return FormControl as unknown as Constructor<FormControlInterface> & TBase;\n}\n"],"names":[],"mappings":";;;;;;;;AAeO,SAAS,iBAId,YAAmB;AAJd;AAAA,EAKL,MAAM,oBAAoB,WAAW;AAAA,IAkPnC,eAAe,MAAa;AAC1B,YAAM,GAAG,IAAI;AAnPjB;AAiGE;AAOA;AAQA;AAMA;AAAA;AAAA;AAAA;AAAA;AAOA;AAOA;AAQA;AAWA;AAyBA;AAmJA;AAAA;AAAA;AAAA;AAAA;AAMA;AAKA;AApPA,WAAA,YAAY,KAAK,gBAAA;AAOjB,yBAAA,UAAW;AAOX,yBAAA,aAAc;AAQd,yBAAA,UAAW;AAaX,yBAAA,2BAA4B;AAO5B,yBAAA,QAAoB;AAQpB,yBAAA,UAAW,MAAY;AACrB,2BAAK,UAAW;AAChB,2BAAK,UAAW;AAChB,8BAAK,4CAAL;AAAA,MACF;AAOA,yBAAA,SAAU,MAAY;AACpB,2BAAK,UAAW;AAEhB,8BAAK,0CAAL,WAAoB,KAAK,sBAAA,IAA0B,mBAAK,UAAS;AAMjE,YAAI,CAAC,KAAK,SAAS,SAAS,mBAAK,WAAU;AACzC,6BAAK,aAAc;AAAA,QACrB;AACA,cAAM,YAAY,sBAAK,4CAAL;AAElB,YAAI,KAAK,2BAA2B;AAClC,eAAK,0BAA0B,YAAY,KAAK,oBAAoB,EAAE;AAAA,QACxE;AACA,8BAAK,iDAAL,WAA2B;AAAA,MAC7B;AAOA,yBAAA,YAAa,CAAC,UAAwB;AACpC,eAAO,eAAA;AACP,eAAO,yBAAA;AAEP,YAAI,mBAAK,8BAA6B,KAAK,kBAAkB;AAC3D,eAAK,UAAU;AAAA,YACb,KAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AAAA,UAAA;AAEP,6BAAK,2BAA4B;AAAA,QACnC;AACA,2BAAK,UAAW;AAChB,2BAAK,aAAc;AACnB,cAAM,YAAY,sBAAK,4CAAL;AAClB,cAAM;AAAA,UACJ,YAAY,KAAK,oBAAoB;AAAA,QAAA;AAEvC,8BAAK,iDAAL,WAA2B;AAAA,MAC7B;AAsIA,yBAAA,sBAAuB;AAKvB,yBAAA,qBAAsB,QAAQ,QAAA;AA1F5B,WAAK,mBAAmB,SAAS,mBAAK,SAAQ;AAC9C,WAAK,mBAAmB,QAAQ,mBAAK,QAAO;AAC5C,WAAK,mBAAmB,WAAW,mBAAK,WAAU;AAClD,WAAK,SAAS,IAAI;AAAA,IACpB;AAAA;AAAA;AAAA;AAAA;AAAA,IAnPA,WAAW,iBAA0B;AACnC,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAuBA,WAAmB,aAA0B;AAC3C,aAAO,KAAK,yBAAyB,CAAA;AAAA,IACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,WAAW,qBAA+B;AACxC,YAAM,sBAAsB,KAAK,WAC9B,IAAI,CAAC,cAAc,UAAU,SAAS,EACtC,KAAA;AAEH,YAAM,qBAAqB,MAAM,sBAAsB,CAAA;AAGvD,YAAM,mCAAmB,IAAI;AAAA,QAC3B,GAAG;AAAA,QACH,GAAG;AAAA,MAAA,CACJ;AACD,aAAO,CAAC,GAAG,YAAY;AAAA,IACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,OAAO,aAAa,WAAqC;AACvD,aACE,KAAK,WAAW;AAAA,QACd,CAAC,cAAc,UAAU,cAAc;AAAA,MAAA,KACpC;AAAA,IAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,OAAO,cAAc,WAAuC;AAC1D,aAAO,KAAK,WAAW,OAAO,CAAC,cAAc;AAC3C,YACE,UAAU,cAAc,aACxB,UAAU,WAAW,SAAS,SAAS,GACvC;AACA,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,IAqHA,IAAI,OAAwB;AAC1B,aAAO,KAAK,UAAU;AAAA,IACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,IAAI,YAAqB;AACvB,aAAO,sBAAK,4CAAL;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,gBAAyB;AACvB,aAAO,KAAK,UAAU,cAAA;AAAA,IACxB;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,IAAI,WAA0B;AAC5B,aAAO,KAAK,UAAU;AAAA,IACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,IAAI,oBAA4B;AAC9B,aAAO,KAAK,UAAU;AAAA,IACxB;AAAA,IAUA,yBACE,MACA,UACA,UACM;AACN,YAAM,2BAA2B,MAAM,UAAU,QAAQ;AAQzD,YAAM,QAAQ,KAAK;AACnB,YAAM,aAAa,MAAM,cAAc,IAAI;AAE3C,UAAI,YAAY,UAAU,KAAK,kBAAkB;AAC/C,aAAK,SAAS,mBAAK,OAAM;AAAA,MAC3B;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUA,SAAS,OAAwB;AAC/B,yBAAK,aAAc;AACnB,WAAK,4BAA4B,EAAE;AACnC,yBAAK,QAAS;AACd,YAAM,oBAAoB,KAAK,sBAAA;AAC/B,YAAM,gBAAgB,oBAAoB,QAAQ;AAClD,WAAK,UAAU,aAAa,aAAuB;AACnD,4BAAK,0CAAL,WAAoB;AACpB,UAAI,KAAK,sBAAsB;AAC7B,aAAK,qBAAqB,aAAa;AAAA,MACzC;AACA,YAAM,YAAY,sBAAK,4CAAL;AAClB,4BAAK,iDAAL,WAA2B;AAAA,IAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,WAAW,SAAkB;AAC3B,UAAI,SAAS;AACX,8BAAK,0DAAL,WAAoC,EAAE,aAAa,KAAA,GAAQ;AAAA,MAC7D;AACA,yBAAK,aAAc;AACnB,4BAAK,4CAAL;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUA,wBAAiC;AAC/B,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA,IAuBA,IAAI,qBAAoC;AACtC,aAAO,IAAI,QAAQ,CAAC,YAAY,QAAQ,mBAAK,oBAAmB,CAAC;AAAA,IACnE;AAAA;AAAA;AAAA;AAAA,IAuPA,oBAAoB;AAClB,yBAAK,UAAW;AAChB,yBAAK,aAAc;AACnB,4BAAK,4CAAL;AACA,WAAK,mBAAA;AACL,YAAM,YAAY,sBAAK,4CAAL;AAClB,WAAK,4BAA4B,YAAY,KAAK,oBAAoB,EAAE;AACxE,4BAAK,iDAAL,WAA2B;AAAA,IAC7B;AAAA,EAaA;AAjgBA;AAOA;AAQA;AAMA;AAOA;AAOA;AAQA;AAWA;AAyBA;AAmJA;AAMA;AAKA;AA9UF;AAmZE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAA,WAA4B;AAC1B,QAAI,KAAK,aAAa,UAAU,GAAG;AACjC,aAAO;AAAA,IACT;AAEA,UAAM,YACJ,mBAAK,gBACJ,mBAAK,aAAY,CAAC,KAAK,SAAS,SAAS,CAAC,mBAAK;AAElD,QAAI,aAAa,KAAK,UAAU,QAAQ;AACtC,WAAK,UAAU,OAAO,IAAI,cAAc;AACxC,WAAK,UAAU,OAAO,IAAI,WAAW;AAAA,IACvC,WAAW,KAAK,UAAU,QAAQ;AAChC,WAAK,UAAU,OAAO,OAAO,cAAc;AAC3C,WAAK,UAAU,OAAO,OAAO,WAAW;AAAA,IAC1C;AAEA,WAAO;AAAA,EACT;AAEA,8BAAe,OAAwB;AACrC,UAAM,QAAQ,KAAK;AACnB,UAAM,WAAgC,CAAA;AACtC,UAAM,aAAa,MAAM;AACzB,UAAM,kBAA6C,CAAA;AACnD,UAAM,qBAAqB,WAAW;AAAA,MACpC,CAAC,cAAc,UAAU,mBAAmB;AAAA,IAAA;AAG9C,QAAI,CAAC,mBAAK,uBAAsB;AAC9B,yBAAK,qBAAsB,IAAI,QAAQ,CAAC,YAAY;AAClD,2BAAK,6BAA8B;AAAA,MACrC,CAAC;AACD,yBAAK,sBAAuB;AAAA,IAC9B;AAOA,QAAI,mBAAK,mBAAkB;AACzB,yBAAK,kBAAiB,MAAA;AAAA,IACxB;AAMA,UAAM,kBAAkB,IAAI,gBAAA;AAC5B,uBAAK,kBAAmB;AACxB,QAAI,oBAAwC;AAG5C,QAAI,YAAY;AAEhB,QAAI,CAAC,WAAW,QAAQ;AACtB;AAAA,IACF;AAEA,eAAW,QAAQ,CAAC,cAAc;AAChC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,UAAU,UAAU,QAAQ,MAAM,OAAO,gBAAgB,MAAM;AACrE,YAAM,mBAAmB,mBAAmB;AAE5C,UAAI,kBAAkB;AACpB,wBAAgB,KAAK,OAAO;AAE5B,gBAAQ,KAAK,CAAC,qBAAqB;AACjC,cAAI,qBAAqB,UAAa,qBAAqB,MAAM;AAC/D;AAAA,UACF;AAEA,mBAAS,GAAG,IAAI,CAAC;AAEjB,8BAAoB,sBAAK,wDAAL,WAClB,WACA;AAEF,gCAAK,0DAAL,WAAoC,UAAU;AAAA,QAChD,CAAC;AAAA,MACH,OAAO;AAEL,iBAAS,GAAG,IAAI,CAAC;AAEjB,YAAI,KAAK,SAAS,GAAG,MAAM,CAAC,SAAS;AACnC,sBAAY;AAAA,QACd;AAKA,YAAI,CAAC,WAAW,CAAC,mBAAmB;AAClC,8BAAoB,sBAAK,wDAAL,WAClB,WACA;AAAA,QAEJ;AAAA,MACF;AAAA,IACF,CAAC;AAGD,YAAQ,WAAW,eAAe,EAAE,KAAK,MAAM;AA9f9C;AAggBC,UAAI,CAAC,iBAAiB,OAAO,SAAS;AACpC,2BAAK,sBAAuB;AAC5B,iCAAK,iCAAL;AAAA,MACF;AAAA,IACF,CAAC;AAUD,QAAI,aAAa,CAAC,oBAAoB;AACpC,4BAAK,0DAAL,WAAoC,UAAU;AAAA,IAChD;AAAA,EACF;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAAA,SACE,UACA,mBACM;AACN,QAAI,KAAK,kBAAkB;AACzB,WAAK,UAAU;AAAA,QACb;AAAA,QACA;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,yBAAK,2BAA4B;AAAA,IACnC,OAAO;AACL,WAAK,UAAU,YAAY,UAAU,iBAAiB;AAEtD,UAAI,KAAK,UAAU,SAAS,OAAO;AACjC;AAAA,MACF;AAUA,yBAAK,2BAA4B;AAAA,IACnC;AAAA,EACF;AAMA;AAAA;AAAA;AAAA;AAAA,mCAAA,SACE,WACA,OACQ;AAGR,QAAI,KAAK,kBAAkB;AACzB,YAAM,UAAU,KAAK,iBAAiB,UAAU,OAAO,aAAa;AAEpE,UAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,UAAU,mBAAmB,UAAU;AACzC,aAAQ,UAAU,QAAsC,MAAM,KAAK;AAAA,IACrE,OAAO;AACL,aAAO,UAAU;AAAA,IACnB;AAAA,EACF;AAeA,qCAAsB,WAAoB;AACxC,UAAM,QAAQ,YAAY,qBAAqB;AAC/C,SAAK;AAAA,MACH,IAAI,YAAY,OAAO;AAAA,QACrB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,UACN,UAAU,KAAK;AAAA,QAAA;AAAA,MACjB,CACD;AAAA,IAAA;AAAA,EAEL;AAGF,SAAO;AACT;"}
|
|
1
|
+
{"version":3,"file":"form-control.mixin.js","sources":["../../src/mixins/form-control.mixin.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport type { IControlHost } from '../types/control-host';\nimport type { FormControlInterface } from '../types/form-control';\nimport type { FormValue } from '../types/form-value';\nimport type { Constructor } from '../types/mixin-constructor';\nimport type {\n CustomValidityState,\n validationMessageCallback,\n Validator,\n} from '../types/validator.type';\n\n/**\n *\n * https://github.com/open-wc/form-participation/tree/main/packages/form-control\n */\nexport function FormControlMixin<\n TBase extends Constructor<LitElement & IControlHost> & {\n observedAttributes?: string[];\n },\n>(SuperClass: TBase) {\n class FormControl extends SuperClass {\n /**\n * Wires up control instances to be form associated\n * @ignore\n */\n static get formAssociated(): boolean {\n return true;\n }\n\n /**\n * A list of Validator objects that will be evaluated when a control's form\n * value is modified or optionally when a given attribute changes.\n *\n * When a Validator's callback returns false, the entire form control will\n * be set to an invalid state.\n * @ignore\n */\n declare static formControlValidators: Validator[];\n\n /**\n * If set to true the control described should be evaluated and validated\n * as part of a group. Like a radio, if any member of the group's validity\n * changes the the other members should update as well.\n * @ignore\n */\n declare static formControlValidationGroup: boolean;\n\n /**\n * @ignore\n */\n private static get validators(): Validator[] {\n return this.formControlValidators || [];\n }\n\n /**\n * Allows the FormControl instance to respond to Validator attributes.\n * For instance, if a given Validator has a `required` attribute, that\n * validator will be evaluated whenever the host's required attribute\n * is updated.\n * @ignore\n */\n static get observedAttributes(): string[] {\n const validatorAttributes = this.validators\n .map((validator) => validator.attribute)\n .flat();\n\n const observedAttributes = super.observedAttributes || [];\n\n /** Make sure there are no duplicates inside the attributes list */\n const attributeSet = new Set([\n ...observedAttributes,\n ...validatorAttributes,\n ]);\n return [...attributeSet] as string[];\n }\n\n /**\n * Return the validator associated with a given attribute. If no\n * Validator is associated with the attribute, it will return null.\n * @ignore\n */\n static getValidator(attribute: string): Validator | null {\n return (\n this.validators.find(\n (validator) => validator.attribute === attribute\n ) || null\n );\n }\n\n /**\n * Get all validators that are set to react to a given attribute\n * @param {string} attribute - The attribute that has changed\n * @returns {Validator[]}\n * @ignore\n */\n static getValidators(attribute: string): Validator[] | null {\n return this.validators.filter((validator) => {\n if (\n validator.attribute === attribute ||\n validator.attribute?.includes(attribute)\n ) {\n return true;\n }\n });\n }\n\n /**\n * The ElementInternals instance for the control.\n * @ignore\n */\n internals = this.attachInternals();\n\n /**\n * Keep track of if the control has focus\n * @private\n * @ignore\n */\n #focused = false;\n\n /**\n * Exists to control when an error should be displayed\n * @private\n * @ignore\n */\n #forceError = false;\n\n /**\n * Toggles to true whenever the element has been altered. This property\n * will reset whenever the control's formResetCallback is called.\n * @private\n * @ignore\n */\n #touched = false;\n\n /**\n * An internal abort controller for cancelling pending async validation\n * @ignore\n */\n #abortController?: AbortController;\n\n /**\n * Used for tracking if a validation target has been set to manage focus\n * when the control's validity is reported\n * @ignore\n */\n #awaitingValidationTarget = true;\n\n /**\n * Acts as a cache for the current value so the value can be re-evaluated\n * whenever an attribute changes or on some other event.\n * @ignore\n */\n #value: FormValue = '';\n\n /**\n * Set this[focused]\n * to true when the element is focused\n * @private\n * @ignore\n */\n #onFocus = (): void => {\n this.#focused = true;\n this.#shouldShowError();\n };\n\n /**\n * Reset this[focused] on blur\n * @private\n * @ignore\n */\n #onBlur = (): void => {\n this.#focused = false;\n\n this.#runValidators(this.shouldFormValueUpdate() ? this.#value : '');\n\n /**\n * Set forceError to ensure error messages persist until\n * the value is changed.\n */\n if (!this.validity.valid && this.#touched) {\n this.#forceError = true;\n }\n const showError = this.#shouldShowError();\n\n if (this.validationMessageCallback) {\n this.validationMessageCallback(showError ? this.validationMessage : '');\n }\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * For the show error state on invalid\n * @private\n * @ignore\n */\n #onInvalid = (event?: Event): void => {\n event?.preventDefault();\n event?.stopImmediatePropagation();\n\n if (this.#awaitingValidationTarget && this.validationTarget) {\n this.internals.setValidity(\n this.validity,\n this.validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n }\n this.#touched = true;\n this.#forceError = true;\n const showError = this.#shouldShowError();\n this?.validationMessageCallback?.(\n showError ? this.validationMessage : ''\n );\n this.#dispatchInvalidEvent(showError);\n };\n\n /**\n * Return a reference to the control's form\n * @ignore\n */\n get form(): HTMLFormElement {\n return this.internals.form as HTMLFormElement;\n }\n\n /**\n * Will return true if it is recommended that the control shows an internal\n * error. If using this property, it is wise to listen for 'invalid' events\n * on the element host and call preventDefault on the event. Doing this will\n * prevent browsers from showing a validation popup.\n * @ignore\n */\n get showError(): boolean {\n return this.#shouldShowError();\n }\n\n /**\n * Forward the internals checkValidity method\n * will return the valid state of the control.\n * @ignore\n */\n checkValidity(): boolean {\n return this.internals.checkValidity();\n }\n\n /**\n * The element's validity state\n * @ignore\n */\n get validity(): ValidityState {\n return this.internals.validity;\n }\n\n /**\n * The validation message shown by a given Validator object. If the control\n * is in a valid state this should be falsy.\n * @ignore\n */\n get validationMessage(): string {\n return this.internals.validationMessage;\n }\n\n constructor(...args: any[]) {\n super(...args);\n this.addEventListener?.('focus', this.#onFocus);\n this.addEventListener?.('blur', this.#onBlur);\n this.addEventListener?.('invalid', this.#onInvalid);\n this.setValue(null);\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string,\n newValue: string\n ): void {\n super.attributeChangedCallback?.(name, oldValue, newValue);\n\n /**\n * Check to see if a Validator is associated with the changed attribute.\n * If one exists, call control's validate function which will perform\n * control validation.\n * @ignore\n */\n const proto = this.constructor as typeof FormControl;\n const validators = proto.getValidators(name);\n\n if (validators?.length && this.validationTarget) {\n this.setValue(this.#value);\n }\n }\n\n /** PUBLIC LIFECYCLE METHODS */\n\n /**\n * Sets the control's form value if the call to `shouldFormValueUpdate`\n * returns `true`. Set this[touch] if connected and value changed.\n * @param value {FormValue} - The value to pass to the form\n * @ignore\n */\n setValue(value: FormValue): void {\n if (this.isConnected && this.#value !== value) {\n this.#touched = true;\n }\n this.#forceError = false;\n this.validationMessageCallback?.('');\n this.#value = value;\n const valueShouldUpdate = this.shouldFormValueUpdate();\n const valueToUpdate = valueShouldUpdate ? value : null;\n this.internals.setFormValue(valueToUpdate as string);\n this.#runValidators(valueToUpdate);\n if (this.valueChangedCallback) {\n this.valueChangedCallback(valueToUpdate);\n }\n const showError = this.#shouldShowError();\n this.#dispatchInvalidEvent(showError);\n }\n\n /**\n * Forces the control to show an error state. If a message is passed in,\n * it will be set as the control's internal validity state message.\n * @param message { string | undefined } - The message for internals validity state\n */\n forceError(message?: string) {\n if (message) {\n this.#setValidityWithOptionalTarget({ customError: true }, message);\n }\n this.#forceError = true;\n this.#shouldShowError();\n }\n\n /**\n * This method can be overridden to determine if the control's form value\n * should be set on a call to `setValue`. An example of when a user might want\n * to skip this step is when implementing checkbox-like behavior, first checking\n * to see if `this.checked` is set to a truthy value. By default this returns\n * `true`.\n * @ignore\n */\n shouldFormValueUpdate(): boolean {\n return true;\n }\n\n /**\n * Save a reference to the validation complete resolver\n * @ignore\n */\n #validationCompleteResolver?: (value: void | PromiseLike<void>) => void;\n\n /**\n * When true validation will be pending\n * @ignore\n */\n #isValidationPending = false;\n\n /**\n * @ignore\n */\n #validationComplete = Promise.resolve();\n\n /**\n * A promise that will resolve when all pending validations are complete\n * @ignore\n */\n get validationComplete(): Promise<void> {\n return new Promise((resolve) => resolve(this.#validationComplete));\n }\n\n /** DECLARED INSTANCE METHODS AND PROPERTIES*/\n\n /**\n * Resets a form control to its initial state\n * @ignore\n */\n declare resetFormControl: () => void;\n\n /**\n * This method is used to override the controls' validity message\n * for a given Validator key. This has the highest level of priority when\n * setting a validationMessage, so use this method wisely.\n *\n * The returned value will be used as the validationMessage for the given key.\n * @param validationKey {string} - The key that has returned invalid\n * @ignore\n */\n declare validityCallback: (validationKey: string) => string | void;\n\n /**\n * Called when the control's validationMessage should be changed\n * @param message { string } - The new validation message\n * @ignore\n */\n declare validationMessageCallback: (message: string) => void;\n\n /**\n * A callback for when the controls' form value changes. The value\n * passed to this function should not be confused with the control's\n * value property, this is the value that will appear on the form.\n *\n * In cases where `checked` did not exist on the control's prototype\n * upon initialization, this value and the value property will be identical;\n * in cases where `checked` is present upon initialization, this will be\n * effectively `this.checked && this.value`.\n * @ignore\n */\n declare valueChangedCallback: (value: FormValue) => void;\n\n /**\n * The element that will receive focus when the control's validity\n * state is reported either by a form submission or via API\n *\n * We use declare since this is optional and we don't particularly\n * care how the consuming component implements this (as a field, member\n * or getter/setter)\n * @ignore\n */\n declare validationTarget: HTMLElement | null;\n\n /** PRIVATE LIFECYCLE METHODS */\n\n /**\n * Check to see if an error should be shown. This method will also\n * update the internals state object with the --show-error state\n * if necessary.\n * @private\n * @ignore\n */\n #shouldShowError(): boolean {\n if (this.hasAttribute('disabled')) {\n return false;\n }\n\n const showError =\n this.#forceError ||\n (this.#touched && !this.validity.valid && !this.#focused);\n\n if (showError && this.internals.states) {\n this.internals.states.add('--show-error');\n this.internals.states.add('--invalid');\n } else if (this.internals.states) {\n this.internals.states.delete('--show-error');\n this.internals.states.delete('--invalid');\n }\n\n return showError;\n }\n\n #runValidators(value: FormValue): void {\n const proto = this.constructor as typeof FormControl;\n const validity: CustomValidityState = {};\n const validators = proto.validators;\n const asyncValidators: Promise<boolean | void>[] = [];\n const hasAsyncValidators = validators.some(\n (validator) => validator.isValid instanceof Promise\n );\n\n if (!this.#isValidationPending) {\n this.#validationComplete = new Promise((resolve) => {\n this.#validationCompleteResolver = resolve;\n });\n this.#isValidationPending = true;\n }\n\n /**\n * If an abort controller exists from a previous validation step\n * notify still-running async validators that we are requesting they\n * discontinue any work.\n */\n if (this.#abortController) {\n this.#abortController.abort();\n }\n\n /**\n * Create a new abort controller and replace the instance reference\n * so we can clean it up for next time\n */\n const abortController = new AbortController();\n this.#abortController = abortController;\n let validationMessage: string | undefined = undefined;\n\n /** Track to see if any validity key has changed */\n let hasChange = false;\n\n if (!validators.length) {\n return;\n }\n\n validators.forEach((validator) => {\n const key = validator.key || 'customError';\n const isValid = validator.isValid(this, value, abortController.signal);\n const isAsyncValidator = isValid instanceof Promise;\n\n if (isAsyncValidator) {\n asyncValidators.push(isValid);\n\n isValid.then((isValidatorValid) => {\n if (isValidatorValid === undefined || isValidatorValid === null) {\n return;\n }\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValidatorValid;\n\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n });\n } else {\n /** Invert the validity state to correspond to the ValidityState API */\n validity[key] = !isValid;\n\n if (this.validity[key] !== !isValid) {\n hasChange = true;\n }\n\n // only update the validationMessage for the first invalid scenario\n // so that earlier invalid validators dont get their messages overwritten by later ones\n // in the validators array\n if (!isValid && !validationMessage) {\n validationMessage = this.#getValidatorMessageForValue(\n validator,\n value\n );\n }\n }\n });\n\n /** Once all the async validators have settled, resolve validationComplete */\n Promise.allSettled(asyncValidators).then(() => {\n /** Don't resolve validations if the signal is aborted */\n if (!abortController?.signal.aborted) {\n this.#isValidationPending = false;\n this.#validationCompleteResolver?.();\n }\n });\n\n /**\n * If async validators are present:\n * Only run updates when a sync validator has a change. This is to prevent\n * situations where running sync validators can override async validators\n * that are still in progress\n *\n * If async validators are not present, always update validity\n */\n if (hasChange || !hasAsyncValidators) {\n this.#setValidityWithOptionalTarget(validity, validationMessage);\n }\n }\n\n /**\n * If the validationTarget is not set, the user can decide how they would\n * prefer to handle focus when the field is validated.\n * @ignore\n */\n #setValidityWithOptionalTarget(\n validity: Partial<ValidityState>,\n validationMessage: string | undefined\n ): void {\n if (this.validationTarget) {\n this.internals.setValidity(\n validity,\n validationMessage,\n this.validationTarget\n );\n this.#awaitingValidationTarget = false;\n } else {\n this.internals.setValidity(validity, validationMessage);\n\n if (this.internals.validity.valid) {\n return;\n }\n\n /**\n * Sets mark the component as awaiting a validation target\n * if the element dispatches an invalid event, the #onInvalid listener\n * will check to see if the validation target has been set since this call\n * has run. This useful in cases like Lit's use of the query\n * decorator for setting the validationTarget or any scenario\n * where the validationTarget isn't available upon construction\n */\n this.#awaitingValidationTarget = true;\n }\n }\n\n /**\n * Process the validator message attribute\n * @ignore\n */\n #getValidatorMessageForValue(\n validator: Validator,\n value: FormValue\n ): string {\n /** If the validity callback exists and returns, use that as the result */\n\n if (this.validityCallback) {\n const message = this.validityCallback(validator.key || 'customError');\n\n if (message) {\n return message;\n }\n }\n\n if (validator.message instanceof Function) {\n return (validator.message as validationMessageCallback)(this, value);\n } else {\n return validator.message as string;\n }\n }\n\n /**\n * Reset control state when the form is reset\n */\n formResetCallback() {\n this.#touched = false;\n this.#forceError = false;\n this.#shouldShowError();\n this.resetFormControl?.();\n const showError = this.#shouldShowError();\n this.validationMessageCallback?.(showError ? this.validationMessage : '');\n this.#dispatchInvalidEvent(showError);\n }\n\n #dispatchInvalidEvent(showError: boolean) {\n const event = showError ? 'mid-invalid-show' : 'mid-invalid-hide';\n this.dispatchEvent(\n new CustomEvent(event, {\n bubbles: true,\n composed: true,\n detail: {\n validity: this.validity,\n },\n })\n );\n }\n }\n\n return FormControl as unknown as Constructor<FormControlInterface> & TBase;\n}\n"],"names":[],"mappings":"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"}
|