diff --git a/src/form/input.js b/src/form/input.js index 5ad259a..775de26 100644 --- a/src/form/input.js +++ b/src/form/input.js @@ -4,364 +4,387 @@ * @date 2023/03/06 15:17:25 */ -import { $, bind, unbind, nextTick, css, html, Component } from '@bd/core' +import { nextTick, css, html, Component } from '@bd/core' import '../icon/index.js' class Input extends Component { static props = { - readonly: false, + readOnly: false, autofocus: false, disabled: false, + closeable: false, icon: '', placeholder: '', - maxlength: '', - minlength: '', - value: '', + maxlength: null, + minlength: null, + value: { + type: String, + default: '', + attribute: false, + observer(val) { + if (this.$refs) { + this.$refs.input.value = val + } + } + }, lazy: 0 // 并发拦截时间, 单位毫秒 } - static styles = css` - :host { - overflow: hidden; - display: inline-flex; - min-width: 228px; - user-select: none; - -moz-user-select: none; - color: var(--color-dark-1); - border-radius: 3px; - cursor: text; - transition: box-shadow 0.15s linear; - } - - .label { - flex: 1; - display: flex; - justify-content: center; - align-items: center; - height: 36px; - font-size: 14px; - border: 1px solid var(--color-grey-2); - border-radius: inherit; - background: var(--bg-color, #fff); - color: inherit; - cursor: inherit; - - input { - flex: 1; - min-width: 36px; - width: 0; - height: 100%; - padding: 0 8px; - border: 0; - border-radius: inherit; - font: inherit; - color: inherit; - background: none; - outline: none; - box-shadow: none; - cursor: inherit; - - &::placeholder { - color: var(--color-grey-1); - } + static styles = [ + css` + :host { + overflow: hidden; + display: inline-flex; + min-width: 228px; + height: 36px; + user-select: none; + -moz-user-select: none; + color: var(--color-dark-1); + border-radius: 3px; + cursor: text; + transition: box-shadow 0.15s linear; } - .prepend, - .append { + .label { + flex: 1; display: flex; justify-content: center; align-items: center; - width: auto; - height: 34px; - padding: 0 10px; - line-height: 1; - white-space: nowrap; - } - .prepend { - border-right: 1px solid var(--color-grey-a); - border-radius: 6px 0 0 6px; - } - .append { - border-left: 1px solid var(--color-grey-a); - border-radius: 0 6px 6px 0; - } - &[prepend] .prepend, - &[append] .append { - display: flex; - } - &[prepend] input, - &[append] input { - min-width: 64px; - } - /* ----- */ - .close { - display: none; - --size: 16px; - margin: 0 8px 0 4px; - padding: 4px; - border-radius: 50%; - color: var(--color-grey-2); - cursor: pointer; - transition: background 0.15s linear; - - &:hover { - background: var(--color-plain-1); - } - - &.show { - display: block; - } - } - } - - .suggestion { - overflow: hidden; - display: none; - position: fixed; - z-index: 10240; - left: 0; - top: 0; - width: 200px; - height: auto; - max-height: 200px; - min-height: 46px; - padding: 4px 0; - border-radius: 4px; - background: var(--color-plain-1); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); - - .list { - width: 100%; - } - &.show { - display: flex; - } - - li { - overflow: hidden; - width: 100%; - height: 30px; - line-height: 30px; - padding: 0 8px; - text-overflow: ellipsis; - white-space: nowrap; - cursor: pointer; - - &:hover, - &[focus] { - background: var(--color-plain-2); - } - } - } - - /* 额外样式 */ - :host([round]) { - border-radius: 26px; - - .label input { - padding: 0 10px; - margin: 0 18px; - } - - .label[prepend] input, - .label[append] input { - padding: 0 5px; - } - .label[prepend] input { - margin-left: 0; - } - .label[append] input { - margin-right: 0; - } - - .prepend { - border-radius: 26px 0 0 26px; - } - .append { - border-radius: 0 26px 26px 0; - } - } - - :host([size='large']) { - min-width: 234px; - .label { - height: 52px; - font-size: 18px; + height: 100%; + font-size: 14px; + border: 1px solid var(--color-grey-2); + border-radius: inherit; + background: var(--bg-color, #fff); + color: inherit; + cursor: inherit; input { - padding: 0 16px; + flex: 1; + min-width: 36px; + width: 0; + height: 100%; + padding: 0 8px; + border: 0; + border-radius: inherit; + font: inherit; + color: inherit; + background: none; + outline: none; + box-shadow: none; + cursor: inherit; + + &::placeholder { + color: var(--color-grey-1); + } } - } - .prepend, - .append { - height: 48px; - padding: 0 16px; - } - .icon { - --size: 24px; - margin: 0 20px 0 4px; - } - } - :host([size='medium']) { - min-width: 160px; - .label { - height: 44px; - - input { - padding: 0 10px; - } - } - .prepend, - .append { - height: 40px; - } - } - :host([size='small']) { - min-width: 96px; - .label { - height: 32px; - - input { - padding: 0 6px; - } - } - .prepend, - .append { - height: 28px; - } - } - :host([size='mini']) { - min-width: 72px; - .label { - height: 26px; - font-size: 12px; - } - .icon { - --size: 14px; - } - .prepend, - .append { - height: 22px; - } - } - - /* ----- 类型(颜色) ----- */ - $colors: ( - primary: 'teal', - info: 'blue', - success: 'green', - warning: 'orange', - danger: 'red', - secondary: 'dark', - help: 'grey' - ); - :host(:focus-within) { - box-shadow: 0 0 0 2px var(--color-plain-a); - } - @loop $t, $c in $colors { - :host([type='#{$t}']:focus-within) { - box-shadow: 0 0 0 2px var(--color-#{$c}-a); - } - - :host([type='#{$t}']) .label { - border-color: var(--color-#{$c}-2); .prepend, .append { - border-color: var(--color-#{$c}-a); + display: flex; + justify-content: center; + align-items: center; + width: auto; + white-space: nowrap; } - } - } - /* --- */ - :host([disabled]) { - pointer-events: none; - cursor: not-allowed; - - .label { - border-color: var(--color-grey-1); - background: var(--color-plain-1); - opacity: 0.6; - } - } - :host([readonly]) { - cursor: default; - } - - :host([no-border]), - :host(:focus-within[no-border]) { - .label { - border: 0; - - &[prepend] input { - padding-left: 2px; + &[prepend] .prepend, + &[append] .append { + display: flex; } + &[prepend] input, &[append] input { - padding-right: 2px; + min-width: 64px; + } + /* ----- */ + .close { + --size: 18px; + margin: 0 8px 0 4px; + padding: 4px; + border-radius: 50%; + color: var(--color-grey-2); + cursor: pointer; + transition: background 0.15s linear; + + &:hover { + background: var(--color-plain-1); + } } } - .prepend, - .append { - border: 0; + + .suggestion { + overflow: hidden; + display: none; + position: fixed; + z-index: 10240; + left: 0; + top: 0; + width: 200px; + height: auto; + max-height: 200px; + min-height: 46px; + padding: 4px 0; + border-radius: 4px; + background: var(--color-plain-1); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); + + .list { + width: 100%; + } + &.show { + display: flex; + } + + li { + overflow: hidden; + width: 100%; + height: 30px; + line-height: 30px; + padding: 0 8px; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + + &:hover, + &[focus] { + background: var(--color-plain-2); + } + } } - } - ` + + /* 额外样式 */ + :host([round]) { + border-radius: 26px; + + .label input { + padding: 0 10px; + // margin: 0 18px; + } + + .label[prepend] input, + .label[append] input { + padding: 0 5px; + } + } + + :host([size='large']) { + min-width: 234px; + .label { + height: 52px; + font-size: 18px; + + input { + padding: 0 16px; + } + } + .prepend, + .append { + height: 48px; + padding: 0 16px; + } + + .icon { + --size: 24px; + margin: 0 20px 0 4px; + } + } + :host([size='medium']) { + min-width: 160px; + .label { + height: 44px; + + input { + padding: 0 10px; + } + } + .prepend, + .append { + height: 40px; + } + } + :host([size='small']) { + min-width: 96px; + .label { + height: 32px; + + input { + padding: 0 6px; + } + } + .prepend, + .append { + height: 28px; + } + } + :host([size='mini']) { + min-width: 72px; + .label { + height: 26px; + font-size: 12px; + } + .icon { + --size: 14px; + } + .prepend, + .append { + height: 22px; + } + } + + :host(:focus-within) { + box-shadow: 0 0 0 2px var(--color-plain-a); + } + /* --- */ + :host([disabled]) { + pointer-events: none; + cursor: not-allowed; + + .label { + border-color: var(--color-grey-1); + background: var(--color-plain-1); + opacity: 0.6; + } + } + :host([readonly]) { + cursor: default; + } + + :host([no-border]), + :host(:focus-within[no-border]) { + .label { + border: 0; + + &[prepend] input { + padding-left: 2px; + } + &[append] input { + padding-right: 2px; + } + } + .prepend, + .append { + border: 0; + } + } + `, + //尺寸 + css` + @use 'sass:map'; + $sizes: ( + m: ( + w: 82px, + h: 24px, + f: 12px + ), + l: ( + w: 108px, + h: 32px, + f: 14px + ), + xl: ( + w: 132px, + h: 36px, + f: 14px + ), + xxl: ( + w: 160px, + h: 44px, + f: 14px + ), + xxxl: ( + w: 192px, + h: 52px, + f: 16px + ) + ); + + @loop $s, $v in $sizes { + :host([size='#{$s}']) { + min-width: map.get($v, 'w'); + height: map.get($v, 'h'); + font-size: map.get($v, 'f'); + .label { + height: map.get($v, 'h'); + font-size: map.get($v, 'f'); + } + .icon { + --size: #{map.get($v, 'f')}; + } + } + :host([size='#{$s}'][circle]) { + width: map.get($v, 'h'); + height: map.get($v, 'h'); + } + } + `, + + /* ----- 类型(颜色) ----- */ + css` + $colors: ( + primary: 'teal', + info: 'blue', + success: 'green', + warning: 'orange', + danger: 'red', + secondary: 'dark', + help: 'grey' + ); + + @loop $t, $c in $colors { + :host([type='#{$t}']:focus-within) { + box-shadow: 0 0 0 2px var(--color-#{$c}-a); + } + + :host([type='#{$t}']) .label { + border-color: var(--color-#{$c}-2); + .prepend, + .append { + border-color: var(--color-#{$c}-a); + } + } + } + ` + ] + renderClose() { + return html`` + } render() { return html`
- - - + ${this.closeable && this.value ? this.renderClose() : ''} + ${this.icon + ? html`` + : html``}
` } - #formatSlot() { - const label = this.root.children[0] - const prepend = label.children.prepend.assignedNodes() - const append = label.children.append.assignedNodes() - - if (prepend.length) { - while (prepend.length > 1) { - this.removeChild(prepend.pop()) - } - label.setAttribute('prepend', '') - } else { - label.removeChild(label.children.prepend) - } - - if (append.length) { - while (append.length > 1) { - this.removeChild(append.pop()) - } - label.setAttribute('append', '') - } else { - !this.icon && label.removeChild(label.children.append) - } + onInput(e) { + this.value = e.currentTarget.value + } + onClickClose() { + this.$refs.input.value = '' + this.value = '' } - mounted() { - this.#formatSlot() - - let $input = $('input', this.root) if (this.autofocus) { - $input.setAttribute('autofocus', '') - // 需要focus()才能聚焦成功 - nextTick(() => $input.focus()) + // 火狐浏览器需要手动focus()才能聚焦成功 + nextTick(_ => this.$refs.input.focus()) } - - bind($input, 'input', e => { - e.stopPropagation() - this.value = e.target.value - this.$emit('input') - }) } }