From 95766415033668e6f68bfd68869e749dc4f7a115 Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Tue, 26 May 2020 20:28:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20TabsTransfer=20=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/components/Page/Form.jsx | 121 ++++++++++++++++ scss/components/_search-box.scss | 58 ++++++++ scss/components/_table.scss | 35 ++--- scss/components/form/_checks.scss | 23 +++ scss/components/form/_selections.scss | 1 + scss/components/form/_transfer.scss | 60 +++++++- scss/themes/cxd.scss | 1 + scss/themes/dark.scss | 1 + scss/themes/default.scss | 1 + src/components/InputBox.tsx | 14 +- src/components/NestedCheckboxes.tsx | 98 +++++++++++++ src/components/ResultBox.tsx | 14 +- src/components/SearchBox.tsx | 82 +++++++++++ src/components/Select.tsx | 1 + src/components/Tabs.tsx | 109 +++++++------- src/components/Transfer.tsx | 69 +++++++-- src/components/TreeCheckboxes.tsx | 6 +- src/components/index.tsx | 6 +- src/index.tsx | 1 + src/renderers/Form/TabsTransfer.tsx | 198 ++++++++++++++++++++++++++ src/renderers/Form/Tag.tsx | 6 +- src/renderers/Form/Transfer.tsx | 26 ++-- src/theme.tsx | 14 +- 23 files changed, 826 insertions(+), 119 deletions(-) create mode 100644 scss/components/_search-box.scss create mode 100644 src/components/NestedCheckboxes.tsx create mode 100644 src/components/SearchBox.tsx create mode 100644 src/renderers/Form/TabsTransfer.tsx diff --git a/examples/components/Page/Form.jsx b/examples/components/Page/Form.jsx index ed3a757a..d4d794a4 100644 --- a/examples/components/Page/Form.jsx +++ b/examples/components/Page/Form.jsx @@ -17,6 +17,127 @@ export default { label: 'Email', type: 'email', name: 'email' + }, + + { + label: 'Transfer', + type: 'transfer', + name: 'transfer', + sortable: true, + selectMode: 'nested', + searchable: true, + options: [ + { + label: '诸葛亮', + value: 'zhugeliang' + }, + { + label: '曹操', + value: 'caocao' + }, + { + label: '钟无艳', + value: 'zhongwuyan' + }, + { + label: '野核', + children: [ + { + label: '李白', + value: 'libai' + }, + { + label: '韩信', + value: 'hanxin' + }, + { + label: '云中君', + value: 'yunzhongjun' + } + ] + } + ] + }, + + { + label: 'Transfer', + type: 'tabs-transfer', + name: 'transfer2', + sortable: true, + selectMode: 'tree', + searchable: true, + options: [ + { + label: '成员', + selectMode: 'tree', + children: [ + { + label: '诸葛亮', + value: 'zhugeliang' + }, + { + label: '曹操', + value: 'caocao' + }, + { + label: '钟无艳', + value: 'zhongwuyan' + }, + { + label: '野核', + children: [ + { + label: '李白', + value: 'libai' + }, + { + label: '韩信', + value: 'hanxin' + }, + { + label: '云中君', + value: 'yunzhongjun' + } + ] + } + ] + }, + + { + label: '用户', + children: [ + { + label: '诸葛亮', + value: 'zhugeliang2' + }, + { + label: '曹操', + value: 'caocao2' + }, + { + label: '钟无艳', + value: 'zhongwuyan2' + }, + { + label: '野核', + children: [ + { + label: '李白', + value: 'libai2' + }, + { + label: '韩信', + value: 'hanxin2' + }, + { + label: '云中君', + value: 'yunzhongjun2' + } + ] + } + ] + } + ] } ] } diff --git a/scss/components/_search-box.scss b/scss/components/_search-box.scss new file mode 100644 index 00000000..03a7b723 --- /dev/null +++ b/scss/components/_search-box.scss @@ -0,0 +1,58 @@ +.#{$ns}SearchBox { + display: inline-flex; + flex-direction: row; + + line-height: $Form-input-lineHeight; + font-size: $Form-input-fontSize; + flex-wrap: nowrap; + align-items: center; + justify-content: flex-end; + + height: 30px; + width: 30px; + padding: 0 8px; + + transition: all 0.3s ease-in-out; + border: $Form-input-borderWidth solid transparent; + border-radius: $Form-input-borderRadius; + + &:hover { + background-color: rgba($Form-input-bg, 0.6); + } + + &.is-active { + background-color: $Form-input-bg; + border: $Form-input-borderWidth solid $Form-input-borderColor; + width: 150px; + > input { + flex-grow: 1; + } + } + + &-activeBtn, + &-cancelBtn { + cursor: pointer; + color: $icon-color; + + &:hover { + color: $icon-onHover-color; + } + } + + > input { + outline: none; + border: none; + background: transparent; + color: $Form-input-color; + + width: 0; + height: $Form-input-lineHeight * $Form-input-fontSize; + + &::placeholder { + color: $Form-input-placeholderColor; + user-select: none; + } + } + + height: 30px; +} diff --git a/scss/components/_table.scss b/scss/components/_table.scss index 56f098b1..50a0f2d2 100644 --- a/scss/components/_table.scss +++ b/scss/components/_table.scss @@ -348,7 +348,7 @@ @for $i from 2 through 10 { tr.#{$ns}Table-tr--#{$i}th.is-expanded { .#{$ns}Table-expandCell:before { - right: px2rem(9px) + px2rem(-20px) * ($i - 1); + right: px2rem(7px) + px2rem(-20px) * ($i - 1); } } @@ -367,7 +367,7 @@ width: px2rem(1px); top: 0; bottom: 0; - left: px2rem(-10px) + px2rem(20px) * ($i - 2); + left: px2rem(-8px) + px2rem(20px) * ($i - 2); height: auto; background-color: $Table-tree-borderColor; } @@ -376,8 +376,8 @@ content: ''; position: absolute; height: px2rem(1px); - top: px2rem(20px); - left: px2rem(-10px) + px2rem(20px) * ($i - 2); + top: px2rem(18px); + left: px2rem(-8px) + px2rem(20px) * ($i - 2); width: px2rem(10px); background-color: $Table-tree-borderColor; } @@ -395,7 +395,7 @@ tr.#{$ns}Table-tr--#{$i}th.is-last:not(.is-expanded) { .#{$ns}Table-expandCell + td { &::before { - height: px2rem(20px); + height: px2rem(18px); bottom: auto; } } @@ -437,7 +437,7 @@ bottom: 0; height: 100%; background-color: $Table-tree-borderColor; - right: px2rem(9px) + px2rem(-20px) * ($i - 1); + right: px2rem(7px) + px2rem(-20px) * ($i - 1); } } } @@ -449,9 +449,9 @@ content: ''; position: absolute; width: px2rem(1px); - top: px2rem(30px); + top: px2rem(28px); bottom: 0; - right: px2rem(9px); + right: px2rem(7px); height: auto; background-color: $Table-tree-borderColor; } @@ -682,30 +682,33 @@ position: relative; z-index: 1; color: $Table-expandBtn-color; + display: inline-flex; + justify-content: center; + align-items: center; + width: px2rem(14px); + line-height: 1; + height: 16px; > i { display: inline-block; - width: px2rem(16px); text-align: center; cursor: pointer; font-style: normal; + transition: transform ease-in-out 0.2s, top ease-in-out 0.2s; + position: relative; + left: 1px; + transform-origin: 50% 50%; &:before { - display: inline-block; line-height: 1; font-size: $Table-expandBtn-fontSize; font-family: $Table-expandBtn-vendor; content: $Table-expandBtn-icon; - transition: transform ease-in-out 0.2s, top ease-in-out 0.2s; - position: relative; - top: -2px; } } - &.is-active > i::before { + &.is-active > i { transform: rotate(90deg); - transform-origin: 50% 50%; - top: 0; } } diff --git a/scss/components/form/_checks.scss b/scss/components/form/_checks.scss index ac7db880..c204c5d4 100644 --- a/scss/components/form/_checks.scss +++ b/scss/components/form/_checks.scss @@ -313,6 +313,10 @@ } .#{$ns}ListCheckboxes { + &-group:not(:first-child) > &-itemLabel { + border-top: px2rem(1px) solid $ListMenu-divider-color; + } + &-group > &-itemLabel { font-size: $fontSizeSm; padding: $gap-xs $gap-xs; @@ -417,11 +421,16 @@ &-item { position: relative; + &.is-collapsed > .#{$ns}TreeCheckboxes-sublist { display: none; } } + &-item:not(:last-child) > &-sublist:before { + bottom: 0; + } + &-sublist &-item:before { height: 1px; content: ''; @@ -449,6 +458,10 @@ cursor: pointer; user-select: none; + &:hover { + background-color: $Tree-item-onHover-bg; + } + &.is-disabled { pointer-events: none; color: $text--muted-color; @@ -458,4 +471,14 @@ &-itemLabel { flex-grow: 1; } + + &-placeholder { + height: $Form-input-height; + line-height: $Form-input-lineHeight; + font-size: $Form-input-fontSize; + padding: ( + $Form-input-height - $Form-input-lineHeight * $Form-input-fontSize + )/2 $gap-sm; + color: $text--muted-color; + } } diff --git a/scss/components/form/_selections.scss b/scss/components/form/_selections.scss index ef51edc7..62c96277 100644 --- a/scss/components/form/_selections.scss +++ b/scss/components/form/_selections.scss @@ -23,6 +23,7 @@ display: flex; flex-direction: column; justify-content: center; + font-size: $Form-input-fontSize; } &-items { diff --git a/scss/components/form/_transfer.scss b/scss/components/form/_transfer.scss index dde8c442..0bc5d98e 100644 --- a/scss/components/form/_transfer.scss +++ b/scss/components/form/_transfer.scss @@ -11,6 +11,7 @@ &-title { display: flex; + align-items: center; background: $Table-thead-bg; height: px2rem(30px); line-height: $Form-input-lineHeight; @@ -30,16 +31,16 @@ &-select, &-result { + width: 0; min-width: px2rem(200px); - flex-basis: px2rem(200px); flex-grow: 1; border: $Form-input-borderWidth solid $Form-input-borderColor; display: flex; flex-direction: column; } - &-checkboxes, - &-selections { + &-select > &-checkboxes, + &-result > &-selections { flex-grow: 1; height: 0; overflow: auto; @@ -71,6 +72,59 @@ color: $text--muted-color; } } + + &-tabs { + display: flex; + flex-direction: column; + height: 100%; + + > .#{$ns}Tabs-links { + padding: 5px 0 0 5px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + + > .#{$ns}Tabs-link > a:first-child { + font-size: 12px; + padding: 7px 8px; + } + + .#{$ns}TabsTransfer-tabsMid { + flex-grow: 1; + } + + > .#{$ns}SearchBox { + margin: 0 5px 0 10px; + padding: 0 5px; + width: 25px; + + &.is-active { + width: 150px; + margin-right: 10px; + padding-left: 10px; + } + } + } + + > .#{$ns}Tabs-content { + flex-grow: 1; + height: 0; + overflow: auto; + position: relative; + padding: 5px 0; + } + } +} + +.#{$ns}TabsTransfer { + .#{$ns}Transfer-title { + height: 40px; + } + + // .#{$ns}Transfer-result { + // flex-grow: unset; + // } } .#{$ns}TransferControl { diff --git a/scss/themes/cxd.scss b/scss/themes/cxd.scss index 8b271069..789cb2bf 100644 --- a/scss/themes/cxd.scss +++ b/scss/themes/cxd.scss @@ -549,6 +549,7 @@ $ListMenu-item--onHover-bg: #eaf6fe; @import '../components/images'; @import '../components/input-box'; @import '../components/result-box'; +@import '../components/search-box'; @import '../components/list-menu'; @import '../components/form/fieldset'; diff --git a/scss/themes/dark.scss b/scss/themes/dark.scss index c806e053..67049e08 100644 --- a/scss/themes/dark.scss +++ b/scss/themes/dark.scss @@ -204,6 +204,7 @@ pre { @import '../components/images'; @import '../components/input-box'; @import '../components/result-box'; +@import '../components/search-box'; @import '../components/list-menu'; @import '../components/form/fieldset'; diff --git a/scss/themes/default.scss b/scss/themes/default.scss index f9072549..893c99a5 100644 --- a/scss/themes/default.scss +++ b/scss/themes/default.scss @@ -69,6 +69,7 @@ $Form-input-borderColor: #cfdadd; @import '../components/images'; @import '../components/input-box'; @import '../components/result-box'; +@import '../components/search-box'; @import '../components/list-menu'; @import '../components/form/fieldset'; diff --git a/src/components/InputBox.tsx b/src/components/InputBox.tsx index 2de7f4d5..93aaa8bb 100644 --- a/src/components/InputBox.tsx +++ b/src/components/InputBox.tsx @@ -6,9 +6,9 @@ import {Icon} from './icons'; export interface InputBoxProps extends ThemeProps, - Omit, 'prefix'> { + Omit, 'prefix' | 'onChange'> { value?: string; - onValueChange?: (value: string) => void; + onChange?: (value: string) => void; onClear?: (e: React.MouseEvent) => void; clearable?: boolean; disabled?: boolean; @@ -35,17 +35,15 @@ export class InputBox extends React.Component { @autobind clearValue(e: any) { const onClear = this.props.onChange; - const onValueChange = this.props.onValueChange; - onClear && onClear(e); - onValueChange && onValueChange(''); + const onChange = this.props.onChange; + onClear?.(e); + onChange?.(''); } @autobind handleChange(e: React.ChangeEvent) { const onChange = this.props.onChange; - const onValueChange = this.props.onValueChange; - onChange && onChange(e); - onValueChange && onValueChange(e.currentTarget.value); + onChange && onChange(e.currentTarget.value); } @autobind diff --git a/src/components/NestedCheckboxes.tsx b/src/components/NestedCheckboxes.tsx new file mode 100644 index 00000000..b165ba79 --- /dev/null +++ b/src/components/NestedCheckboxes.tsx @@ -0,0 +1,98 @@ +import {Checkboxes} from './Checkboxes'; +import {themeable} from '../theme'; +import React from 'react'; +import uncontrollable from 'uncontrollable'; +import Checkbox from './Checkbox'; +import {Option} from './Select'; + +export class NestedCheckboxes extends Checkboxes { + valueArray: Array