forked from p96170835/amis
添加 InputBox Transfer 组件
This commit is contained in:
parent
98077b9637
commit
4b2985404d
|
@ -355,6 +355,18 @@
|
|||
}
|
||||
|
||||
.#{$ns}TableCheckboxes {
|
||||
.#{$ns}Table-table > thead > tr > th,
|
||||
.#{$ns}Table-table > tbody > tr > td {
|
||||
font-size: $fontSizeSm;
|
||||
padding-top: px2rem(5px);
|
||||
padding-bottom: px2rem(6px);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.#{$ns}Table-table > thead > tr > th {
|
||||
padding-top: px2rem(6px);
|
||||
}
|
||||
|
||||
.#{$ns}Table-table > thead > tr > th:first-child,
|
||||
.#{$ns}Table-table > tbody > tr > td:first-child {
|
||||
padding-left: px2rem(10px);
|
||||
|
|
|
@ -17,6 +17,35 @@
|
|||
}
|
||||
}
|
||||
|
||||
@mixin input-input {
|
||||
display: flex;
|
||||
background-color: $Form-input-bg;
|
||||
border: $Form-input-borderWidth solid $Form-input-borderColor;
|
||||
border-radius: $Form-input-borderRadius;
|
||||
// height: $Form-input-height;
|
||||
line-height: $Form-input-lineHeight;
|
||||
padding: $Form-input-paddingY $Form-input-paddingX;
|
||||
font-size: $Form-input-fontSize;
|
||||
|
||||
input {
|
||||
outline: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: $Form-input-color;
|
||||
width: 100%;
|
||||
height: $Form-input-lineHeight * $Form-input-fontSize;
|
||||
|
||||
&::placeholder {
|
||||
color: $Form-input-placeholderColor;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
> input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin input-text {
|
||||
position: relative;
|
||||
min-width: $Form-control-widthBase;
|
||||
|
@ -26,32 +55,7 @@
|
|||
}
|
||||
|
||||
&-input {
|
||||
display: flex;
|
||||
background-color: $Form-input-bg;
|
||||
border: $Form-input-borderWidth solid $Form-input-borderColor;
|
||||
border-radius: $Form-input-borderRadius;
|
||||
// height: $Form-input-height;
|
||||
line-height: $Form-input-lineHeight;
|
||||
padding: $Form-input-paddingY $Form-input-paddingX;
|
||||
font-size: $Form-input-fontSize;
|
||||
|
||||
input {
|
||||
outline: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: $Form-input-color;
|
||||
width: 100%;
|
||||
height: $Form-input-lineHeight * $Form-input-fontSize;
|
||||
|
||||
&::placeholder {
|
||||
color: $Form-input-placeholderColor;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
> input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@include input-input();
|
||||
}
|
||||
|
||||
&.is-error > &-input {
|
||||
|
@ -325,3 +329,45 @@
|
|||
padding: 0 $gap-xs;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}InputBox {
|
||||
@include input-input();
|
||||
|
||||
&.is-error {
|
||||
border-color: $Form-input-onError-borderColor;
|
||||
background-color: $Form-input-onError-bg;
|
||||
}
|
||||
|
||||
&.is-focused {
|
||||
border-color: $Form-input-onFocused-borderColor;
|
||||
box-shadow: $Form-input-boxShadow;
|
||||
|
||||
@if $Form-input-onFocused-bg !=$Form-input-bg {
|
||||
background-color: $Form-input-onFocused-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-error.is-focused {
|
||||
border-color: $Form-input-onError-borderColor;
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
color: $text--muted-color;
|
||||
background: $Form-input-onDisabled-bg;
|
||||
border-color: $Form-input-onDisabled-borderColor;
|
||||
}
|
||||
|
||||
&-clear {
|
||||
@include input-clear();
|
||||
}
|
||||
|
||||
> svg {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
color: $icon-color;
|
||||
}
|
||||
|
||||
> a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
.#{$ns}Transfer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
min-height: px2rem(300px);
|
||||
|
||||
&--inline {
|
||||
display: inline-flex;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
background: $Table-thead-bg;
|
||||
height: px2rem(30px);
|
||||
line-height: $Form-input-lineHeight;
|
||||
font-size: $Form-input-fontSize;
|
||||
padding: (px2rem(30px) - $Form-input-lineHeight * $Form-input-fontSize)/2
|
||||
$gap-sm;
|
||||
flex-direction: row;
|
||||
|
||||
&--light {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
> span {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-select,
|
||||
&-result {
|
||||
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 {
|
||||
flex-grow: 1;
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-search {
|
||||
padding: $gap-sm;
|
||||
}
|
||||
|
||||
&-arrow {
|
||||
width: px2rem(10px);
|
||||
}
|
||||
|
||||
&-checkAll,
|
||||
&-clearAll {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
|
@ -572,6 +572,7 @@ $Combo--horizontal-dragger-top: px2rem(5px);
|
|||
@import '../components/form/qr-code';
|
||||
@import '../components/form/tag';
|
||||
@import '../components/form/rating';
|
||||
@import '../components/form/transfer';
|
||||
@import '../components/form/transfer-select';
|
||||
@import '../components/form/nested-select';
|
||||
@import '../components/form/icon-picker';
|
||||
|
|
|
@ -235,6 +235,7 @@ pre {
|
|||
@import '../components/form/qr-code';
|
||||
@import '../components/form/tag';
|
||||
@import '../components/form/rating';
|
||||
@import '../components/form/transfer';
|
||||
@import '../components/form/transfer-select';
|
||||
@import '../components/form/nested-select';
|
||||
@import '../components/form/icon-picker';
|
||||
|
|
|
@ -100,6 +100,7 @@ $Form-input-borderColor: #cfdadd;
|
|||
@import '../components/form/qr-code';
|
||||
@import '../components/form/tag';
|
||||
@import '../components/form/rating';
|
||||
@import '../components/form/transfer';
|
||||
@import '../components/form/transfer-select';
|
||||
@import '../components/form/nested-select';
|
||||
@import '../components/form/icon-picker';
|
||||
|
|
|
@ -11,7 +11,7 @@ import chunk from 'lodash/chunk';
|
|||
import {ClassNamesFn, themeable, ThemeProps} from '../theme';
|
||||
import {Option, value2array, Options} from './Select';
|
||||
import find from 'lodash/find';
|
||||
import { autobind, findTree } from '../utils/helper';
|
||||
import {autobind, findTree} from '../utils/helper';
|
||||
// import isPlainObject from 'lodash/isPlainObject';
|
||||
|
||||
export interface CheckboxesProps extends ThemeProps {
|
||||
|
@ -29,7 +29,10 @@ export interface CheckboxesProps extends ThemeProps {
|
|||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export class Checkboxes<T extends CheckboxesProps = CheckboxesProps, S = any> extends React.Component<T, S> {
|
||||
export class Checkboxes<
|
||||
T extends CheckboxesProps = CheckboxesProps,
|
||||
S = any
|
||||
> extends React.Component<T, S> {
|
||||
static defaultProps = {
|
||||
placeholder: '暂无选项',
|
||||
itemRender: (option: Option) => <span>{option.label}</span>
|
||||
|
@ -48,15 +51,15 @@ export class Checkboxes<T extends CheckboxesProps = CheckboxesProps, S = any> ex
|
|||
value = [value];
|
||||
}
|
||||
|
||||
return value
|
||||
.map((value: any) => {
|
||||
const option = findTree(options, option => option2value(option) === value);
|
||||
return option;
|
||||
})
|
||||
.filter((item: any) => item);
|
||||
return value.map((value: any) => {
|
||||
const option = findTree(
|
||||
options,
|
||||
option => option2value(option) === value
|
||||
);
|
||||
return option || value;
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
toggleOption(option: Option) {
|
||||
const {value, onChange, option2value, options} = this.props;
|
||||
|
||||
|
@ -77,23 +80,23 @@ export class Checkboxes<T extends CheckboxesProps = CheckboxesProps, S = any> ex
|
|||
? valueArray.map(item => option2value(item))
|
||||
: valueArray;
|
||||
|
||||
onChange?.(newValue);
|
||||
onChange && onChange(newValue);
|
||||
}
|
||||
|
||||
@autobind
|
||||
toggleAll() {
|
||||
const {value, onChange, option2value, options} = this.props;
|
||||
let valueArray:Array<Option> = [];
|
||||
let valueArray: Array<Option> = [];
|
||||
|
||||
if (!Array.isArray(value) || !value.length) {
|
||||
valueArray = options.filter(option => !option.disabled);
|
||||
}
|
||||
|
||||
|
||||
let newValue: string | Array<Option> = option2value
|
||||
? valueArray.map(item => option2value(item))
|
||||
: valueArray;
|
||||
|
||||
onChange?.(newValue);
|
||||
onChange && onChange(newValue);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -131,10 +134,14 @@ export class Checkboxes<T extends CheckboxesProps = CheckboxesProps, S = any> ex
|
|||
}
|
||||
|
||||
return (
|
||||
<div className={cx('Checkboxes', className, inline ? 'Checkboxes--inline' : '')}>
|
||||
{body && body.length ? body : (
|
||||
<div>{placeholder}</div>
|
||||
<div
|
||||
className={cx(
|
||||
'Checkboxes',
|
||||
className,
|
||||
inline ? 'Checkboxes--inline' : ''
|
||||
)}
|
||||
>
|
||||
{body && body.length ? body : <div>{placeholder}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import React from 'react';
|
||||
import {ThemeProps, themeable} from '../theme';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import Input from './Input';
|
||||
import {autobind} from '../utils/helper';
|
||||
import {Icon} from './icons';
|
||||
|
||||
export interface InputBoxProps
|
||||
extends ThemeProps,
|
||||
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
clearable?: boolean;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
children?: JSX.Element;
|
||||
}
|
||||
|
||||
export interface InputBoxState {
|
||||
isFocused: boolean;
|
||||
}
|
||||
|
||||
export class InputBox extends React.Component<InputBoxProps, InputBoxState> {
|
||||
static defaultProps = {
|
||||
clearable: true,
|
||||
placeholder: ''
|
||||
};
|
||||
|
||||
state = {
|
||||
isFocused: false
|
||||
};
|
||||
|
||||
@autobind
|
||||
clearValue() {
|
||||
const onChange = this.props.onChange;
|
||||
onChange && onChange('');
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const onChange = this.props.onChange;
|
||||
onChange && onChange(e.currentTarget.value);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleFocus(e: any) {
|
||||
const onFocus = this.props.onFocus;
|
||||
onFocus && onFocus(e);
|
||||
this.setState({
|
||||
isFocused: true
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleBlur(e: any) {
|
||||
const onBlur = this.props.onBlur;
|
||||
onBlur && onBlur(e);
|
||||
this.setState({
|
||||
isFocused: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
classnames: cx,
|
||||
classPrefix,
|
||||
clearable,
|
||||
disabled,
|
||||
value,
|
||||
placeholder,
|
||||
children,
|
||||
...rest
|
||||
} = this.props;
|
||||
const isFocused = this.state.isFocused;
|
||||
|
||||
return (
|
||||
<div className={cx('InputBox', className, isFocused ? 'is-focused' : '')}>
|
||||
<Input
|
||||
{...rest}
|
||||
value={value || ''}
|
||||
onChange={this.handleChange}
|
||||
placeholder={placeholder}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
{clearable && !disabled && value ? (
|
||||
<a onClick={this.clearValue} className={cx('InputBox-clear')}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(InputBox, {
|
||||
value: 'onChange'
|
||||
})
|
||||
);
|
|
@ -0,0 +1,339 @@
|
|||
import React from 'react';
|
||||
import {ThemeProps, themeable} from '../theme';
|
||||
import {CheckboxesProps, Checkboxes} from './Checkboxes';
|
||||
import {Options} from './Select';
|
||||
import uncontrollable from 'uncontrollable';
|
||||
import Selections from './Selections';
|
||||
import TableCheckboxes from './TableCheckboxes';
|
||||
import ListCheckboxes from './ListCheckboxes';
|
||||
import TreeCheckboxes from './TreeCheckboxes';
|
||||
import {autobind, flattenTree} from '../utils/helper';
|
||||
import InputBox from './InputBox';
|
||||
import {Icon} from './icons';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
export interface TransferPorps extends ThemeProps, CheckboxesProps {
|
||||
inline?: boolean;
|
||||
|
||||
selectTitle: string;
|
||||
selectMode?: 'table' | 'list' | 'tree';
|
||||
columns?: Array<{
|
||||
name: string;
|
||||
label: string;
|
||||
[propName: string]: any;
|
||||
}>;
|
||||
|
||||
// search 相关
|
||||
searchResultMode?: 'table' | 'list' | 'tree';
|
||||
searchResultColumns?: Array<{
|
||||
name: string;
|
||||
label: string;
|
||||
[propName: string]: any;
|
||||
}>;
|
||||
searchPlaceholder?: string;
|
||||
noResultsText?: string;
|
||||
onSearch?: (
|
||||
term: string,
|
||||
setCancel: (cancel: () => void) => void
|
||||
) => Promise<Options>;
|
||||
|
||||
// 自定义选择框相关
|
||||
selectRender?: (props: TransferPorps) => JSX.Element;
|
||||
|
||||
resultTitle: string;
|
||||
sortable?: boolean;
|
||||
}
|
||||
|
||||
export interface TransferState {
|
||||
inputValue: string;
|
||||
searchResult: Options | null;
|
||||
}
|
||||
|
||||
export class Transfer extends React.Component<TransferPorps, TransferState> {
|
||||
static defaultProps = {
|
||||
selectTitle: '请选择',
|
||||
resultTitle: '当前选择'
|
||||
};
|
||||
|
||||
state = {
|
||||
inputValue: '',
|
||||
searchResult: null
|
||||
};
|
||||
|
||||
valueArray: Options;
|
||||
availableOptions: Options;
|
||||
unmounted = false;
|
||||
cancelSearch?: () => void;
|
||||
|
||||
componentWillUnmount() {
|
||||
this.lazySearch.cancel();
|
||||
this.unmounted = true;
|
||||
}
|
||||
|
||||
@autobind
|
||||
toggleAll() {
|
||||
const {options, option2value, onChange, value} = this.props;
|
||||
let valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
const availableOptions = flattenTree(options).filter(
|
||||
option => !option.disabled && option.value !== void 0
|
||||
);
|
||||
|
||||
if (valueArray.length < availableOptions.length) {
|
||||
valueArray = availableOptions;
|
||||
} else {
|
||||
valueArray = [];
|
||||
}
|
||||
|
||||
let newValue: string | Options = option2value
|
||||
? valueArray.map(item => option2value(item))
|
||||
: valueArray;
|
||||
|
||||
onChange && onChange(newValue);
|
||||
}
|
||||
|
||||
@autobind
|
||||
clearAll() {
|
||||
const {onChange} = this.props;
|
||||
onChange && onChange([]);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSearch(text: string) {
|
||||
this.setState(
|
||||
{
|
||||
inputValue: text
|
||||
},
|
||||
() => {
|
||||
// 如果有取消搜索,先取消掉。
|
||||
this.cancelSearch && this.cancelSearch();
|
||||
this.lazySearch(text);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSeachCancel() {
|
||||
this.setState({
|
||||
inputValue: '',
|
||||
searchResult: null
|
||||
});
|
||||
}
|
||||
|
||||
lazySearch = debounce(
|
||||
async (text: string) => {
|
||||
const onSearch = this.props.onSearch!;
|
||||
let result = await onSearch(
|
||||
text,
|
||||
(cancel: () => void) => (this.cancelSearch = cancel)
|
||||
);
|
||||
|
||||
if (this.unmounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(result)) {
|
||||
throw new Error('onSearch 需要返回数组');
|
||||
}
|
||||
|
||||
this.setState({
|
||||
searchResult: result
|
||||
});
|
||||
},
|
||||
250,
|
||||
{
|
||||
trailing: true,
|
||||
leading: false
|
||||
}
|
||||
);
|
||||
|
||||
renderSelect() {
|
||||
const {
|
||||
selectRender,
|
||||
selectMode,
|
||||
classnames: cx,
|
||||
selectTitle,
|
||||
onSearch
|
||||
} = this.props;
|
||||
|
||||
if (selectRender) {
|
||||
return selectRender(this.props);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cx(
|
||||
'Transfer-title',
|
||||
selectMode === 'table' ? 'Transfer-title--light' : ''
|
||||
)}
|
||||
>
|
||||
<span>
|
||||
{selectTitle}({this.valueArray.length}/
|
||||
{this.availableOptions.length})
|
||||
</span>
|
||||
{selectMode !== 'table' ? (
|
||||
<a onClick={this.toggleAll} className={cx('Transfer-checkAll')}>
|
||||
全选
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{onSearch ? (
|
||||
<div className={cx('Transfer-search')}>
|
||||
<InputBox
|
||||
value={this.state.inputValue}
|
||||
onChange={this.handleSearch}
|
||||
placeholder="请输入关键字"
|
||||
clearable={false}
|
||||
>
|
||||
{this.state.searchResult !== null ? (
|
||||
<a onClick={this.handleSeachCancel}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
) : (
|
||||
<Icon icon="search" className="icon" />
|
||||
)}
|
||||
</InputBox>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{this.state.searchResult !== null
|
||||
? this.renderSearchResult()
|
||||
: this.renderOptions()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
renderSearchResult() {
|
||||
const {
|
||||
searchResultMode,
|
||||
noResultsText,
|
||||
searchResultColumns,
|
||||
classnames: cx,
|
||||
value,
|
||||
onChange,
|
||||
option2value
|
||||
} = this.props;
|
||||
const options = this.state.searchResult || [];
|
||||
|
||||
return searchResultMode === 'table' ? (
|
||||
<TableCheckboxes
|
||||
placeholder={noResultsText}
|
||||
className={cx('Transfer-checkboxes')}
|
||||
columns={searchResultColumns!}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : searchResultMode === 'tree' ? (
|
||||
<TreeCheckboxes
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderOptions() {
|
||||
const {
|
||||
selectMode,
|
||||
columns,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
option2value,
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
|
||||
return selectMode === 'table' ? (
|
||||
<TableCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
columns={columns!}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : selectMode === 'tree' ? (
|
||||
<TreeCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
) : (
|
||||
<ListCheckboxes
|
||||
className={cx('Transfer-checkboxes')}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
option2value={option2value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
inline,
|
||||
classnames: cx,
|
||||
className,
|
||||
value,
|
||||
onChange,
|
||||
resultTitle,
|
||||
sortable,
|
||||
options,
|
||||
option2value
|
||||
} = this.props;
|
||||
|
||||
this.valueArray = Checkboxes.value2array(value, options, option2value);
|
||||
this.availableOptions = flattenTree(options).filter(
|
||||
option => !option.disabled && option.value !== void 0
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx('Transfer', className, inline ? 'Transfer--inline' : '')}
|
||||
>
|
||||
<div className={cx('Transfer-select')}>{this.renderSelect()}</div>
|
||||
<div className={cx('Transfer-arrow')}></div>
|
||||
<div className={cx('Transfer-result')}>
|
||||
<div className={cx('Transfer-title')}>
|
||||
<span>
|
||||
{resultTitle}({this.valueArray.length}/
|
||||
{this.availableOptions.length})
|
||||
</span>
|
||||
<a onClick={this.clearAll} className={cx('Transfer-clearAll')}>
|
||||
清空
|
||||
</a>
|
||||
</div>
|
||||
<Selections
|
||||
className={cx('Transfer-selections')}
|
||||
sortable={sortable}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Transfer, {
|
||||
value: 'onChange'
|
||||
})
|
||||
);
|
|
@ -4,6 +4,7 @@ import React from 'react';
|
|||
import uncontrollable from 'uncontrollable';
|
||||
import Checkbox from './Checkbox';
|
||||
import {Option} from './Select';
|
||||
import {autobind} from '../utils/helper';
|
||||
|
||||
export interface TreeCheckboxesProps extends CheckboxesProps {}
|
||||
|
||||
|
|
|
@ -743,10 +743,12 @@ export const detectProps = [
|
|||
|
||||
export function asFormItem(config: Omit<FormItemConfig, 'component'>) {
|
||||
return (Control: FormControlComponent) => {
|
||||
const isSFC = !(Control.prototype instanceof React.Component);
|
||||
|
||||
// 兼容老的 FormItem 用法。
|
||||
if (config.validate && !Control.prototype.validate) {
|
||||
const fn = config.validate;
|
||||
Control.prototype.validate = function() {
|
||||
Control.prototype.validate = function () {
|
||||
// console.warn('推荐直接在类中定义,而不是 FormItem HOC 的参数中传入。');
|
||||
const host = {
|
||||
input: this
|
||||
|
@ -855,7 +857,7 @@ export function asFormItem(config: Omit<FormItemConfig, 'component'>) {
|
|||
onBlur={this.handleBlur}
|
||||
type={type}
|
||||
classnames={cx}
|
||||
ref={this.refFn}
|
||||
ref={isSFC ? undefined : this.refFn}
|
||||
formItem={model}
|
||||
className={cx(
|
||||
`Form-control`,
|
||||
|
@ -901,7 +903,7 @@ export function registerFormItem(config: FormItemConfig): RendererConfig {
|
|||
}
|
||||
|
||||
export function FormItem(config: FormItemBasicConfig) {
|
||||
return function(component: FormControlComponent): any {
|
||||
return function (component: FormControlComponent): any {
|
||||
const renderer = registerFormItem({
|
||||
...config,
|
||||
component
|
||||
|
|
Loading…
Reference in New Issue