UNPKG

@limetech/lime-elements

Version:
1,197 lines (1,196 loc) • 48.1 kB
import { MDCTextField } from "@material/textfield"; import { h, Host, } from "@stencil/core"; import { debounce } from "lodash-es"; import { ARROW_DOWN, ARROW_UP, ENTER, ESCAPE, SPACE, TAB, } from "../../util/keycodes"; import { getHref, getTarget, getRel } from "../../util/link-helper"; import { createRandomString } from "../../util/random-string"; import { globalConfig } from "../../global/config"; const CHANGE_EVENT_DEBOUNCE_TIMEOUT = 300; const RESIZE_HANDLER_DEBOUNCE_TIMEOUT = 100; /** * @exampleComponent limel-example-input-field-text * @exampleComponent limel-example-input-field-placeholder * @exampleComponent limel-example-input-field-text-multiple * @exampleComponent limel-example-input-field-number * @exampleComponent limel-example-input-field-autocomplete * @exampleComponent limel-example-input-field-icon-leading * @exampleComponent limel-example-input-field-icon-trailing * @exampleComponent limel-example-input-field-icon-both * @exampleComponent limel-example-input-field-showlink * @exampleComponent limel-example-input-field-error-icon * @exampleComponent limel-example-input-field-textarea * @exampleComponent limel-example-input-field-suffix * @exampleComponent limel-example-input-field-prefix * @exampleComponent limel-example-input-field-search * @exampleComponent limel-example-input-field-pattern * @exampleComponent limel-example-input-field-focus * @exampleComponent limel-example-input-field-selection */ export class InputField { constructor() { /** * Set to `true` to disable the field. * Use `disabled` to indicate that the field can normally be interacted * with, but is currently disabled. This tells the user that if certain * requirements are met, the field may become enabled again. */ this.disabled = false; /** * Set to `true` to make the field read-only. * Use `readonly` when the field is only there to present the data it holds, * and will not become possible for the current user to edit. */ this.readonly = false; /** * Set to `true` to indicate that the current value of the input field is * invalid. */ this.invalid = false; /** * Set to `true` to indicate that the field is required. */ this.required = false; /** * Type of input. * * Note** regarding type `url`: `limel-input` uses the native validation * built into the browser for many types of input fields. The native * validation for `url` is very strict, and does not allow relative urls, * nor any other formats that are not a "fully qualified" url. To allow * such urls, use the type `urlAsText` instead. `urlAsText` works exactly * like `text` in all regards, except that it enables use of the `showLink` * property. */ this.type = 'text'; /** * Set to `true` to format the current value of the input field only * if the field is of type number. * The number format is determined by the current language of the browser. */ this.formatNumber = true; /** * Defines which numeric values are valid and the increment/decrement interval. * For example, `step={0.1}` allows decimals and steps by 0.1. * Set to `'any'` to allow any numeric value. * Only applies when `type` is `number`. */ this.step = 'any'; /** * list of suggestions `value` can autocomplete to. */ this.completions = []; /** * For inputs of type `email`, `tel`, `url`, and `urlAsText`, set this to * `true` to show a trailing icon with a `mailto:`,`tel:`, or normal link, * respectively. The default icon can be overridden using the `trailingIcon` * property. */ this.showLink = false; /** * The locale to use for formatting numbers. */ this.locale = globalConfig.defaultLocale; this.isFocused = false; this.wasInvalid = false; this.showCompletions = false; this.completionsList = []; this.changeWaiting = false; this.initialize = () => { const element = this.limelInputField.shadowRoot.querySelector('.mdc-text-field'); if (!element) { return; } this.mdcTextField = new MDCTextField(element); if (this.value) { this.mdcTextField.value = this.value; } if (this.invalid) { this.mdcTextField.valid = false; } this.mapCompletions(); window.addEventListener('resize', this.layout, { passive: true }); this.limelInputField.addEventListener('focus', this.setFocus); }; this.mapCompletions = () => { this.completionsList = [...this.completions].map((item) => { return { text: item }; }); }; this.setFocus = () => { this.mdcTextField.focus(); }; this.getContainerClassList = () => { const classList = { 'mdc-text-field': true, 'mdc-text-field--outlined': true, 'mdc-text-field--invalid': this.isInvalid(), 'mdc-text-field--disabled': this.disabled || this.readonly, 'lime-text-field--readonly': this.readonly, 'mdc-text-field--required': this.required, 'lime-text-field--empty': this.isEmpty(), 'lime-has-prefix': this.hasPrefix(), 'lime-has-suffix': this.hasSuffix(), }; if (this.type === 'textarea') { classList['mdc-text-field--textarea'] = true; } else { classList['mdc-text-field--with-leading-icon'] = !!this.leadingIcon; classList['mdc-text-field--with-trailing-icon'] = !!this.getTrailingIcon(); } return classList; }; this.isEmpty = () => { var _a; if (this.type === 'number' && ((_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.validity.badInput)) { return false; } return !this.getCurrentValue(); }; this.getCurrentValue = () => { if (this.changeWaiting && this.inputElement) { return this.inputElement.value; } return this.value; }; this.renderInput = (properties) => { if (this.type === 'textarea') { return; } const type = this.type === 'urlAsText' ? 'text' : this.type; return (h("input", Object.assign({}, properties, { type: type, pattern: this.pattern, onWheel: this.handleWheel, onKeyDown: this.onKeyDown, placeholder: this.placeholder }))); }; this.renderTextarea = (properties) => { if (this.type !== 'textarea') { return; } return (h("span", { class: "mdc-text-field__resizer" }, h("textarea", Object.assign({}, properties, { placeholder: this.placeholder })))); }; this.layout = () => { var _a; (_a = this.mdcTextField) === null || _a === void 0 ? void 0 : _a.layout(); this.restyleCompletionsDropDown(); }; this.restyleCompletionsDropDown = debounce(() => { const stateOfShowCompletions = this.showCompletions; this.showCompletions = false; requestAnimationFrame(() => { this.showCompletions = stateOfShowCompletions; }); }, RESIZE_HANDLER_DEBOUNCE_TIMEOUT); this.getAdditionalProps = () => { const props = {}; if (this.type === 'number') { props.step = this.step; } if (this.type === 'number' && Number.isInteger(this.min)) { props.min = this.min; } if (this.type === 'number' && Number.isInteger(this.max)) { props.max = this.max; } if (this.minlength) { props.minlength = this.minlength; } if (this.maxlength) { props.maxlength = this.maxlength; } return props; }; this.onFocus = () => { this.isFocused = true; this.showCompletions = true; }; this.onBlur = () => { this.isFocused = false; this.validate(); this.changeEmitter.flush(); }; this.hasHelperText = () => { var _a; return !!((_a = this.helperText) !== null && _a !== void 0 ? _a : this.validationMessage); }; this.hasHelperLine = () => { return this.maxlength > 0 || this.hasHelperText(); }; this.renderHelperLine = () => { var _a; const text = this.getCurrentValue() || ''; const length = text.length; if (!this.hasHelperLine()) { return; } return (h("limel-helper-line", { helperTextId: this.helperTextId, helperText: (_a = this.helperText) !== null && _a !== void 0 ? _a : this.validationMessage, length: length, maxLength: this.maxlength, invalid: this.isInvalid() })); }; this.renderSuffix = () => { if (!this.hasSuffix() || this.type === 'textarea') { return; } const classList = { 'mdc-text-field__affix': true, 'mdc-text-field__affix--suffix': true, }; return h("span", { class: classList }, this.suffix); }; this.hasSuffix = () => { return this.suffix !== null && this.suffix !== undefined; }; this.renderPrefix = () => { if (!this.hasPrefix() || this.type === 'textarea') { return; } const classList = { 'mdc-text-field__affix': true, 'mdc-text-field__affix--prefix': true, }; return h("span", { class: classList }, this.prefix); }; this.hasPrefix = () => { return this.prefix !== null && this.prefix !== undefined; }; this.isInvalid = () => { if (this.readonly) { // A readonly field can never be invalid. return false; } if (this.invalid) { // `this.invalid` is set by the consumer. If the consumer explicitly // told us to consider the field invalid, we consider it invalid // regardless of what our internal validation thinks, and regardless // of whether the field has been modified. return true; } return this.wasInvalid; }; this.validate = () => { if (this.readonly || this.invalid) { this.wasInvalid = false; return; } if (this.inputElement) { this.wasInvalid = !this.inputElement.checkValidity(); } }; this.setInputElement = (element) => { if (element) { this.inputElement = element; } }; this.renderLeadingIcon = () => { if (this.type === 'textarea') { return; } if (this.leadingIcon) { return (h("i", { class: "material-icons mdc-text-field__icon mdc-text-field__icon--leading" }, h("limel-icon", { name: this.leadingIcon }))); } }; this.renderTrailingLinkOrButton = () => { if (this.type === 'textarea') { return; } const trailingIcon = this.getTrailingIcon(); if (!this.isInvalid() && this.hasLink()) { return this.renderLinkIcon(this.getLink(), trailingIcon); } else if (trailingIcon) { return this.renderTrailingIcon(trailingIcon); } }; this.hasLink = () => { return (this.showLink && ['email', 'tel', 'url', 'urlAsText'].includes(this.type)); }; this.getLink = () => { const props = { href: '' }; switch (this.type) { case 'email': { props.href = `mailto:${this.value}`; break; } case 'tel': { props.href = `tel:${this.value}`; break; } default: { props.href = getHref(this.value); props.target = getTarget(this.value); props.rel = getRel(props.target); } } return props; }; this.renderLinkIcon = (linkProps, icon) => { // If the trailing icon uses the class `mdc-text-field__icon--trailing`, // MDC attaches a click handler to it, which apparently runs // `preventDefault()` on the event. For links, we don't want that, // so instead of `mdc-text-field__icon--trailing`, we use our own class // `lime-trailing-icon-for-link`, which uses all the same styling. /Ads return (h("a", Object.assign({}, linkProps, { class: "material-icons mdc-text-field__icon lime-trailing-icon-for-link", tabindex: this.disabled || this.isEmpty() ? '-1' : '0', role: "button" }), h("limel-icon", { name: icon }))); }; this.renderTrailingIcon = (icon) => { if (this.isInvalid()) { return (h("i", { key: "invalid", class: "material-icons mdc-text-field__icon invalid-icon" }, h("limel-icon", { name: icon }))); } return (h("i", { key: "action", class: "material-icons mdc-text-field__icon mdc-text-field__icon--trailing", tabIndex: 0, role: "button", onKeyDown: this.handleIconKeyPress, onClick: this.handleIconClick }, h("limel-icon", { name: icon }))); }; this.getTrailingIcon = () => { if (this.isInvalid()) { return 'high_importance'; } if (this.trailingIcon) { return this.trailingIcon; } if (this.showLink && this.type === 'email') { return 'filled_message'; } if (this.showLink && this.type === 'tel') { return 'phone'; } if (this.showLink && (this.type === 'url' || this.type === 'urlAsText')) { return 'external_link'; } }; this.renderFormattedNumber = () => { if (this.type !== 'number') { return; } let renderValue = this.value; if (this.formatNumber && this.value) { renderValue = new Intl.NumberFormat(this.locale).format(Number(this.value)); if (renderValue === 'NaN') { return; } } return (h("span", { class: "lime-formatted-input lime-looks-like-input-value" }, renderValue)); }; /** * Key handler for the input field * Will change focus to the first/last item in the dropdown list to enable selection with the keyboard * * @param event - event */ this.onKeyDown = (event) => { this.showCompletions = true; const isForwardTab = event.key === TAB && !event.altKey && !event.metaKey && !event.shiftKey; const isUp = event.key === ARROW_UP; const isDown = event.key === ARROW_DOWN; if (event.key === TAB && event.shiftKey) { this.showCompletions = false; } if (!isForwardTab && !isUp && !isDown) { return; } const list = document.querySelector(` #${this.portalId} limel-list`); if (!list) { return; } event.preventDefault(); if (isForwardTab || isDown) { const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:first-child'); listElement.focus(); return; } if (isUp) { const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:last-child'); listElement.focus(); } }; this.handleCompletionChange = (event) => { event.stopPropagation(); if (!event.detail) { return; } this.showCompletions = false; /* This change event doesn't need to be debounced in itself, but we want to make absolutely sure that an earlier change event that *has* been debounced doesn't emit after this one. Therefore, we run this through the same debounced emitter function. /Ads */ this.changeEmitter(event.detail.text); this.changeEmitter.flush(); }; this.renderAutocompleteList = () => { if (this.type === 'textarea' || this.completions.length === 0) { return; } const dropdownZIndex = getComputedStyle(this.limelInputField).getPropertyValue('--dropdown-z-index'); return (h("limel-portal", { visible: this.showCompletions, containerId: this.portalId, inheritParentWidth: true, containerStyle: { 'z-index': dropdownZIndex } }, h("limel-menu-surface", { open: this.showCompletions, allowClicksElement: this.limelInputField, style: { '--menu-surface-width': '100%', 'max-height': 'inherit', display: 'flex', }, onDismiss: this.handleCloseMenu }, this.renderListResult()))); }; this.renderListResult = () => { const filteredCompletions = this.filterCompletions(this.getCurrentValue()); if (!filteredCompletions || filteredCompletions.length === 0) { return null; } return (h("limel-list", { onChange: this.handleCompletionChange, onKeyDown: this.handleKeyDownInDropdown, type: "selectable", items: filteredCompletions })); }; this.handleKeyDownInDropdown = (event) => { const keyFound = [TAB, ESCAPE, ENTER].includes(event.key); if (keyFound) { this.setFocus(); } }; this.handleCloseMenu = () => { this.showCompletions = false; }; this.filterCompletions = (filter) => { if (!filter) { return this.completionsList; } return this.completionsList.filter((completion) => completion.text.toLowerCase().includes(filter.toLowerCase())); }; this.handleInput = (event) => { event.stopPropagation(); let value = event.target.value; if (this.type === 'number') { if (!value && event.data) { event.stopPropagation(); return; } if (value) { value = Number(value); } } this.changeWaiting = true; this.changeEmitter(value); }; this.changeEmitter = debounce((value) => { this.change.emit(value); this.changeWaiting = false; }, CHANGE_EVENT_DEBOUNCE_TIMEOUT); this.handleChange = (event) => { event.stopPropagation(); this.changeEmitter.flush(); }; this.handleIconClick = () => { this.action.emit(); }; this.handleIconKeyPress = (event) => { const isEnter = event.key === ENTER; const isSpace = event.key === SPACE; if (isSpace || isEnter) { this.action.emit(); } }; this.handleWheel = () => { // This empty event handler is here to circumvent a bug. // In some browsers (Chrome for example), hovering the input with // the input focused, and scrolling, will both change the value // AND scroll the page. We would prefer to never change the value // on scroll, instead always scrolling the page, but since we // haven't found a way to do that, this is the next best thing, as // it prevents the page from being scrolled, but only in the // circumstances when the value is changed by the scrolling. // Please test THOROUGHLY if you remove this event handler 😄 }; this.portalId = createRandomString(); this.helperTextId = createRandomString(); this.labelId = createRandomString(); } connectedCallback() { this.initialize(); } componentDidLoad() { this.initialize(); } disconnectedCallback() { if (this.mdcTextField) { this.mdcTextField.destroy(); } this.restyleCompletionsDropDown.cancel(); window.removeEventListener('resize', this.layout); this.limelInputField.removeEventListener('focus', this.setFocus); } componentDidUpdate() { if (this.invalid) { this.mdcTextField.valid = false; } this.mdcTextField.disabled = this.disabled || this.readonly; } /** * Returns the start position of the current text selection. * Returns `null` if the input element is not available or if * the input type does not support selection (e.g., `number`). */ async getSelectionStart() { var _a, _b; try { return (_b = (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.selectionStart) !== null && _b !== void 0 ? _b : null; } catch (_c) { // Some input types (e.g., number) throw InvalidStateError return null; } } /** * Returns the end position of the current text selection. * Returns `null` if the input element is not available or if * the input type does not support selection (e.g., `number`). */ async getSelectionEnd() { var _a, _b; try { return (_b = (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.selectionEnd) !== null && _b !== void 0 ? _b : null; } catch (_c) { // Some input types (e.g., number) throw InvalidStateError return null; } } /** * Returns the direction of the current text selection. * Can be `'forward'`, `'backward'`, or `'none'`. * Returns `null` if the input element is not available or if * the input type does not support selection (e.g., `number`). */ async getSelectionDirection() { var _a, _b; try { return (_b = (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.selectionDirection) !== null && _b !== void 0 ? _b : null; } catch (_c) { // Some input types (e.g., number) throw InvalidStateError return null; } } render() { const properties = this.getAdditionalProps(); properties['aria-labelledby'] = this.labelId; properties.class = 'mdc-text-field__input'; properties.ref = this.setInputElement; properties.onInput = this.handleInput; properties.onChange = this.handleChange; properties.onFocus = this.onFocus; properties.onBlur = this.onBlur; properties.required = this.required; properties.readonly = this.readonly; properties.disabled = this.disabled || this.readonly; let ariaControls = ''; if (this.hasHelperText()) { ariaControls += this.helperTextId; properties['aria-describedby'] = this.helperTextId; } if (this.renderAutocompleteList()) { if (ariaControls) { ariaControls += ' '; } ariaControls += this.portalId; } if (ariaControls) { properties['aria-controls'] = ariaControls; } return (h(Host, { key: 'be352ea1f105d4c3f77b567de32626488ea4a60b' }, h("limel-notched-outline", { key: '0bae1383ad7421ffdc3468bbfc79af59d7c2e3cb', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid || this.isInvalid(), disabled: this.disabled, readonly: this.readonly, hasValue: !!this.value, hasLeadingIcon: !!this.leadingIcon }, h("label", { key: '3667d9fbf90227232d8089a421455c7ab72e4202', slot: "content", class: this.getContainerClassList() }, this.renderLeadingIcon(), this.renderPrefix(), this.renderFormattedNumber(), this.renderInput(properties), this.renderSuffix(), this.renderTextarea(properties), this.renderTrailingLinkOrButton())), this.renderHelperLine(), this.renderAutocompleteList())); } valueWatcher(newValue) { if (!this.mdcTextField) { return; } if (this.changeWaiting) { return; } if (this.type === 'number' && this.isFocused && Number(newValue) === Number(this.mdcTextField.value)) { return; } if (newValue !== this.mdcTextField.value) { this.mdcTextField.value = newValue || ''; } if (this.wasInvalid) { this.validate(); } } completionsWatcher() { this.mapCompletions(); } get validationMessage() { var _a; if (this.isInvalid() && !this.invalid) { return ((_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.validationMessage) || ''; } return ''; } static get is() { return "limel-input-field"; } static get encapsulation() { return "shadow"; } static get delegatesFocus() { return true; } static get originalStyleUrls() { return { "$": ["input-field.scss"] }; } static get styleUrls() { return { "$": ["input-field.css"] }; } static get properties() { return { "disabled": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` to disable the field.\nUse `disabled` to indicate that the field can normally be interacted\nwith, but is currently disabled. This tells the user that if certain\nrequirements are met, the field may become enabled again." }, "getter": false, "setter": false, "reflect": true, "attribute": "disabled", "defaultValue": "false" }, "readonly": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` to make the field read-only.\nUse `readonly` when the field is only there to present the data it holds,\nand will not become possible for the current user to edit." }, "getter": false, "setter": false, "reflect": true, "attribute": "readonly", "defaultValue": "false" }, "invalid": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` to indicate that the current value of the input field is\ninvalid." }, "getter": false, "setter": false, "reflect": true, "attribute": "invalid", "defaultValue": "false" }, "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The input label." }, "getter": false, "setter": false, "reflect": true, "attribute": "label" }, "placeholder": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The placeholder text shown inside the input field, when the field is focused and empty." }, "getter": false, "setter": false, "reflect": true, "attribute": "placeholder" }, "helperText": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Optional helper text to display below the input field when it has focus" }, "getter": false, "setter": false, "reflect": true, "attribute": "helper-text" }, "prefix": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "A short piece of text to display before the value inside the input field.\nDisplayed for all types except `textarea`." }, "getter": false, "setter": false, "reflect": true, "attribute": "prefix" }, "suffix": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "A short piece of text to display after the value inside the input field.\nDisplayed for all types except `textarea`." }, "getter": false, "setter": false, "reflect": true, "attribute": "suffix" }, "required": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` to indicate that the field is required." }, "getter": false, "setter": false, "reflect": true, "attribute": "required", "defaultValue": "false" }, "value": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The value of the field." }, "getter": false, "setter": false, "reflect": true, "attribute": "value" }, "trailingIcon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Trailing icon to show to the far right in the field." }, "getter": false, "setter": false, "reflect": true, "attribute": "trailing-icon" }, "leadingIcon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Leading icon to show to the far left in the field." }, "getter": false, "setter": false, "reflect": true, "attribute": "leading-icon" }, "pattern": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Regular expression that the current value of the input field must match.\nNo forward slashes should be specified around the pattern.\nOnly used if type is `text`, `tel`, `email`, `url`, `urlAsText`,\n`password`, or `search`." }, "getter": false, "setter": false, "reflect": true, "attribute": "pattern" }, "type": { "type": "string", "mutable": false, "complexType": { "original": "InputType", "resolved": "\"date\" | \"datetime-local\" | \"email\" | \"month\" | \"number\" | \"password\" | \"search\" | \"tel\" | \"text\" | \"textarea\" | \"time\" | \"url\" | \"urlAsText\" | \"week\"", "references": { "InputType": { "location": "import", "path": "../input-field/input-field.types", "id": "src/components/input-field/input-field.types.ts::InputType", "referenceLocation": "InputType" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Type of input.\n\nNote** regarding type `url`: `limel-input` uses the native validation\nbuilt into the browser for many types of input fields. The native\nvalidation for `url` is very strict, and does not allow relative urls,\nnor any other formats that are not a \"fully qualified\" url. To allow\nsuch urls, use the type `urlAsText` instead. `urlAsText` works exactly\nlike `text` in all regards, except that it enables use of the `showLink`\nproperty." }, "getter": false, "setter": false, "reflect": true, "attribute": "type", "defaultValue": "'text'" }, "formatNumber": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` to format the current value of the input field only\nif the field is of type number.\nThe number format is determined by the current language of the browser." }, "getter": false, "setter": false, "reflect": true, "attribute": "format-number", "defaultValue": "true" }, "step": { "type": "any", "mutable": false, "complexType": { "original": "number | 'any'", "resolved": "\"any\" | number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Defines which numeric values are valid and the increment/decrement interval.\nFor example, `step={0.1}` allows decimals and steps by 0.1.\nSet to `'any'` to allow any numeric value.\nOnly applies when `type` is `number`." }, "getter": false, "setter": false, "reflect": true, "attribute": "step", "defaultValue": "'any'" }, "max": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Maximum allowed value if input type is `number`." }, "getter": false, "setter": false, "reflect": true, "attribute": "max" }, "min": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Minimum allowed value if input type is `number`." }, "getter": false, "setter": false, "reflect": true, "attribute": "min" }, "maxlength": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Maximum length of the value if type is `password`, `search`, `tel`,\n`text`, `url`, or `urlAsText`." }, "getter": false, "setter": false, "reflect": true, "attribute": "maxlength" }, "minlength": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Minimum length of the value if type is `password`, `search`, `tel`,\n`text`, `url`, or `urlAsText`." }, "getter": false, "setter": false, "reflect": true, "attribute": "minlength" }, "completions": { "type": "unknown", "mutable": false, "complexType": { "original": "string[]", "resolved": "string[]", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "list of suggestions `value` can autocomplete to." }, "getter": false, "setter": false, "defaultValue": "[]" }, "showLink": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "For inputs of type `email`, `tel`, `url`, and `urlAsText`, set this to\n`true` to show a trailing icon with a `mailto:`,`tel:`, or normal link,\nrespectively. The default icon can be overridden using the `trailingIcon`\nproperty." }, "getter": false, "setter": false, "reflect": true, "attribute": "show-link", "defaultValue": "false" }, "locale": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The locale to use for formatting numbers." }, "getter": false, "setter": false, "reflect": true, "attribute": "locale", "defaultValue": "globalConfig.defaultLocale" } }; } static get states() { return { "isFocused": {}, "wasInvalid": {}, "showCompletions": {} }; } static get events() { return [{ "method": "change", "name": "change", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the input value is changed." }, "complexType": { "original": "string", "resolved": "string", "references": {} } }, { "method": "action", "name": "action", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when `trailingIcon` or `leadingIcon` is set\nand the icon is interacted with." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }]; } static get methods() { return { "getSelectionStart": { "complexType": { "signature": "() => Promise<number | null>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<number>" }, "docs": { "text": "Returns the start position of the current text selection.\nReturns `null` if the input element is not available or if\nthe input type does not support selection (e.g., `number`).", "tags": [] } }, "getSelectionEnd": { "complexType": { "signature": "() => Promise<number | null>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<number>" }, "docs": { "text": "Returns the end position of the current text selection.\nReturns `null` if the input element is not available or if\nthe input type does not support selection (e.g., `number`).", "tags": [] } }, "getSelectionDirection": { "complexType": { "signature": "() => Promise<\"forward\" | \"backward\" | \"none\" | null>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<\"none\" | \"forward\" | \"backward\">" }, "docs": { "text": "Returns the direction of the current text selection.\nCan be `'forward'`, `'backward'`, or `'none'`.\nReturns `null` if the input element is not available or if\nthe input type does not support selection (e.g., `number`).", "tags": [] } } }; } static get elementRef() { return "limelInputField"; } static get watchers() { return [{ "propName": "value", "methodName": "valueWatcher" }, { "propName": "completions", "methodName": "completionsWatcher" }]; } }