mdui
Version:
实现 material you 设计规范的 Web Components 组件库
754 lines (753 loc) • 31.8 kB
JavaScript
import { __decorate } from "tslib";
import { html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { live } from 'lit/directives/live.js';
import { createRef, ref } from 'lit/directives/ref.js';
import { when } from 'lit/directives/when.js';
import { msg } from '@lit/localize';
import { $ } from '@mdui/jq/$.js';
import '@mdui/jq/methods/css.js';
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
import { FormController, formResets } from '@mdui/shared/controllers/form.js';
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
import { defaultValue } from '@mdui/shared/decorators/default-value.js';
import { watch } from '@mdui/shared/decorators/watch.js';
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
import { observeResize } from '@mdui/shared/helpers/observeResize.js';
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
import '@mdui/shared/icons/cancel--outlined.js';
import '@mdui/shared/icons/error.js';
import '@mdui/shared/icons/visibility-off.js';
import '@mdui/shared/icons/visibility.js';
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
import { FocusableMixin } from '@mdui/shared/mixins/focusable.js';
import { onLocaleReady, offLocaleReady } from '../../internal/localize.js';
import '../button-icon.js';
import '../icon.js';
import { style } from './style.js';
/**
* @summary 文本框组件
*
* ```html
* <mdui-text-field label="Text Field"></mdui-text-field>
* ```
*
* @event focus - 获得焦点时触发
* @event blur - 失去焦点时触发
* @event change - 在文本框的值变更,且失去焦点时触发
* @event input - 在文本框的值变更时触发
* @event invalid - 表单字段验证不通过时触发
* @event clear - 在点击由 `clearable` 属性生成的清空按钮时触发。可以通过调用 `event.preventDefault()` 阻止清空文本框
*
* @slot icon - 左侧图标
* @slot end-icon - 右侧图标
* @slot error-icon - 验证失败状态的右侧图标
* @slot prefix - 左侧文本
* @slot suffix - 右侧文本
* @slot clear-button - 清空按钮
* @slot clear-icon - 清空按钮中的图标
* @slot toggle-password-button - 密码显示状态切换按钮
* @slot show-password-icon - 显示密码状态下,密码显示状态切换按钮中的图标
* @slot hide-password-icon - 隐藏密码状态下,密码显示状态切换按钮中的图标
* @slot helper - 底部的帮助文本
*
* @csspart container - 文本框容器
* @csspart icon - 左侧图标
* @csspart end-icon - 右侧图标
* @csspart error-icon - 验证失败状态的右侧图标
* @csspart prefix - 左侧文本
* @csspart suffix - 右侧文本
* @csspart label - 上方的标签文本
* @csspart input - 内部的 `<input>` 或 `<textarea>` 元素
* @csspart clear-button - 清空按钮
* @csspart clear-icon - 清空按钮中的图标
* @csspart toggle-password-button - 密码显示状态切换按钮
* @csspart show-password-icon - 显示密码状态下,密码显示状态切换按钮中的图标
* @csspart hide-password-icon - 隐藏密码状态下,密码显示状态切换按钮中的图标
* @csspart supporting - 底部辅助信息容器,包括 helper、error、counter
* @csspart helper - 底部的帮助文本
* @csspart error - 底部的错误描述文本
* @csspart counter - 底部右侧的字数统计
*/
let TextField = class TextField extends FocusableMixin(MduiElement) {
constructor() {
super(...arguments);
/**
* 文本框的形状。默认为 `filled`。可选值包括:
*
* * `filled`:带背景色的文本框,视觉效果较强
* * `outlined`:带边框的文本框,视觉效果较弱
*/
this.variant = 'filled';
/**
* 文本框输入类型。默认为 `text`。可选值包括:
*
* * `text`:默认值。文本字段
* * `number`:只能输入数字。拥有动态键盘的设备上会显示数字键盘
* * `password`:用于输入密码,其值会被遮盖
* * `url`:用于输入 URL,会验证 URL 格式。在支持动态键盘的设备上有相应的键盘
* * `email`:用于输入邮箱地址,会验证邮箱格式。在支持动态键盘的设备上有相应的键盘
* * `search`:用于搜索框。拥有动态键盘的设备上的回车图标会变成搜索图标
* * `tel`:用于输入电话号码。拥有动态键盘的设备上会显示电话数字键盘
* * `hidden`:隐藏该控件,但其值仍会提交到服务器
* * `date`:输入日期的控件(年、月、日,不包括时间)。在支持的浏览器激活时打开日期选择器或年月日的数字滚轮
* * `datetime-local`:输入日期和时间的控件,不包括时区。在支持的浏览器激活时打开日期选择器或年月日的数字滚轮
* * `month`:输入年和月的控件,没有时区
* * `time`:用于输入时间的控件,不包括时区
* * `week`:用于输入以年和周数组成的日期,不带时区
*/
this.type = 'text';
/**
* 文本框名称,将与表单数据一起提交
*/
this.name = '';
/**
* 文本框的值,将与表单数据一起提交
*/
this.value = '';
/**
* 默认值。在重置表单时,将重置为该默认值。该属性只能通过 JavaScript 属性设置
*/
this.defaultValue = '';
/**
* 是否仅在获得焦点时,显示底部的帮助文本
*/
this.helperOnFocus = false;
/**
* 是否可清空文本框内容
*/
this.clearable = false;
/**
* 是否将文本右对齐
*/
this.endAligned = false;
/**
* 是否为只读模式
*/
this.readonly = false;
/**
* 是否禁用输入框
*/
this.disabled = false;
/**
* 提交表单时,是否必须填写该字段
*/
this.required = false;
/**
* 是否根据输入内容自动调整文本框高度
*/
this.autosize = false;
/**
* 是否显示字数统计,只在 `maxlength` 被指定时有效
*/
this.counter = false;
/**
* `type` 为 `password` 时,设置此属性会添加一个切换按钮,用于在明文和密文之间切换
*/
this.togglePassword = false;
/**
* 是否启用拼写检查
*/
this.spellcheck = false;
/**
* 是否验证未通过
*
* 该验证为浏览器原生验证 API,基于 `type`、`required`、`minlength`、`maxlength` 及 `pattern` 等属性的验证结果
*/
this.invalid = false;
/**
* 该属性设置为 true 时,则在样式上为 text-field 赋予 invalid 的状态。实际是否验证通过仍需根据 invalid 属性判断
* 该属性仅供 mdui 内部使用,当前 select 组件使用了该属性
*/
this.invalidStyle = false;
/**
* 该属性设置为 true 时,则在样式上为 text-field 赋予聚焦状态。实际是否聚焦仍然由 focusableMixin 控制
* 该属性仅供 mdui 内部使用,当前 select 组件使用了该属性
*/
this.focusedStyle = false;
this.isPasswordVisible = false;
this.hasValue = false;
/**
* 通过该属性传入了错误文案时,会优先显示该文案。需要配合 invalid=true 或 invalidStyle=true 使用
* 当前仅供 select 组件使用
*/
this.error = '';
this.inputRef = createRef();
this.formController = new FormController(this);
this.hasSlotController = new HasSlotController(this, 'icon', 'end-icon', 'helper', 'input');
/**
* 该属性设为 true 时,即使设置了 readonly,仍可以显示 clearable
* 当前仅供 select 组件使用
*/
this.readonlyButClearable = false;
}
/**
* 表单验证状态对象,具体参见 [`ValidityState`](https://developer.mozilla.org/zh-CN/docs/Web/API/ValidityState)
*/
get validity() {
return this.inputRef.value.validity;
}
/**
* 如果表单验证未通过,此属性将包含提示信息。如果验证通过,此属性将为空字符串
*/
get validationMessage() {
return this.inputRef.value.validationMessage;
}
/**
* 获取当前值,并转换为 `number` 类型;或设置一个 `number` 类型的值。
* 如果值无法被转换为 `number` 类型,则会返回 `NaN`。
*/
get valueAsNumber() {
return (this.inputRef.value?.valueAsNumber ??
parseFloat(this.value));
}
set valueAsNumber(newValue) {
const input = document.createElement('input');
input.type = 'number';
input.valueAsNumber = newValue;
this.value = input.value;
}
get focusElement() {
return this.inputRef.value;
}
get focusDisabled() {
return this.disabled;
}
/**
* 是否显示聚焦状态样式
*/
get isFocusedStyle() {
// @ts-ignore
return this.focused || this.focusedStyle;
}
/**
* 是否渲染为 textarea。为 false 时渲染为 input
*/
get isTextarea() {
return (this.rows && this.rows > 1) || this.autosize;
}
onDisabledChange() {
// 禁用状态始终为验证通过,所以 disabled 变更时需要重新校验
this.inputRef.value.disabled = this.disabled;
this.invalid = !this.inputRef.value.checkValidity();
}
async onValueChange() {
this.hasValue = !['', null].includes(this.value);
if (this.hasUpdated) {
await this.updateComplete;
this.setTextareaHeight();
// reset 引起的值变更,不执行验证;直接修改值引起的变更,需要进行验证
const form = this.formController.getForm();
if (form && formResets.get(form)?.has(this)) {
this.invalid = false;
formResets.get(form).delete(this);
}
else {
this.invalid = !this.inputRef.value.checkValidity();
}
}
}
onRowsChange() {
this.setTextareaHeight();
}
async onMaxRowsChange() {
if (!this.autosize) {
return;
}
if (!this.hasUpdated) {
await this.updateComplete;
}
// 设置最大高度,为 line-height * maxRows + padding-top + padding-bottom
const $input = $(this.inputRef.value);
$input.css('max-height', parseFloat($input.css('line-height')) * (this.maxRows ?? 1) +
parseFloat($input.css('padding-top')) +
parseFloat($input.css('padding-bottom')));
}
async onMinRowsChange() {
if (!this.autosize) {
return;
}
if (!this.hasUpdated) {
await this.updateComplete;
}
// 设置最小高度,为 line-height * minRows + padding-top + padding-bottom
const $input = $(this.inputRef.value);
$input.css('min-height', parseFloat($input.css('line-height')) * (this.minRows ?? 1) +
parseFloat($input.css('padding-top')) +
parseFloat($input.css('padding-bottom')));
}
connectedCallback() {
super.connectedCallback();
this.updateComplete.then(() => {
this.setTextareaHeight();
this.observeResize = observeResize(this.inputRef.value, () => this.setTextareaHeight());
});
}
disconnectedCallback() {
super.disconnectedCallback();
this.observeResize?.unobserve();
offLocaleReady(this);
}
/**
* 选中文本框中的文本
*/
select() {
this.inputRef.value.select();
}
/**
* 选中文本框中特定范围的内容
*
* @param start 被选中的第一个字符的位置索引,从 `0` 开始。如果这个值比元素的 `value` 长度还大,则会被看作 `value` 最后一个位置的索引
* @param end 被选中的最后一个字符的*下一个*位置索引。如果这个值比元素的 `value` 长度还大,则会被看作 `value` 最后一个位置的索引
* @param direction 一个表示选择方向的字符串,可能的值有:`forward`、`backward`、`none`
*/
setSelectionRange(start, end, direction = 'none') {
this.inputRef.value.setSelectionRange(start, end, direction);
}
/**
* 将文本框中特定范围的文本替换为新的文本
* @param replacement 要插入的字符串
* @param start 要替换的字符的起止位置的索引。默认为当前用户选中的字符的起始位置的索引
* @param end 要替换的字符的结束位置的索引。默认为当前用户选中的字符的结束位置的索引
* @param selectMode 文本被替换后,选取的状态。可选值为:
* * `select`:选择新插入的文本
* * `start`:将光标移动到新插入的文本的起始位置
* * `end`:将光标移动到新插入的文本的结束位置
* * `preserve`:默认值。尝试保留选取
*/
setRangeText(replacement, start, end, selectMode = 'preserve') {
this.inputRef.value.setRangeText(replacement, start, end, selectMode);
if (this.value !== this.inputRef.value.value) {
this.value = this.inputRef.value.value;
this.setTextareaHeight();
this.emit('input');
this.emit('change');
}
}
/**
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`
*/
checkValidity() {
const valid = this.inputRef.value.checkValidity();
if (!valid) {
this.emit('invalid', {
bubbles: false,
cancelable: true,
composed: false,
});
}
return valid;
}
/**
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`。
*
* 如果验证未通过,还会在组件上显示验证失败的提示。
*/
reportValidity() {
this.invalid = !this.inputRef.value.reportValidity();
if (this.invalid) {
this.emit('invalid', {
bubbles: false,
cancelable: true,
composed: false,
});
this.focus();
}
return !this.invalid;
}
/**
* 设置自定义的错误提示文本。只要这个文本不为空,就表示字段未通过验证
*
* @param message 自定义的错误提示文本
*/
setCustomValidity(message) {
this.setCustomValidityInternal(message);
// 外部调用 setCustomValidity 时,不再使用内置的验证规则,所以需要移除监听语言变更事件
offLocaleReady(this);
}
render() {
const hasIcon = !!this.icon || this.hasSlotController.test('icon');
const hasEndIcon = !!this.endIcon || this.hasSlotController.test('end-icon');
const hasErrorIcon = this.invalid || this.invalidStyle;
const hasTogglePasswordButton = this.type === 'password' && this.togglePassword && !this.disabled;
const hasClearButton = this.clearable &&
!this.disabled &&
(!this.readonly || this.readonlyButClearable) &&
(typeof this.value === 'number' || this.value.length > 0);
const hasPrefix = !!this.prefix || this.hasSlotController.test('prefix');
const hasSuffix = !!this.suffix || this.hasSlotController.test('suffix');
const hasHelper = !!this.helper || this.hasSlotController.test('helper');
const hasError = hasErrorIcon && !!(this.error || this.inputRef.value.validationMessage);
const hasCounter = this.counter && !!this.maxlength;
// 存在 input slot 时,隐藏组件内部的 .input 元素,使用 slot 代替
const hasInputSlot = this.hasSlotController.test('input');
const invalidClassNameObj = {
invalid: this.invalid,
'invalid-style': this.invalidStyle,
};
const className = classMap({
container: true,
'has-value': this.hasValue,
'has-icon': hasIcon,
'has-right-icon': hasEndIcon || hasErrorIcon,
'has-action': hasClearButton || hasTogglePasswordButton,
'has-prefix': hasPrefix,
'has-suffix': hasSuffix,
'is-firefox': navigator.userAgent.includes('Firefox'),
...invalidClassNameObj,
});
return html `<div part="container" class="${className}">${this.renderPrefix()}<div class="input-container">${this.renderLabel()} ${this.isTextarea
? this.renderTextArea(hasInputSlot)
: this.renderInput(hasInputSlot)} ${when(hasInputSlot, () => html `<slot name="input" class="input"></slot>`)}</div>${this.renderSuffix()}${this.renderClearButton(hasClearButton)} ${this.renderTogglePasswordButton(hasTogglePasswordButton)} ${this.renderRightIcon(hasErrorIcon)}</div>${when(hasError || hasHelper || hasCounter, () => html `<div part="supporting" class="${classMap({ supporting: true, ...invalidClassNameObj })}">${this.renderHelper(hasError, hasHelper)} ${this.renderCounter(hasCounter)}</div>`)}`;
}
setCustomValidityInternal(message) {
this.inputRef.value.setCustomValidity(message);
this.invalid = !this.inputRef.value.checkValidity();
this.requestUpdate();
}
onChange() {
this.value = this.inputRef.value.value;
if (this.isTextarea) {
this.setTextareaHeight();
}
this.emit('change');
}
onClear(event) {
this.value = '';
this.emit('clear');
this.emit('input');
this.emit('change');
this.focus();
event.stopPropagation();
}
onInput(event) {
event.stopPropagation();
this.value = this.inputRef.value.value;
if (this.isTextarea) {
this.setTextareaHeight();
}
this.emit('input');
}
onInvalid(event) {
event.preventDefault();
}
onKeyDown(event) {
const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
// 聚焦状态按下回车时,提交表单。可以在 keydown 事件中使用 event.preventDefault() 来取消提交表单
if (event.key === 'Enter' && !hasModifier) {
setTimeout(() => {
if (!event.defaultPrevented) {
this.formController.submit();
}
});
}
}
/**
* textarea 不支持 pattern 属性,所以在 keyup 时执行验证
*/
onTextAreaKeyUp() {
if (this.pattern) {
const patternRegex = new RegExp(this.pattern);
const hasError = this.value && !this.value.match(patternRegex);
if (hasError) {
this.setCustomValidityInternal(this.getPatternErrorMsg());
onLocaleReady(this, () => {
this.setCustomValidityInternal(this.getPatternErrorMsg());
});
}
else {
this.setCustomValidityInternal('');
offLocaleReady(this);
}
}
}
onTogglePassword() {
this.isPasswordVisible = !this.isPasswordVisible;
}
getPatternErrorMsg() {
return msg('Please match the requested format.', {
id: 'components.textField.patternError',
});
}
setTextareaHeight() {
if (this.autosize) {
this.inputRef.value.style.height = 'auto';
this.inputRef.value.style.height = `${this.inputRef.value.scrollHeight}px`;
}
else {
this.inputRef.value.style.height = undefined;
}
}
renderLabel() {
return this.label
? html `<label part="label" class="label">${this.label}</label>`
: nothingTemplate;
}
renderPrefix() {
return html `<slot name="icon" part="icon" class="icon">${this.icon
? html `<mdui-icon name="${this.icon}" class="i"></mdui-icon>`
: nothingTemplate}</slot><slot name="prefix" part="prefix" class="prefix">${this.prefix}</slot>`;
}
renderSuffix() {
return html `<slot name="suffix" part="suffix" class="suffix">${this.suffix}</slot>`;
}
renderRightIcon(hasErrorIcon) {
return hasErrorIcon
? html `<slot name="error-icon" part="error-icon" class="right-icon">${this.errorIcon
? html `<mdui-icon name="${this.errorIcon}" class="i"></mdui-icon>`
: html `<mdui-icon-error class="i"></mdui-icon-error>`}</slot>`
: html `<slot name="end-icon" part="end-icon" class="end-icon right-icon">${this.endIcon
? html `<mdui-icon name="${this.endIcon}" class="i"></mdui-icon>`
: nothingTemplate}</slot>`;
}
renderClearButton(hasClearButton) {
return when(hasClearButton, () => html `<slot name="clear-button" part="clear-button" class="action" ="${this.onClear}"><mdui-button-icon tabindex="-1"><slot name="clear-icon" part="clear-icon">${this.clearIcon
? html `<mdui-icon name="${this.clearIcon}" class="i"></mdui-icon>`
: html `<mdui-icon-cancel--outlined class="i"></mdui-icon-cancel--outlined>`}</slot></mdui-button-icon></slot>`);
}
renderTogglePasswordButton(hasTogglePasswordButton) {
return when(hasTogglePasswordButton, () => html `<slot name="toggle-password-button" part="toggle-password-button" class="action" ="${this.onTogglePassword}"><mdui-button-icon tabindex="-1">${this.isPasswordVisible
? html `<slot name="show-password-icon" part="show-password-icon">${this.showPasswordIcon
? html `<mdui-icon name="${this.showPasswordIcon}" class="i"></mdui-icon>`
: html `<mdui-icon-visibility-off class="i"></mdui-icon-visibility-off>`}</slot>`
: html `<slot name="hide-password-icon" part="hide-password-icon">${this.hidePasswordIcon
? html `<mdui-icon name="${this.hidePasswordIcon}" class="i"></mdui-icon>`
: html `<mdui-icon-visibility class="i"></mdui-icon-visibility>`}</slot>`}</mdui-button-icon></slot>`);
}
renderInput(hasInputSlot) {
return html `<input ${ref(this.inputRef)} part="input" class="input ${classMap({ 'hide-input': hasInputSlot })}" type="${this.type === 'password' && this.isPasswordVisible
? 'text'
: this.type}" name="${ifDefined(this.name)}" .value="${live(this.value)}" placeholder="${ifDefined(!this.label || this.isFocusedStyle || this.hasValue
? this.placeholder
: undefined)}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" ?required="${this.required}" minlength="${ifDefined(this.minlength)}" maxlength="${ifDefined(this.maxlength)}" min="${ifDefined(this.min)}" max="${ifDefined(this.max)}" step="${ifDefined(this.step)}" autocapitalize="${ifDefined(this.type === 'password' ? 'off' : this.autocapitalize)}" autocomplete="${this.autocomplete}" autocorrect="${ifDefined(this.type === 'password' ? 'off' : this.autocorrect)}" spellcheck="${ifDefined(this.spellcheck)}" pattern="${ifDefined(this.pattern)}" enterkeyhint="${ifDefined(this.enterkeyhint)}" inputmode="${ifDefined(this.inputmode)}" ="${this.onChange}" ="${this.onInput}" ="${this.onInvalid}" ="${this.onKeyDown}">`;
}
renderTextArea(hasInputSlot) {
return html `<textarea ${ref(this.inputRef)} part="input" class="input ${classMap({ 'hide-input': hasInputSlot })}" name="${ifDefined(this.name)}" .value="${live(this.value)}" placeholder="${ifDefined(!this.label || this.isFocusedStyle || this.hasValue
? this.placeholder
: undefined)}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" ?required="${this.required}" minlength="${ifDefined(this.minlength)}" maxlength="${ifDefined(this.maxlength)}" rows="${this.rows ?? 1}" autocapitalize="${ifDefined(this.autocapitalize)}" autocorrect="${ifDefined(this.autocorrect)}" spellcheck="${ifDefined(this.spellcheck)}" enterkeyhint="${ifDefined(this.enterkeyhint)}" inputmode="${ifDefined(this.inputmode)}" ="${this.onChange}" ="${this.onInput}" ="${this.onInvalid}" ="${this.onKeyDown}" ="${this.onTextAreaKeyUp}"></textarea>`;
}
/**
* @param hasError 是否包含错误提示
* @param hasHelper 是否含 helper 属性或 helper slot
*/
renderHelper(hasError, hasHelper) {
return hasError
? html `<div part="error" class="error">${this.error || this.inputRef.value.validationMessage}</div>`
: hasHelper
? html `<slot name="helper" part="helper" class="helper">${this.helper}</slot>`
: // 右边有 counter,需要占位
html `<span></span>`;
}
renderCounter(hasCounter) {
return hasCounter
? html `<div part="counter" class="counter">${this.value.length}/${this.maxlength}</div>`
: nothingTemplate;
}
};
TextField.styles = [componentStyle, style];
__decorate([
property({ reflect: true })
], TextField.prototype, "variant", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "type", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "name", void 0);
__decorate([
property()
], TextField.prototype, "value", void 0);
__decorate([
defaultValue()
], TextField.prototype, "defaultValue", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "label", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "placeholder", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "helper", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
attribute: 'helper-on-focus',
})
], TextField.prototype, "helperOnFocus", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TextField.prototype, "clearable", void 0);
__decorate([
property({ reflect: true, attribute: 'clear-icon' })
], TextField.prototype, "clearIcon", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
attribute: 'end-aligned',
})
], TextField.prototype, "endAligned", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "prefix", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "suffix", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "icon", void 0);
__decorate([
property({ reflect: true, attribute: 'end-icon' })
], TextField.prototype, "endIcon", void 0);
__decorate([
property({ reflect: true, attribute: 'error-icon' })
], TextField.prototype, "errorIcon", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "form", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TextField.prototype, "readonly", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TextField.prototype, "disabled", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TextField.prototype, "required", void 0);
__decorate([
property({ type: Number, reflect: true })
], TextField.prototype, "rows", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TextField.prototype, "autosize", void 0);
__decorate([
property({ type: Number, reflect: true, attribute: 'min-rows' })
], TextField.prototype, "minRows", void 0);
__decorate([
property({ type: Number, reflect: true, attribute: 'max-rows' })
], TextField.prototype, "maxRows", void 0);
__decorate([
property({ type: Number, reflect: true })
], TextField.prototype, "minlength", void 0);
__decorate([
property({ type: Number, reflect: true })
], TextField.prototype, "maxlength", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TextField.prototype, "counter", void 0);
__decorate([
property({ type: Number, reflect: true })
], TextField.prototype, "min", void 0);
__decorate([
property({ type: Number, reflect: true })
], TextField.prototype, "max", void 0);
__decorate([
property({ type: Number, reflect: true })
], TextField.prototype, "step", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "pattern", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
attribute: 'toggle-password',
})
], TextField.prototype, "togglePassword", void 0);
__decorate([
property({ reflect: true, attribute: 'show-password-icon' })
], TextField.prototype, "showPasswordIcon", void 0);
__decorate([
property({ reflect: true, attribute: 'hide-password-icon' })
], TextField.prototype, "hidePasswordIcon", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "autocapitalize", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "autocorrect", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "autocomplete", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "enterkeyhint", void 0);
__decorate([
property({ type: Boolean, reflect: true, converter: booleanConverter })
], TextField.prototype, "spellcheck", void 0);
__decorate([
property({ reflect: true })
], TextField.prototype, "inputmode", void 0);
__decorate([
state()
], TextField.prototype, "invalid", void 0);
__decorate([
state()
], TextField.prototype, "invalidStyle", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
attribute: 'focused-style',
})
], TextField.prototype, "focusedStyle", void 0);
__decorate([
state()
], TextField.prototype, "isPasswordVisible", void 0);
__decorate([
state()
], TextField.prototype, "hasValue", void 0);
__decorate([
state()
], TextField.prototype, "error", void 0);
__decorate([
watch('disabled', true)
], TextField.prototype, "onDisabledChange", null);
__decorate([
watch('value')
], TextField.prototype, "onValueChange", null);
__decorate([
watch('rows', true)
], TextField.prototype, "onRowsChange", null);
__decorate([
watch('maxRows')
], TextField.prototype, "onMaxRowsChange", null);
__decorate([
watch('minRows')
], TextField.prototype, "onMinRowsChange", null);
TextField = __decorate([
customElement('mdui-text-field')
], TextField);
export { TextField };