@felleslosninger/minid-elements 0.0.132 → 0.0.134

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.
@@ -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;;AA0FD;;;;;;;;;;;;;;;;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;IA4BnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;IAiBrB,KAAK;IAKL,gBAAgB;IAKhB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;IAKnC,kBAAkB;IAOT,MAAM;CA8FhB"}
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;IAKL,gBAAgB;IAKhB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;IAKnC,kBAAkB;IAOT,MAAM;CA8FhB"}
@@ -56,8 +56,7 @@ const styles = [
56
56
  color: transparent;
57
57
  /* Hide the real caret */
58
58
  caret-color: transparent;
59
- /* Make font tiny to avoid visual artifacts */
60
- font-size: 1px;
59
+ font-size: 16px; /* Must be at least 16px to prevent ios from zooming in */
61
60
  /* Allow clicks to pass through to elements underneath */
62
61
  pointer-events: none;
63
62
  }
@@ -154,8 +153,12 @@ let MinidCodeInput = class extends FormControlMixin(
154
153
  }
155
154
  handleInput(event) {
156
155
  const input = event.target;
157
- const value = input.value.substring(0, this.length);
158
- if (input.value.length > this.length) {
156
+ let value = input.value;
157
+ if (this.type === "number") {
158
+ value = value.replace(/[^0-9]/g, "");
159
+ }
160
+ value = value.substring(0, this.length);
161
+ if (input.value !== value) {
159
162
  input.value = value;
160
163
  }
161
164
  if (this.value !== value) {
@@ -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 /* Make font tiny to avoid visual artifacts */\n font-size: 1px;\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 const value = input.value.substring(0, this.length);\n\n // If the browser allowed a value longer than our length (e.g. on type=\"number\"),\n // we need to truncate the underlying input's value directly to keep it in sync.\n if (input.value.length > this.length) {\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.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.dispatchEvent(\n new Event('mid-complete', { bubbles: true, composed: true }),\n );\n }\n\n }\n\n private handleChange() {\n this.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.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.dispatchEvent(\n new Event('mid-complete', { bubbles: true, composed: true }),\n );\n }\n\n }\n\n private handleChange() {\n this.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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"}
@@ -68,6 +68,10 @@ export declare class MinidTextfield extends MinidTextfield_base {
68
68
  */
69
69
  invalidmessage: string;
70
70
  type: 'date' | 'datetime-local' | 'email' | 'file' | 'month' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'time' | 'url' | 'week';
71
+ /**
72
+ * For displaying appropriate virtual keyboard
73
+ */
74
+ inputmode: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal';
71
75
  /**
72
76
  * Adds a clear button when the input is not empty.
73
77
  * */
@@ -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;;AAYD;;;;;;;;;;;;;;;;;;;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,EACA,MAAM,GACN,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;;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;;IAUQ,iBAAiB,IAAI,IAAI;IAKlC,oBAAoB,IAAI,IAAI;IAI5B,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,WAAW;IAQnB,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"}
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;;IAUQ,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"}
@@ -26,6 +26,15 @@ const styles = [
26
26
  :host {
27
27
  display: block;
28
28
  }
29
+
30
+ /* Hide increment/decrement buttons on inputs */
31
+ input[type='number']::-webkit-outer-spin-button,
32
+ input[type='number']::-webkit-inner-spin-button,
33
+ input[type='number'] {
34
+ -webkit-appearance: none;
35
+ margin: 0;
36
+ -moz-appearance: textfield !important;
37
+ }
29
38
  `
30
39
  ];
31
40
  let nextUniqueId = 0;
@@ -43,6 +52,7 @@ let MinidTextfield = class extends FormControlMixin(
43
52
  this.autofocus = false;
44
53
  this.invalidmessage = "";
45
54
  this.type = "text";
55
+ this.inputmode = "text";
46
56
  this.clearable = false;
47
57
  this.passwordtoggle = false;
48
58
  this.passwordvisible = false;
@@ -94,7 +104,11 @@ let MinidTextfield = class extends FormControlMixin(
94
104
  );
95
105
  }
96
106
  handleInput() {
97
- this.value = this.input.value;
107
+ let tmp_value = this.input.value;
108
+ if (this.type === "number") {
109
+ tmp_value = tmp_value.replace(/[^0-9]/g, "");
110
+ }
111
+ this.value = tmp_value;
98
112
  this.setValue(this.value);
99
113
  this.dispatchEvent(
100
114
  new Event("mid-input", { bubbles: true, composed: true })
@@ -334,6 +348,9 @@ __decorateClass([
334
348
  __decorateClass([
335
349
  property()
336
350
  ], MinidTextfield.prototype, "type", 2);
351
+ __decorateClass([
352
+ property()
353
+ ], MinidTextfield.prototype, "inputmode", 2);
337
354
  __decorateClass([
338
355
  property({ type: Boolean })
339
356
  ], MinidTextfield.prototype, "clearable", 2);
@@ -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];\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 * 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 this.value = this.input.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":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAM,SAAS;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAKF;AAEA,IAAI,eAAe;AAuBZ,IAAM,iBAAN,cAA6B;AAAA,EAClC,OAAO,YAAY,MAAM;AAC3B,EAAE;AAAA,EAsJA,cAAc;AACZ,UAAA;AAnJF,SAAiB,mBAAmB,IAAI,kBAAkB,MAAM,OAAO;AAEvE,SAAQ,eAAe;AAMvB,SAAA,QAAQ;AAGR,SAAA,cAAc;AAGd,SAAA,QAAQ;AAGR,SAAA,OAA2B;AAS3B,SAAA,YAAY;AAoCZ,SAAA,iBAAiB;AAGjB,SAAA,OAaa;AAMb,SAAA,YAAY;AAOZ,SAAA,iBAAiB;AAOjB,SAAA,kBAAkB;AAGlB,SAAA,WAAW;AAGX,SAAA,WAAW;AAYX,SAAA,WAAW;AAMX,SAAA,YAAY;AAaZ,SAAA,WAAW;AAaT;AACA,SAAK,UAAU,uBAAuB,YAAY;AAClD,SAAK,gBAAgB,6BAA6B,YAAY;AAC9D,SAAK,eAAe,4BAA4B,YAAY;AAAA,EAC9D;AAAA,EAfA,WAAW,wBAAwB;AACjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAAA,EAUS,oBAA0B;AACjC,UAAM,kBAAA;AACN,SAAK,eAAe,KAAK;AAAA,EAC3B;AAAA,EAEA,uBAA6B;AAC3B,SAAK,WAAW,QAAA;AAAA,EAClB;AAAA,EAEQ,cAAc,OAAsB;AAC1C,UAAM,cACJ,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY,MAAM;AAI5D,QAAI,MAAM,QAAQ,WAAW,CAAC,aAAa;AACzC,iBAAW,MAAM;AAIf,YAAI,CAAC,MAAM,oBAAoB,CAAC,MAAM,aAAa;AACjD,eAAK,KAAK,cAAA;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,aAAa;AACnB,SAAK,WAAW;AAChB,SAAK;AAAA,MACH,IAAI,MAAM,YAAY,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,IAAA;AAAA,EAE3D;AAAA,EAEQ,eAAe;AACrB,SAAK,QAAQ,KAAK,MAAM;AACxB,SAAK;AAAA,MACH,IAAI,MAAM,cAAc,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,IAAA;AAAA,EAE7D;AAAA,EAEQ,cAAc;AACpB,SAAK,QAAQ,KAAK,MAAM;AACxB,SAAK,SAAS,KAAK,KAAK;AACxB,SAAK;AAAA,MACH,IAAI,MAAM,aAAa,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,IAAA;AAAA,EAE5D;AAAA,EAEQ,cAAc;AACpB,SAAK,WAAW;AAChB,SAAK;AAAA,MACH,IAAI,MAAM,aAAa,EAAE,UAAU,MAAM,SAAS,MAAM;AAAA,IAAA;AAAA,EAE5D;AAAA,EAEQ,uBAAuB;AAC7B,SAAK,kBAAkB,CAAC,KAAK;AAAA,EAC/B;AAAA,EAEQ,iBAAiB,OAAmB;AAC1C,UAAM,eAAA;AAEN,QAAI,KAAK,UAAU,IAAI;AACrB,WAAK,QAAQ;AACb,WAAK;AAAA,QACH,IAAI,MAAM,aAAa,EAAE,UAAU,MAAM,SAAS,MAAM;AAAA,MAAA;AAE1D,WAAK;AAAA,QACH,IAAI,MAAM,aAAa,EAAE,UAAU,MAAM,SAAS,MAAM;AAAA,MAAA;AAE1D,WAAK;AAAA,QACH,IAAI,MAAM,cAAc,EAAE,UAAU,MAAM,SAAS,MAAM;AAAA,MAAA;AAAA,IAE7D;AAEA,SAAK,MAAM,MAAA;AAAA,EACb;AAAA,EAEA,QAAQ;AACN,SAAK,WAAW;AAChB,SAAK,MAAM,MAAA;AAAA,EACb;AAAA,EAEA,mBAAmB;AACjB,SAAK,iBAAiB;AACtB,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA,EAEA,WAAW,SAAwB;AACjC,UAAM,WAAW,OAAO;AAAA,EAC1B;AAAA,EAGA,oBAAoB;AAClB,SAAK,SAAS,KAAK,KAAK;AAAA,EAC1B;AAAA,EAGA,MAAM,mBAAmB;AACvB,QAAI,CAAC,KAAK,KAAM;AAChB,UAAM,KAAK;AACX,SAAK,WAAW,QAAA;AAChB,SAAK,YAAY,IAAI,UAAU,KAAK,OAAO;AAAA,MACzC,MAAM,KAAK;AAAA,MACX,OAAO;AAAA,IAAA,CACR;AAAA,EACH;AAAA,EAES,SAAS;AAChB,UAAM,KAAK,KAAK,SAAS;AACzB,UAAM,KAAK,KAAK,SAAS;AACzB,UAAM,KAAK,KAAK,SAAS;AAEzB,UAAM,eAAe,KAAK,iBAAiB,KAAK,OAAO;AACvD,UAAM,WAAW,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;AACnC,UAAM,eAAe,KAAK,aAAa,CAAC,KAAK,YAAY,CAAC,KAAK;AAC/D,UAAM,qBACJ,iBAAiB,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,SAAS;AAEzE,WAAO;AAAA;AAAA;AAAA,iBAGM,SAAS;AAAA,MAChB,oBAAoB,KAAK;AAAA,MACzB,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,IAAA,CACjB,CAAC;AAAA;AAAA;AAAA,iBAGO,KAAK,OAAO;AAAA,mBACV,SAAS;AAAA,MAChB,WAAW,KAAK,aAAa,CAAC;AAAA,IAAA,CAC/B,CAAC;AAAA;AAAA,YAEA,KAAK,WACH;AAAA;AAAA;AAAA;AAAA,8BAKA,OAAO;AAAA,gCACW,KAAK,KAAK;AAAA;AAAA,UAEhC,KAAK,cACH;AAAA;AAAA,sBAEU,KAAK,aAAa;AAAA;AAAA,yBAEf,SAAS;AAAA,MAChB,WAAW,KAAK;AAAA,IAAA,CACjB,CAAC;AAAA;AAAA,kBAEA,KAAK,WAAW;AAAA;AAAA,gBAGtB,OAAO;AAAA;AAAA;AAAA,mBAGA,SAAS;AAAA,MAChB,kBAAkB,CAAC,KAAK,kBAAkB,CAAC,KAAK;AAAA,MAChD,iBAAiB,KAAK,kBAAkB,CAAC,KAAK;AAAA,MAC9C,yBAAyB,KAAK;AAAA,MAC9B,6BAA6B,KAAK;AAAA,MAClC,sBAAsB,CAAC,KAAK;AAAA,MAC5B,QAAQ,CAAC,KAAK;AAAA,MACd,YAAY,KAAK;AAAA,IAAA,CAClB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAMM,KAAK,OAAO;AAAA,qBACT,SAAS;AAAA,MAChB,UAAU,CAAC;AAAA,MACX,mCAAmC;AAAA,MACnC,qDACE,KAAK,SAAS;AAAA,IAAA,CACjB,CAAC;AAAA;AAAA,qBAEO,KAAK,KAAK,KAAK,CAAC;AAAA,wBACb,KAAK,QAAQ;AAAA,wBACb,KAAK,QAAQ;AAAA,yBACZ,KAAK,SAAS;AAAA,2BACZ,UAAU,KAAK,YAAmB,CAAC;AAAA,mBAC3C,KAAK,SAAS,cAAc,KAAK,kBACpC,SACA,KAAK,IAAI;AAAA,gCACO;AAAA,MACjB,KAAK,eAAe,KAAK,iBAAkB;AAAA,IAAA,CAC7C;AAAA,iCACoB,KAAK,YAAY;AAAA,0BACxB,UAAU,KAAK,WAAW,CAAC;AAAA,wBAC7B,UAAU,KAAK,SAAS,CAAC;AAAA,wBACzB,UAAU,KAAK,SAAS,CAAC;AAAA,kBAC/B,UAAU,KAAK,GAAG,CAAC;AAAA,kBACnB,UAAU,KAAK,GAAG,CAAC;AAAA,sBACf,UAAU,KAAK,OAAO,CAAC;AAAA,qBACxB,KAAK,WAAW;AAAA,sBACf,KAAK,YAAY;AAAA,qBAClB,KAAK,WAAW;AAAA,oBACjB,KAAK,UAAU;AAAA,uBACZ,KAAK,aAAa;AAAA;AAAA,YAE7B,qBACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAMa,KAAK,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBASlC,EAAE;AAAA,YACJ,KAAK,kBAAkB,CAAC,KAAK,WAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKiB,KAAK,kBACd,kBACA,aAAa;AAAA,2BACR,KAAK,oBAAoB;AAAA;AAAA;AAAA,oBAGhC,KAAK,kBACH;AAAA;AAAA;AAAA;AAAA,sCAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAMC;AAAA;AAAA,kBAGT,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAOA,KAAK,YAAY;AAAA;AAAA,oBAEb,CAAC,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAM5B,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA,EAI7B;AACF;AAnaE,gBAAA;AAAA,EADC,MAAM,QAAQ;AAAA,GAVJ,eAWX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAbC,eAcX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAhBC,eAiBX,WAAA,eAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAnBC,eAoBX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAtBC,eAuBX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,WAAW,gBAAA,CAAiB;AAAA,GAzB7B,eA0BX,WAAA,eAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GA/BhB,eAgCX,WAAA,aAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAA;AAAS,GArCC,eAsCX,WAAA,gBAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA3Cf,eA4CX,WAAA,aAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAjDf,eAkDX,WAAA,aAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAA;AAAS,GAvDC,eAwDX,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAA;AAAS,GA7DC,eA8DX,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAA;AAAS,GAnEC,eAoEX,WAAA,kBAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAtEC,eAuEX,WAAA,QAAA,CAAA;AAmBA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAzFhB,eA0FX,WAAA,aAAA,CAAA;AAOA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAhGhB,eAiGX,WAAA,kBAAA,CAAA;AAOA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAvGhB,eAwGX,WAAA,mBAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA,GA1G/B,eA2GX,WAAA,YAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,MAAM;AAAA,GA7G/B,eA8GX,WAAA,YAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAA;AAAS,GAnHC,eAoHX,WAAA,WAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAzHhB,eA0HX,WAAA,YAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GA/HhB,eAgIX,WAAA,aAAA,CAAA;AAUA,gBAAA;AAAA,EADC,SAAA;AAAS,GAzIC,eA0IX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,MAAA;AAAM,GA5II,eA6IX,WAAA,YAAA,CAAA;AAiHA,gBAAA;AAAA,EADC,MAAM,OAAO;AAAA,GA7PH,eA8PX,WAAA,qBAAA,CAAA;AAKM,gBAAA;AAAA,EADL,MAAM,MAAM;AAAA,GAlQF,eAmQL,WAAA,oBAAA,CAAA;AAnQK,iBAAN,gBAAA;AAAA,EADN,cAAc,eAAe;AAAA,GACjB,cAAA;"}
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 +1 @@
1
- {"version":3,"file":"web-otp-api.d.ts","sourceRoot":"","sources":["../../src/utilities/web-otp-api.ts"],"names":[],"mappings":"AAWA,wBAAgB,aAAa,CAAC,UAAU,EAAE,WAAW,GAAG,gBAAgB,GAAG,IAAI,CA4B9E;AAED,wBAAgB,cAAc,SAK7B"}
1
+ {"version":3,"file":"web-otp-api.d.ts","sourceRoot":"","sources":["../../src/utilities/web-otp-api.ts"],"names":[],"mappings":"AAaA,wBAAgB,aAAa,CAAC,UAAU,EAAE,WAAW,GAAG,gBAAgB,GAAG,IAAI,CA6C9E;AAED,wBAAgB,cAAc,SAK7B"}
@@ -1,5 +1,6 @@
1
1
  let form;
2
2
  let ac;
3
+ let handleManualSubmit;
3
4
  function closestElement(selector, el) {
4
5
  if (el === null) {
5
6
  return null;
@@ -14,25 +15,36 @@ function webOtpApiInit(renderRoot) {
14
15
  }
15
16
  ac = new AbortController();
16
17
  form = closestElement("form", input);
17
- form?.addEventListener("submit", () => {
18
+ handleManualSubmit = () => {
18
19
  ac?.abort("Form submitted manually");
19
- });
20
+ };
21
+ form?.addEventListener("submit", handleManualSubmit);
20
22
  navigator.credentials.get({
21
23
  otp: { transport: ["sms"] },
22
24
  signal: ac.signal
23
25
  }).then((otp) => {
24
- input.value = otp?.code;
26
+ if (!otp?.code) {
27
+ return;
28
+ }
29
+ const otpCode = otp.code;
30
+ const submit = () => {
31
+ form?.requestSubmit();
32
+ };
33
+ if (otpCode.length >= input.maxLength) {
34
+ input.addEventListener("mid-complete", submit, { once: true });
35
+ }
36
+ input.value = otpCode;
25
37
  input.dispatchEvent(new Event("input", { bubbles: true, cancelable: true, composed: true }));
26
- form?.dispatchEvent(new Event("submit"));
27
38
  }).catch((err) => {
39
+ if (err.name !== "AbortError") ;
28
40
  });
29
41
  }
30
42
  }
31
43
  function webOtpApiClose() {
32
44
  ac?.abort("User navigated away from page");
33
- form?.removeEventListener("submit", () => {
34
- ac?.abort("Form submitted manually");
35
- });
45
+ if (form && handleManualSubmit) {
46
+ form.removeEventListener("submit", handleManualSubmit);
47
+ }
36
48
  }
37
49
  export {
38
50
  webOtpApiClose,
@@ -1 +1 @@
1
- {"version":3,"file":"web-otp-api.js","sources":["../../src/utilities/web-otp-api.ts"],"sourcesContent":["let form: HTMLFormElement | null;\nlet ac: AbortController | null;\nfunction closestElement(selector :string, el :Element | Window | Document | null ) :HTMLFormElement | null { /* https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd */\n if(el === null) {\n return null;\n }\n return ((el && el instanceof Element && el.closest(selector))\n || closestElement(selector, el instanceof Element && (el.getRootNode() as ShadowRoot).host || null)\n );\n}\n\nexport function webOtpApiInit(renderRoot: HTMLElement | DocumentFragment): void {\n\n if (\"OTPCredential\" in window) {\n const input = renderRoot.querySelector(\"input[autocomplete=\\\"one-time-code\\\"]\") as HTMLInputElement | null;\n\n if (!input || !navigator.credentials) {\n return;\n }\n\n /* handle manual submit */\n ac = new AbortController(); // Cancel the WebOTP API if the form is submitted manually.\n form = closestElement(\"form\", input);\n form?.addEventListener(\"submit\", () => {\n ac?.abort(\"Form submitted manually\"); // Cancel WebOTP API.\n });\n\n navigator.credentials.get({\n otp: { transport: [\"sms\"] },\n signal: ac.signal\n }).then( (otp) => {\n input.value = <string>(otp as OTPCredential)?.code;\n input.dispatchEvent(new Event('input', { bubbles: true, cancelable: true, composed: true }));\n form?.dispatchEvent(new Event('submit'));\n }).catch(err => {\n import.meta.env.DEV && console.log(\"WebOPT API error:\", err);\n });\n\n }\n}\n\nexport function webOtpApiClose() {\n ac?.abort(\"User navigated away from page\");\n form?.removeEventListener(\"submit\", () => {\n ac?.abort(\"Form submitted manually\");\n });\n}"],"names":[],"mappings":"AAAA,IAAI;AACJ,IAAI;AACJ,SAAS,eAAe,UAAkB,IAAiE;AACzG,MAAG,OAAO,MAAM;AACd,WAAO;AAAA,EACT;AACA,SAAS,MAAM,cAAc,WAAW,GAAG,QAAQ,QAAQ,KACtD,eAAe,UAAU,cAAc,WAAY,GAAG,YAAA,EAA6B,QAAQ,IAAI;AAEtG;AAEO,SAAS,cAAc,YAAkD;AAE9E,MAAI,mBAAmB,QAAQ;AAC7B,UAAM,QAAQ,WAAW,cAAc,qCAAuC;AAE9E,QAAI,CAAC,SAAS,CAAC,UAAU,aAAa;AACpC;AAAA,IACF;AAGA,SAAK,IAAI,gBAAA;AACT,WAAO,eAAe,QAAQ,KAAK;AACnC,UAAM,iBAAiB,UAAU,MAAM;AACrC,UAAI,MAAM,yBAAyB;AAAA,IACrC,CAAC;AAED,cAAU,YAAY,IAAI;AAAA,MACxB,KAAK,EAAE,WAAW,CAAC,KAAK,EAAA;AAAA,MACxB,QAAQ,GAAG;AAAA,IAAA,CACZ,EAAE,KAAM,CAAC,QAAQ;AAChB,YAAM,QAAiB,KAAuB;AAC9C,YAAM,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,MAAM,YAAY,MAAM,UAAU,KAAA,CAAM,CAAC;AAC3F,YAAM,cAAc,IAAI,MAAM,QAAQ,CAAC;AAAA,IACzC,CAAC,EAAE,MAAM,CAAA,QAAO;AAAA,IAEhB,CAAC;AAAA,EAEH;AACF;AAEO,SAAS,iBAAiB;AAC/B,MAAI,MAAM,+BAA+B;AACzC,QAAM,oBAAoB,UAAU,MAAM;AACxC,QAAI,MAAM,yBAAyB;AAAA,EACrC,CAAC;AACH;"}
1
+ {"version":3,"file":"web-otp-api.js","sources":["../../src/utilities/web-otp-api.ts"],"sourcesContent":["let form: HTMLFormElement | null;\nlet ac: AbortController | null;\nlet handleManualSubmit: () => void;\n\nfunction closestElement(selector :string, el :Element | Window | Document | null ) :HTMLFormElement | null { /* https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd */\n if(el === null) {\n return null;\n }\n return ((el && el instanceof Element && el.closest(selector))\n || closestElement(selector, el instanceof Element && (el.getRootNode() as ShadowRoot).host || null)\n );\n}\n\nexport function webOtpApiInit(renderRoot: HTMLElement | DocumentFragment): void {\n\n if ('OTPCredential' in window) {\n const input = renderRoot.querySelector('input[autocomplete=\"one-time-code\"]') as HTMLInputElement | null;\n\n if (!input || !navigator.credentials) {\n return;\n }\n\n /* handle manual submit */\n ac = new AbortController(); // Cancel the WebOTP API if the form is submitted manually.\n form = closestElement('form', input);\n\n handleManualSubmit = () => {\n ac?.abort('Form submitted manually'); // Cancel WebOTP API.\n };\n form?.addEventListener('submit', handleManualSubmit);\n\n navigator.credentials.get({\n otp: { transport: ['sms'] },\n signal: ac.signal,\n }).then( (otp) => {\n if (!<string>(otp as OTPCredential)?.code) {\n return;\n }\n const otpCode = <string>(otp as OTPCredential).code;\n\n const submit = () => {\n form?.requestSubmit();\n };\n\n if (otpCode.length >= input.maxLength) {\n input.addEventListener('mid-complete', submit, { once: true });\n }\n\n input.value = otpCode;\n input.dispatchEvent(new Event('input', { bubbles: true, cancelable: true, composed: true }));\n\n }).catch(err => {\n if (err.name !== 'AbortError') {\n import.meta.env.DEV && console.log('WebOTP API error:', err);\n }\n });\n\n }\n}\n\nexport function webOtpApiClose() {\n ac?.abort('User navigated away from page');\n if (form && handleManualSubmit) {\n form.removeEventListener('submit', handleManualSubmit);\n }\n}\n"],"names":[],"mappings":"AAAA,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,SAAS,eAAe,UAAkB,IAAiE;AACzG,MAAG,OAAO,MAAM;AACd,WAAO;AAAA,EACT;AACA,SAAS,MAAM,cAAc,WAAW,GAAG,QAAQ,QAAQ,KACtD,eAAe,UAAU,cAAc,WAAY,GAAG,YAAA,EAA6B,QAAQ,IAAI;AAEtG;AAEO,SAAS,cAAc,YAAkD;AAE9E,MAAI,mBAAmB,QAAQ;AAC7B,UAAM,QAAQ,WAAW,cAAc,qCAAqC;AAE5E,QAAI,CAAC,SAAS,CAAC,UAAU,aAAa;AACpC;AAAA,IACF;AAGA,SAAK,IAAI,gBAAA;AACT,WAAO,eAAe,QAAQ,KAAK;AAEnC,yBAAqB,MAAM;AACzB,UAAI,MAAM,yBAAyB;AAAA,IACrC;AACA,UAAM,iBAAiB,UAAU,kBAAkB;AAEnD,cAAU,YAAY,IAAI;AAAA,MACxB,KAAK,EAAE,WAAW,CAAC,KAAK,EAAA;AAAA,MACxB,QAAQ,GAAG;AAAA,IAAA,CACZ,EAAE,KAAM,CAAC,QAAQ;AAChB,UAAI,CAAU,KAAuB,MAAM;AACzC;AAAA,MACF;AACA,YAAM,UAAmB,IAAsB;AAE/C,YAAM,SAAS,MAAM;AACnB,cAAM,cAAA;AAAA,MACR;AAEA,UAAI,QAAQ,UAAU,MAAM,WAAW;AACrC,cAAM,iBAAiB,gBAAgB,QAAQ,EAAE,MAAM,MAAM;AAAA,MAC/D;AAEA,YAAM,QAAQ;AACd,YAAM,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,MAAM,YAAY,MAAM,UAAU,KAAA,CAAM,CAAC;AAAA,IAE7F,CAAC,EAAE,MAAM,CAAA,QAAO;AACd,UAAI,IAAI,SAAS,aAAc;AAAA,IAGjC,CAAC;AAAA,EAEH;AACF;AAEO,SAAS,iBAAiB;AAC/B,MAAI,MAAM,+BAA+B;AACzC,MAAI,QAAQ,oBAAoB;AAC9B,SAAK,oBAAoB,UAAU,kBAAkB;AAAA,EACvD;AACF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@felleslosninger/minid-elements",
3
- "version": "0.0.132",
3
+ "version": "0.0.134",
4
4
  "description": "MinID Web Components",
5
5
  "author": "Digitaliseringsdirektoratet",
6
6
  "license": "MIT",