diff --git a/Readme.md b/Readme.md index 93faafc..b9086cf 100644 --- a/Readme.md +++ b/Readme.md @@ -22,7 +22,7 @@ - [ ] `wc-badge`徽标组件 - [ ] `wc-counter`倒计时组件 - [ ] `wc-drag`拖拽组件 -- [ ] `wc-button`表单组件-按钮 +- [x] `wc-button`表单组件-按钮 - [ ] `wc-checkbox`表单组件-复选框 - [ ] `wc-input`表单组件-文本输入框 - [ ] `wc-number`表单组件-步进数字输入 diff --git a/develop.md b/develop.md index 4f0c8c7..28ad8b2 100644 --- a/develop.md +++ b/develop.md @@ -18,7 +18,7 @@ - +
diff --git a/src/form/button.js b/src/form/button.js index a43abf2..ec63169 100644 --- a/src/form/button.js +++ b/src/form/button.js @@ -4,207 +4,267 @@ * @date 2023/03/06 15:17:25 */ -import { css, html, Component } from '@bd/core' +import { css, html, Component, $, nextTick } from '@bd/core' import '../icon/index.js' class Button extends Component { static props = { + type: 'primary', icon: '', - autofocus: '', - loading: false, + size: 'l', + autofocus: false, + loading: { + type: Boolean, + default: false, + observer(val) { + if (val) { + this.cacheIcon = this.icon + this.icon = 'loading' + } else { + this.icon = this.cacheIcon || '' + } + } + }, disabled: false, lazy: 0 // 并发拦截时间, 单位毫秒 } - static styles = css` - :host { - overflow: hidden; - display: inline-flex; - min-width: 128px; - height: 36px; - border-radius: 3px; - user-select: none; - -moz-user-select: none; - color: var(--color-dark-1); - font-size: 14px; - cursor: pointer; - transition: box-shadow 0.15s linear; + static styles = [ + // 基础样式 + css` + :host { + overflow: hidden; + display: inline-flex; + border: 0; + border-radius: 3px; + user-select: none; + -moz-user-select: none; + color: var(--color-dark-1); + font-size: 14px; + cursor: pointer; + transition: box-shadow 0.15s linear; - button { - display: flex; - justify-content: space-evenly; - align-items: center; - width: 100%; - height: inherit; - padding: var(--padding, 0 14px); - line-height: 1; - border: 1px solid var(--color-grey-2); - border-radius: inherit; - white-space: nowrap; - background: #fff; - font-size: inherit; - font-family: inherit; - outline: none; - color: inherit; - cursor: inherit; - transition: background 0.15s linear; - - &::-moz-focus-inner { - border: none; - } - } - - .icon { - --size: var(--icon-size, 18px); - } - } - - :host([size='large']) { - min-width: 212px; - height: 52px; - font-size: 18px; - - button { - padding: 0 24px; - } - - .icon { - --size: 26px; - } - } - :host([size='large'][circle]) { - min-width: 52px; - width: 52px; - height: 52px; - - button { - padding: 0; - } - } - :host([size='medium']) { - min-width: 160px; - height: 44px; - - button { - padding: 0 18px; - } - } - :host([size='medium'][circle]) { - min-width: 44px; - width: 44px; - } - :host([size='small']) { - min-width: 96px; - height: 32px; - } - :host([size='small'][circle]) { - min-width: 32px; - width: 32px; - } - :host([size='mini']) { - min-width: 72px; - height: 26px; - font-size: 12px; - - button { - padding: 0 6px; - } - - .icon { - --size: 14px; - } - } - :host([size='mini'][circle]) { - min-width: 26px; - width: 26px; - } - - :host([round]) { - border-radius: 26px; - } - :host([circle]) { - min-width: 36px; - width: 36px; - border-radius: 50%; - button { - padding: 0; - } - .icon { - margin-right: 0; - } - - slot { - display: none; - } - } - - :host(:focus-within) { - box-shadow: 0 0 0 2px var(--color-plain-a); - } - - $colors: ( - primary: 'teal', - info: 'blue', - success: 'green', - warning: 'orange', - danger: 'red', - secondary: 'dark', - help: 'grey' - ); - - @loop $t, $c in $colors { - :host([type='#{$t}']) { button { - color: var(--color-#{$c}-2); - border: 1px solid var(--color-#{$c}-2); + display: flex; + justify-content: center; + align-items: center; + width: 100%; + min-width: 1px; + height: inherit; + padding: var(--button-padding, 0 4px); + line-height: 1; + border: 1px solid transparent; + border-radius: inherit; + white-space: nowrap; + background: #fff; + font-size: inherit; + font-family: inherit; + outline: none; + color: inherit; + cursor: inherit; + transition: background 0.15s linear; - &:hover { - color: var(--color-#{$c}-1); - border-color: var(--color-#{$c}-1); - } - &:active { - color: var(--color-#{$c}-3); - } - &:disabled { - color: var(--color-#{$c}-2); + &::-moz-focus-inner { + border: none; } } - &:host([solid]) button { - border: 0; - color: #fff; - background: var(--color-#{$c}-2); - - &:hover { - background: var(--color-#{$c}-1); - } - &:active { - background: var(--color-#{$c}-3); - } - - &:disabled { - background: var(--color-#{$c}-2); - } - } - - &:host(:focus-within) { - box-shadow: 0 0 0 2px var(--color-#{$c}-a); + .icon { + --size: var(--icon-size, 18px); + margin-right: 4px; } } - } + :host(:focus-within) { + box-shadow: 0 0 0 2px var(--color-plain-a); + } + `, + // 尺寸 + css` + @use 'sass:map'; + $sizes: ( + s: ( + w: 52px, + h: 20px, + f: 12px + ), + m: ( + w: 72px, + 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 + ), + xxxxl: ( + w: 212px, + h: 64px, + f: 18px + ) + ); - :host([loading]), - :host([disabled]) { - cursor: not-allowed; - opacity: 0.6; + @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'); + + .icon { + --size: #{map.get($v, 'f')}; + } + } + :host([size='#{$s}'][circle]) { + width: map.get($v, 'h'); + height: map.get($v, 'h'); + + button { + } + } + } + + :host([dashed]) button { + border-style: dashed; + } + + :host([round]) { + border-radius: 32px; + } + :host([circle]) { + min-width: 0; + border-radius: 50%; + button { + padding: 0; + } + .icon { + margin-right: 0; + } + + slot { + display: none; + } + } + `, + // 配色 + css` + $colors: ( + primary: 'teal', + info: 'blue', + success: 'green', + warning: 'orange', + danger: 'red', + secondary: 'dark', + help: 'grey' + ); + + @loop $t, $c in $colors { + :host([type='#{$t}']) { + button { + color: var(--color-#{$c}-2); + border-color: var(--color-#{$c}-2); + + &:hover { + color: var(--color-#{$c}-1); + border-color: var(--color-#{$c}-1); + } + &:active { + color: var(--color-#{$c}-3); + } + &:disabled { + color: var(--color-#{$c}-2); + } + } + + &:host([solid]) button { + border: 0; + color: #fff; + background: var(--color-#{$c}-2); + + &:hover { + background: var(--color-#{$c}-1); + } + &:active { + background: var(--color-#{$c}-3); + } + + &:disabled { + background: var(--color-#{$c}-2); + } + } + + &:host(:focus-within) { + box-shadow: 0 0 0 2px var(--color-#{$c}-a); + } + } + } + `, + // 状态 + css` + :host([loading]), + :host([disabled]) { + cursor: not-allowed; + opacity: 0.6; + } + ` + ] + + created() { + this.stamp = 0 + + this._clickFn = this.$on( + 'click', + ev => { + let { loading, disabled, lazy } = this + let now = Date.now() + + if (loading || disabled) { + return ev.stopPropagation() + } + // 并发拦截 + if (lazy > 0 && now - this.stamp < lazy) { + return ev.stopPropagation() + } + this.stamp = now + }, + true + ) + } + + mounted() { + if (this.autofocus) { + let $btn = $('button', this.root) + $btn.setAttribute('autofocus', '') + // 需要focus()才能聚焦成功 + nextTick(_ => $btn.focus()) } - ` + } + + unmounted() { + this.$off('click', this._clickFn) + } render() { - return html`` + return html` + + ` } } diff --git a/src/form/link.js b/src/form/link.js new file mode 100644 index 0000000..3e25971 --- /dev/null +++ b/src/form/link.js @@ -0,0 +1,156 @@ +/** + * {} + * @author yutent