diff --git a/src/form/input.js b/src/form/input.js new file mode 100644 index 0000000..5ad259a --- /dev/null +++ b/src/form/input.js @@ -0,0 +1,368 @@ +/** + * {按钮组件} + * @author yutent + * @date 2023/03/06 15:17:25 + */ + +import { $, bind, unbind, nextTick, css, html, Component } from '@bd/core' +import '../icon/index.js' + +class Input extends Component { + static props = { + readonly: false, + autofocus: false, + disabled: false, + icon: '', + placeholder: '', + maxlength: '', + minlength: '', + value: '', + 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); + } + } + + .prepend, + .append { + 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; + + 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; + } + } + + /* ----- 类型(颜色) ----- */ + $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); + } + } + } + + /* --- */ + :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; + } + } + ` + + render() { + return 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) + } + } + + mounted() { + this.#formatSlot() + + let $input = $('input', this.root) + if (this.autofocus) { + $input.setAttribute('autofocus', '') + // 需要focus()才能聚焦成功 + nextTick(() => $input.focus()) + } + + bind($input, 'input', e => { + e.stopPropagation() + this.value = e.target.value + this.$emit('input') + }) + } +} + +customElements.define('wc-input', Input)