新增 TabsTransfer 渲染器
This commit is contained in:
parent
4b6c04b411
commit
9576641503
|
@ -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'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
font-size: $Form-input-fontSize;
|
||||
}
|
||||
|
||||
&-items {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -6,9 +6,9 @@ import {Icon} from './icons';
|
|||
|
||||
export interface InputBoxProps
|
||||
extends ThemeProps,
|
||||
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'prefix'> {
|
||||
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'prefix' | 'onChange'> {
|
||||
value?: string;
|
||||
onValueChange?: (value: string) => void;
|
||||
onChange?: (value: string) => void;
|
||||
onClear?: (e: React.MouseEvent<any>) => void;
|
||||
clearable?: boolean;
|
||||
disabled?: boolean;
|
||||
|
@ -35,17 +35,15 @@ export class InputBox extends React.Component<InputBoxProps, InputBoxState> {
|
|||
@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<HTMLInputElement>) {
|
||||
const onChange = this.props.onChange;
|
||||
const onValueChange = this.props.onValueChange;
|
||||
onChange && onChange(e);
|
||||
onValueChange && onValueChange(e.currentTarget.value);
|
||||
onChange && onChange(e.currentTarget.value);
|
||||
}
|
||||
|
||||
@autobind
|
||||
|
|
|
@ -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<Option>;
|
||||
|
||||
renderOption(option: Option, index: number) {
|
||||
const {
|
||||
labelClassName,
|
||||
disabled,
|
||||
classnames: cx,
|
||||
itemClassName,
|
||||
itemRender
|
||||
} = this.props;
|
||||
const valueArray = this.valueArray;
|
||||
|
||||
if (Array.isArray(option.children)) {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={cx('ListCheckboxes-group', option.className)}
|
||||
>
|
||||
<div className={cx('ListCheckboxes-itemLabel')}>
|
||||
{itemRender(option)}
|
||||
</div>
|
||||
|
||||
<div className={cx('ListCheckboxes-items', option.className)}>
|
||||
{option.children.map((child, index) =>
|
||||
this.renderOption(child, index)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={cx(
|
||||
'ListCheckboxes-item',
|
||||
itemClassName,
|
||||
option.className,
|
||||
disabled || option.disabled ? 'is-disabled' : ''
|
||||
)}
|
||||
onClick={() => this.toggleOption(option)}
|
||||
>
|
||||
<div className={cx('ListCheckboxes-itemLabel')}>
|
||||
{itemRender(option)}
|
||||
</div>
|
||||
|
||||
<Checkbox
|
||||
checked={!!~valueArray.indexOf(option)}
|
||||
disabled={disabled || option.disabled}
|
||||
labelClassName={labelClassName}
|
||||
description={option.description}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
options,
|
||||
className,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
option2value
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
if (Array.isArray(options) && options.length) {
|
||||
body = options.map((option, key) => this.renderOption(option, key));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('ListCheckboxes', className)}>
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('ListCheckboxes-placeholder')}>{placeholder}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(NestedCheckboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
);
|
|
@ -8,7 +8,9 @@ import {autobind} from '../utils/helper';
|
|||
|
||||
export interface ResultBoxProps
|
||||
extends ThemeProps,
|
||||
Omit<InputBoxProps, 'result' | 'prefix'> {
|
||||
Omit<InputBoxProps, 'result' | 'prefix' | 'onChange'> {
|
||||
onChange?: (value: string) => void;
|
||||
onResultClick?: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
result?: Array<any>;
|
||||
itemRender: (value: any) => JSX.Element;
|
||||
onResultChange?: (value: Array<any>) => void;
|
||||
|
@ -67,6 +69,12 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
onResultChange && onResultChange(newResult);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {onChange} = this.props;
|
||||
onChange?.(e.currentTarget.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
|
@ -84,6 +92,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
inputPlaceholder,
|
||||
onResultChange,
|
||||
onChange,
|
||||
onResultClick,
|
||||
...rest
|
||||
} = this.props;
|
||||
const isFocused = this.state.isFocused;
|
||||
|
@ -97,6 +106,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
disabled ? 'is-disabled' : '',
|
||||
hasError ? 'is-error' : ''
|
||||
)}
|
||||
onClick={onResultClick}
|
||||
>
|
||||
{Array.isArray(result) && result.length ? (
|
||||
result.map((item, index) => (
|
||||
|
@ -119,7 +129,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
|||
<Input
|
||||
{...rest}
|
||||
value={value || ''}
|
||||
onChange={onChange}
|
||||
onChange={this.handleChange}
|
||||
placeholder={
|
||||
Array.isArray(result) && result.length
|
||||
? inputPlaceholder
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import React from 'react';
|
||||
import {ThemeProps, themeable} from '../theme';
|
||||
import {Icon} from './icons';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import {autobind} from '../utils/helper';
|
||||
|
||||
export interface SearchBoxProps extends ThemeProps {
|
||||
name?: string;
|
||||
onChange?: (text: string) => void;
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
active?: boolean;
|
||||
onActiveChange?: (active: boolean) => void;
|
||||
onSearch?: (value: string) => void;
|
||||
onCancel?: () => void;
|
||||
}
|
||||
|
||||
export class SearchBox extends React.Component<SearchBoxProps> {
|
||||
inputRef: React.RefObject<HTMLInputElement> = React.createRef();
|
||||
|
||||
@autobind
|
||||
handleActive() {
|
||||
const {onActiveChange} = this.props;
|
||||
onActiveChange?.(true);
|
||||
this.inputRef.current?.focus();
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleCancel() {
|
||||
const {onActiveChange, onChange, onCancel} = this.props;
|
||||
onActiveChange?.(false);
|
||||
onCancel?.();
|
||||
onChange?.('');
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {onChange, onSearch} = this.props;
|
||||
onChange?.(e.currentTarget.value);
|
||||
onSearch?.(e.currentTarget.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
value,
|
||||
active,
|
||||
name,
|
||||
onChange,
|
||||
placeholder
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('SearchBox', active ? 'is-active' : '')}>
|
||||
<input
|
||||
name={name}
|
||||
onChange={this.handleChange}
|
||||
value={value || ''}
|
||||
placeholder={placeholder || '输入关键字'}
|
||||
ref={this.inputRef}
|
||||
/>
|
||||
|
||||
{active ? (
|
||||
<a className={cx('SearchBox-cancelBtn')} onClick={this.handleCancel}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : (
|
||||
<a className={cx('SearchBox-activeBtn')} onClick={this.handleActive}>
|
||||
<Icon icon="search" className="icon" />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(SearchBox, {
|
||||
active: 'onActiveChange',
|
||||
value: 'onChange'
|
||||
})
|
||||
);
|
|
@ -40,6 +40,7 @@ export interface OptionProps {
|
|||
multi?: boolean;
|
||||
multiple?: boolean;
|
||||
valueField?: string;
|
||||
labelField?: string;
|
||||
simpleValue?: boolean; // 默认onChange 出去是整个 option 节点,如果配置了 simpleValue 就只包含值。
|
||||
options: Options;
|
||||
joinValues?: boolean;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import {Schema} from '../types';
|
||||
import Transition, {ENTERED, ENTERING} from 'react-transition-group/Transition';
|
||||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {themeable, ThemeProps} from '../theme';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
|
||||
const transitionStyles: {
|
||||
|
@ -31,6 +31,54 @@ export interface TabProps extends ThemeProps {
|
|||
toolbar?: React.ReactNode;
|
||||
}
|
||||
|
||||
class TabComponent extends React.PureComponent<TabProps> {
|
||||
contentDom: any;
|
||||
contentRef = (ref: any) => (this.contentDom = ref);
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
mountOnEnter,
|
||||
reload,
|
||||
unmountOnExit,
|
||||
eventKey,
|
||||
activeKey,
|
||||
children,
|
||||
className
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Transition
|
||||
in={activeKey === eventKey}
|
||||
mountOnEnter={mountOnEnter}
|
||||
unmountOnExit={typeof reload === 'boolean' ? reload : unmountOnExit}
|
||||
timeout={500}
|
||||
>
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
this.contentDom.offsetWidth;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
ref={this.contentRef}
|
||||
className={cx(
|
||||
transitionStyles[status],
|
||||
activeKey === eventKey ? 'is-active' : '',
|
||||
'Tabs-pane',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Tab = themeable(TabComponent);
|
||||
|
||||
export interface TabsProps extends ThemeProps {
|
||||
mode: '' | 'line' | 'card' | 'radio' | 'vertical';
|
||||
tabsMode?: '' | 'line' | 'card' | 'radio' | 'vertical';
|
||||
|
@ -50,6 +98,8 @@ export class Tabs extends React.Component<TabsProps> {
|
|||
contentClassName: ''
|
||||
};
|
||||
|
||||
static Tab = Tab;
|
||||
|
||||
handleSelect(key: string | number) {
|
||||
const {onSelect} = this.props;
|
||||
onSelect && onSelect(key);
|
||||
|
@ -110,8 +160,7 @@ export class Tabs extends React.Component<TabsProps> {
|
|||
tabsMode,
|
||||
children,
|
||||
additionBtns,
|
||||
toolbar,
|
||||
activeKey: activeKeyProps
|
||||
toolbar
|
||||
} = this.props;
|
||||
|
||||
if (!Array.isArray(children)) {
|
||||
|
@ -146,56 +195,12 @@ export class Tabs extends React.Component<TabsProps> {
|
|||
}
|
||||
}
|
||||
|
||||
class TabComponent extends React.PureComponent<TabProps> {
|
||||
contentDom: any;
|
||||
contentRef = (ref: any) => (this.contentDom = ref);
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
mountOnEnter,
|
||||
reload,
|
||||
unmountOnExit,
|
||||
eventKey,
|
||||
activeKey,
|
||||
children,
|
||||
className
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Transition
|
||||
in={activeKey === eventKey}
|
||||
mountOnEnter={mountOnEnter}
|
||||
unmountOnExit={typeof reload === 'boolean' ? reload : unmountOnExit}
|
||||
timeout={500}
|
||||
>
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
this.contentDom.offsetWidth;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
ref={this.contentRef}
|
||||
className={cx(
|
||||
transitionStyles[status],
|
||||
activeKey === eventKey ? 'is-active' : '',
|
||||
'Tabs-pane',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Tab = themeable(TabComponent);
|
||||
|
||||
export default themeable(
|
||||
const ThemedTabs = themeable(
|
||||
uncontrollable(Tabs, {
|
||||
activeKey: 'onSelect'
|
||||
})
|
||||
);
|
||||
|
||||
export default ThemedTabs as typeof ThemedTabs & {
|
||||
Tab: typeof Tab;
|
||||
};
|
||||
|
|
|
@ -11,12 +11,14 @@ import {autobind, flattenTree} from '../utils/helper';
|
|||
import InputBox from './InputBox';
|
||||
import {Icon} from './icons';
|
||||
import debounce from 'lodash/debounce';
|
||||
import NestedCheckboxes from './NestedCheckboxes';
|
||||
|
||||
export interface TransferPorps extends ThemeProps, CheckboxesProps {
|
||||
inline?: boolean;
|
||||
statistics?: boolean;
|
||||
|
||||
selectTitle: string;
|
||||
selectMode?: 'table' | 'list' | 'tree';
|
||||
selectMode?: 'table' | 'list' | 'tree' | 'nested';
|
||||
columns?: Array<{
|
||||
name: string;
|
||||
label: string;
|
||||
|
@ -24,7 +26,7 @@ export interface TransferPorps extends ThemeProps, CheckboxesProps {
|
|||
}>;
|
||||
|
||||
// search 相关
|
||||
searchResultMode?: 'table' | 'list' | 'tree';
|
||||
searchResultMode?: 'table' | 'list' | 'tree' | 'nested';
|
||||
searchResultColumns?: Array<{
|
||||
name: string;
|
||||
label: string;
|
||||
|
@ -38,7 +40,13 @@ export interface TransferPorps extends ThemeProps, CheckboxesProps {
|
|||
) => Promise<Options | void>;
|
||||
|
||||
// 自定义选择框相关
|
||||
selectRender?: (props: TransferPorps) => JSX.Element;
|
||||
selectRender?: (
|
||||
props: Omit<TransferPorps, 'onSearch'> & {
|
||||
onSearch: (text: string) => void;
|
||||
onSearchCancel: () => void;
|
||||
searchResult: Options | null;
|
||||
}
|
||||
) => JSX.Element;
|
||||
|
||||
resultTitle: string;
|
||||
sortable?: boolean;
|
||||
|
@ -99,8 +107,7 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
}
|
||||
|
||||
@autobind
|
||||
handleSearch(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const text = e.currentTarget.value;
|
||||
handleSearch(text: string) {
|
||||
this.setState(
|
||||
{
|
||||
inputValue: text
|
||||
|
@ -158,11 +165,17 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
selectTitle,
|
||||
onSearch,
|
||||
disabled,
|
||||
options
|
||||
options,
|
||||
statistics
|
||||
} = this.props;
|
||||
|
||||
if (selectRender) {
|
||||
return selectRender(this.props);
|
||||
return selectRender({
|
||||
...this.props,
|
||||
onSearch: this.handleSearch,
|
||||
onSearchCancel: this.handleSeachCancel,
|
||||
searchResult: this.state.searchResult
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -174,8 +187,12 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
)}
|
||||
>
|
||||
<span>
|
||||
{selectTitle}({this.valueArray.length}/
|
||||
{this.availableOptions.length})
|
||||
{selectTitle}
|
||||
{statistics !== false ? (
|
||||
<span>
|
||||
({this.valueArray.length}/{this.availableOptions.length})
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
{selectMode !== 'table' ? (
|
||||
<a
|
||||
|
@ -249,6 +266,15 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : mode === 'nested' ? (
|
||||
<NestedCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : (
|
||||
<ListCheckboxes
|
||||
placeholder={noResultsText}
|
||||
|
@ -276,7 +302,7 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
<TableCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
columns={columns!}
|
||||
options={options}
|
||||
options={options || []}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
|
@ -284,7 +310,15 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
) : selectMode === 'tree' ? (
|
||||
<TreeCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
options={options || []}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : selectMode === 'nested' ? (
|
||||
<NestedCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options || []}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
|
@ -292,7 +326,7 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
) : (
|
||||
<ListCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
options={options || []}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
|
@ -311,7 +345,8 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
sortable,
|
||||
options,
|
||||
option2value,
|
||||
disabled
|
||||
disabled,
|
||||
statistics
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
|
@ -328,8 +363,12 @@ export class Transfer extends React.Component<TransferPorps, TransferState> {
|
|||
<div className={cx('Transfer-result')}>
|
||||
<div className={cx('Transfer-title')}>
|
||||
<span>
|
||||
{resultTitle}({this.valueArray.length}/
|
||||
{this.availableOptions.length})
|
||||
{resultTitle}
|
||||
{statistics !== false ? (
|
||||
<span>
|
||||
({this.valueArray.length}/{this.availableOptions.length})
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
<a
|
||||
onClick={this.clearAll}
|
||||
|
|
|
@ -200,7 +200,11 @@ export class TreeCheckboxes extends Checkboxes<
|
|||
|
||||
return (
|
||||
<div className={cx('TreeCheckboxes', className)}>
|
||||
{body && body.length ? body : <div>{placeholder}</div>}
|
||||
{body && body.length ? (
|
||||
body
|
||||
) : (
|
||||
<div className={cx('TreeCheckboxes-placeholder')}>{placeholder}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ import Transfer from './Transfer';
|
|||
import ListCheckboxes from './ListCheckboxes';
|
||||
import TableCheckboxes from './TableCheckboxes';
|
||||
import TreeCheckboxes from './TreeCheckboxes';
|
||||
import ResultBox from './ResultBox';
|
||||
import InputBox from './InputBox';
|
||||
|
||||
export {
|
||||
NotFound,
|
||||
|
@ -88,5 +90,7 @@ export {
|
|||
Transfer,
|
||||
ListCheckboxes,
|
||||
TableCheckboxes,
|
||||
TreeCheckboxes
|
||||
TreeCheckboxes,
|
||||
ResultBox,
|
||||
InputBox
|
||||
};
|
||||
|
|
|
@ -94,6 +94,7 @@ import './renderers/Form/IconPicker';
|
|||
import './renderers/Form/Formula';
|
||||
import './renderers/Form/FieldSet';
|
||||
import './renderers/Form/Tabs';
|
||||
import './renderers/Form/TabsTransfer';
|
||||
import './renderers/Form/Group';
|
||||
import './renderers/Form/InputGroup';
|
||||
import './renderers/Grid';
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
import {OptionsControlProps, OptionsControl} from './Options';
|
||||
import React from 'react';
|
||||
import Transfer from '../../components/Transfer';
|
||||
import {Api} from '../../types';
|
||||
import Spinner from '../../components/Spinner';
|
||||
import {TransferRenderer} from './Transfer';
|
||||
import {autobind} from '../../utils/helper';
|
||||
import Tabs, {Tab} from '../../components/Tabs';
|
||||
import {Icon} from '../../components/icons';
|
||||
import TableCheckboxes from '../../components/TableCheckboxes';
|
||||
import TreeCheckboxes from '../../components/TreeCheckboxes';
|
||||
import ListCheckboxes from '../../components/ListCheckboxes';
|
||||
import SearchBox from '../../components/SearchBox';
|
||||
import {Options} from '../../components/Select';
|
||||
import NestedCheckboxes from '../../components/NestedCheckboxes';
|
||||
|
||||
export interface TabsTransferProps extends OptionsControlProps {
|
||||
sortable?: boolean;
|
||||
searchable?: boolean;
|
||||
searchApi?: Api;
|
||||
searchResultMode?: 'table' | 'list' | 'tree' | 'nested';
|
||||
}
|
||||
|
||||
@OptionsControl({
|
||||
type: 'tabs-transfer'
|
||||
})
|
||||
export class TabsTransferRenderer extends TransferRenderer<TabsTransferProps> {
|
||||
renderSearchResult(searchResult: Options | null) {
|
||||
const {
|
||||
searchResultMode,
|
||||
selectMode,
|
||||
noResultsText,
|
||||
searchResultColumns,
|
||||
classnames: cx,
|
||||
value,
|
||||
onChange,
|
||||
option2value
|
||||
} = this.props;
|
||||
const options = searchResult || [];
|
||||
const mode = searchResultMode || selectMode;
|
||||
|
||||
return mode === 'table' ? (
|
||||
<TableCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
columns={searchResultColumns!}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : mode === 'tree' ? (
|
||||
<TreeCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : mode === 'nested' ? (
|
||||
<NestedCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : (
|
||||
<ListCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@autobind
|
||||
renderSelect({onSearch, onSearchCancel, searchResult}: any) {
|
||||
const {
|
||||
options,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
labelField,
|
||||
selectedOptions,
|
||||
searchable
|
||||
} = this.props;
|
||||
|
||||
if (!Array.isArray(options) || !options.length) {
|
||||
return <div>{placeholder || '暂无可选项'}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
mode="card"
|
||||
className={cx('Transfer-tabs')}
|
||||
activeKey={searchResult !== null ? 0 : undefined}
|
||||
toolbar={
|
||||
searchable ? (
|
||||
<>
|
||||
<span className={cx('TabsTransfer-tabsMid')}></span>
|
||||
<SearchBox onSearch={onSearch} onCancel={onSearchCancel} />
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
{searchResult !== null
|
||||
? [
|
||||
<Tab title="搜索结果" key={0} eventKey={0}>
|
||||
{this.renderSearchResult(searchResult)}
|
||||
</Tab>
|
||||
]
|
||||
: options.map((option, index) => (
|
||||
<Tab
|
||||
eventKey={index}
|
||||
key={index}
|
||||
title={option[labelField || 'label'] || option.title}
|
||||
>
|
||||
{option.selectMode === 'table' ? (
|
||||
<TableCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
columns={option.columns as any}
|
||||
options={option.children || []}
|
||||
value={selectedOptions}
|
||||
onChange={this.handleChange}
|
||||
option2value={this.option2value}
|
||||
/>
|
||||
) : option.selectMode === 'tree' ? (
|
||||
<TreeCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={option.children || []}
|
||||
value={selectedOptions}
|
||||
onChange={this.handleChange}
|
||||
option2value={this.option2value}
|
||||
/>
|
||||
) : option.selectMode === 'nested' ? (
|
||||
<NestedCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={option.children || []}
|
||||
value={selectedOptions}
|
||||
onChange={this.handleChange}
|
||||
option2value={this.option2value}
|
||||
/>
|
||||
) : (
|
||||
<ListCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={option.children || []}
|
||||
value={selectedOptions}
|
||||
onChange={this.handleChange}
|
||||
option2value={this.option2value}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
classnames: cx,
|
||||
options,
|
||||
selectedOptions,
|
||||
sortable,
|
||||
selectMode,
|
||||
columns,
|
||||
loading,
|
||||
searchable,
|
||||
searchResultMode
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('TabsTransferControl', className)}>
|
||||
<Transfer
|
||||
statistics={false}
|
||||
className="TabsTransfer"
|
||||
selectRender={this.renderSelect}
|
||||
value={selectedOptions}
|
||||
options={options}
|
||||
onChange={this.handleChange}
|
||||
option2value={this.option2value}
|
||||
sortable={sortable}
|
||||
selectMode={selectMode}
|
||||
searchResultMode={searchResultMode}
|
||||
columns={columns}
|
||||
onSearch={searchable ? this.handleSearch : undefined}
|
||||
/>
|
||||
|
||||
<Spinner overlay key="info" show={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -146,9 +146,9 @@ export default class TagControl extends React.PureComponent<
|
|||
}
|
||||
|
||||
@autobind
|
||||
handleInputChange(e: React.ChangeEvent<any>) {
|
||||
handleInputChange(text: string) {
|
||||
this.setState({
|
||||
inputValue: e.currentTarget.value
|
||||
inputValue: text
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -301,13 +301,13 @@ export default class TagControl extends React.PureComponent<
|
|||
name,
|
||||
ref: this.input,
|
||||
placeholder: placeholder || '暂无标签',
|
||||
onChange: this.handleInputChange,
|
||||
value: this.state.inputValue,
|
||||
onKeyDown: this.handleKeyDown,
|
||||
onFocus: this.handleFocus,
|
||||
onBlur: this.handleBlur,
|
||||
disabled
|
||||
})}
|
||||
onChange={this.handleInputChange}
|
||||
className={cx('TagControl-input')}
|
||||
result={selectedOptions}
|
||||
onResultChange={this.handleChange}
|
||||
|
|
|
@ -6,7 +6,8 @@ import {
|
|||
autobind,
|
||||
filterTree,
|
||||
string2regExp,
|
||||
createObject
|
||||
createObject,
|
||||
findTree
|
||||
} from '../../utils/helper';
|
||||
import {Api} from '../../types';
|
||||
import Spinner from '../../components/Spinner';
|
||||
|
@ -22,10 +23,9 @@ export interface TransferProps extends OptionsControlProps {
|
|||
searchApi?: Api;
|
||||
}
|
||||
|
||||
@OptionsControl({
|
||||
type: 'transfer'
|
||||
})
|
||||
export class TransferRenderer extends React.Component<TransferProps> {
|
||||
export class TransferRenderer<
|
||||
T extends OptionsControlProps = TransferProps
|
||||
> extends React.Component<T> {
|
||||
@autobind
|
||||
handleChange(value: Array<Option>) {
|
||||
const {
|
||||
|
@ -43,11 +43,11 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
|||
if (Array.isArray(value)) {
|
||||
if (joinValues || extractValue) {
|
||||
newValue = value.map(item => {
|
||||
const resolved = find(
|
||||
const resolved = findTree(
|
||||
options,
|
||||
optionValueCompare(
|
||||
item[valueField || 'value'],
|
||||
valueField || 'value'
|
||||
item[(valueField as string) || 'value'],
|
||||
(valueField as string) || 'value'
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -55,7 +55,7 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
|||
newOptions.push(item);
|
||||
}
|
||||
|
||||
return item[valueField || 'value'];
|
||||
return item[(valueField as string) || 'value'];
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -124,8 +124,8 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
|||
(option: Option) => {
|
||||
return !!(
|
||||
(Array.isArray(option.children) && option.children.length) ||
|
||||
regexp.test(option[labelField || 'label']) ||
|
||||
regexp.test(option[valueField || 'value'])
|
||||
regexp.test(option[(labelField as string) || 'label']) ||
|
||||
regexp.test(option[(valueField as string) || 'value'])
|
||||
);
|
||||
},
|
||||
0,
|
||||
|
@ -169,3 +169,7 @@ export class TransferRenderer extends React.Component<TransferProps> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default OptionsControl({
|
||||
type: 'transfer'
|
||||
})(TransferRenderer);
|
||||
|
|
|
@ -127,8 +127,9 @@ export function themeable<
|
|||
};
|
||||
|
||||
class EnhancedComponent extends React.Component<Props> {
|
||||
static displayName = `Themeable(${ComposedComponent.displayName ||
|
||||
ComposedComponent.name})`;
|
||||
static displayName = `Themeable(${
|
||||
ComposedComponent.displayName || ComposedComponent.name
|
||||
})`;
|
||||
static contextType = ThemeContext;
|
||||
static ComposedComponent = ComposedComponent;
|
||||
|
||||
|
@ -147,7 +148,7 @@ export function themeable<
|
|||
<ThemeContext.Provider value={theme}>
|
||||
<ComposedComponent
|
||||
{
|
||||
...this.props as any /* todo, 解决这个类型问题 */
|
||||
...(this.props as any) /* todo, 解决这个类型问题 */
|
||||
}
|
||||
{...injectedProps}
|
||||
/>
|
||||
|
@ -156,10 +157,9 @@ export function themeable<
|
|||
}
|
||||
}
|
||||
|
||||
return hoistNonReactStatic(
|
||||
EnhancedComponent,
|
||||
ComposedComponent
|
||||
) as React.ComponentClass<Props> & {
|
||||
const result = hoistNonReactStatic(EnhancedComponent, ComposedComponent);
|
||||
|
||||
return result as typeof result & {
|
||||
ComposedComponent: T;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue