优化 checkboxes

This commit is contained in:
2betop 2020-05-12 14:17:43 +08:00
parent 25075b2298
commit 9100907de2
5 changed files with 84 additions and 74 deletions

View File

@ -2,6 +2,7 @@
margin: 0 $gap-sm 0 0; margin: 0 $gap-sm 0 0;
font-weight: $fontWeightNormal; font-weight: $fontWeightNormal;
user-select: none; user-select: none;
pointer-events: none;
input { input {
opacity: 0; opacity: 0;
@ -20,8 +21,10 @@
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
pointer-events: all;
+ span { + span {
pointer-events: all;
margin-left: $Checkbox-gap; margin-left: $Checkbox-gap;
cursor: pointer; cursor: pointer;
@ -230,6 +233,7 @@
color: $text--muted-color; color: $text--muted-color;
margin-left: $Checkbox-gap; margin-left: $Checkbox-gap;
margin-top: $gap-xs; margin-top: $gap-xs;
pointer-events: all;
} }
} }
@ -274,6 +278,22 @@
} }
.#{$ns}Checkboxes { .#{$ns}Checkboxes {
> .#{$ns}Checkbox {
display: block;
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
($Form-input-height - $Form-input-lineHeight * $Form-input-fontSize)/2
($gap-sm + $Checkbox-size);
}
&--inline > .#{$ns}Checkbox {
display: inline-block;
}
&-addBtn { &-addBtn {
display: block; display: block;
cursor: pointer; cursor: pointer;

View File

@ -27,8 +27,6 @@
&-items { &-items {
flex-grow: 1; flex-grow: 1;
height: 0;
overflow: auto;
} }
&-item { &-item {

View File

@ -8,117 +8,111 @@ import React from 'react';
import uncontrollable from 'uncontrollable'; import uncontrollable from 'uncontrollable';
import Checkbox from './Checkbox'; import Checkbox from './Checkbox';
import chunk from 'lodash/chunk'; import chunk from 'lodash/chunk';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable, ThemeProps} from '../theme';
import {Option, OptionProps, value2array} from './Select'; import {Option, value2array, Options} from './Select';
import find from 'lodash/find';
// import isPlainObject from 'lodash/isPlainObject'; // import isPlainObject from 'lodash/isPlainObject';
interface CheckboxesProps extends OptionProps { interface CheckboxesProps extends ThemeProps {
id?: string; options: Options;
key?: string;
className?: string; className?: string;
type: string;
placeholder?: string; placeholder?: string;
disabled?: boolean; value?: Array<any>;
value?: string; onChange?: (value: Array<Option>) => void;
onChange?: Function;
inline?: boolean; inline?: boolean;
checked?: boolean;
labelClassName?: string; labelClassName?: string;
classPrefix: string; option2value?: (option: Option) => any;
classnames: ClassNamesFn; itemClassName?: string;
itemRender: (option: Option) => JSX.Element;
disabled?: boolean;
} }
export class Checkboxes extends React.PureComponent<CheckboxesProps, any> { export class Checkboxes extends React.Component<CheckboxesProps, any> {
static defaultProps = { static defaultProps = {
joinValues: true, placeholder: '暂无选项',
extractValue: false, itemRender: (option: Option) => <span>{option.label}</span>
inline: false,
delimiter: ',',
columnsCount: 1 // 一行显示一个
}; };
toggleOption(option: Option) { static value2array(
const { value: any,
value, options: Options,
onChange, option2value: (option: Option) => any = (option: Option) => option
delimiter, ): Options {
valueField, if (value === void 0) {
options, return [];
simpleValue
} = this.props;
let valueArray = value2array(value, {
multiple: true,
valueField,
delimiter,
options
});
let idx = valueArray.indexOf(option);
if (!~idx) {
option =
value2array(option[valueField || 'value'], {
multiple: true,
valueField,
delimiter,
options
})[0] || option;
idx = valueArray.indexOf(option);
} }
if (!Array.isArray(value)) {
value = [value];
}
return value
.map((value: any) => {
const option = find(options, option => option2value(option) === value);
return option;
})
.filter((item: any) => item);
}
toggleOption(option: Option) {
const {value, onChange, option2value, options} = this.props;
let valueArray = Checkboxes.value2array(value, options, option2value);
let idx = valueArray.indexOf(option);
if (~idx) { if (~idx) {
valueArray.splice(idx, 1); valueArray.splice(idx, 1);
} else { } else {
valueArray.push(option); valueArray.push(option);
} }
let newValue: string | Array<Option> = simpleValue let newValue: string | Array<Option> = option2value
? valueArray.map(item => item[valueField || 'value']) ? valueArray.map(item => option2value(item))
: valueArray; : valueArray;
onChange && onChange(newValue); onChange?.(newValue);
} }
render() { render() {
const { const {
value, value,
valueField,
delimiter,
options, options,
className, className,
placeholder, placeholder,
disabled,
inline, inline,
labelClassName labelClassName,
disabled,
classnames: cx,
option2value,
itemClassName,
itemRender
} = this.props; } = this.props;
let valueArray = value2array(value, { let valueArray = Checkboxes.value2array(value, options, option2value);
multiple: true,
valueField,
delimiter,
options
});
let body: Array<React.ReactNode> = []; let body: Array<React.ReactNode> = [];
if (options) { if (Array.isArray(options) && options.length) {
body = options.map((option, key) => ( body = options.map((option, key) => (
<Checkbox <Checkbox
className={cx(itemClassName, option.className)}
key={key} key={key}
onChange={() => this.toggleOption(option)} onChange={() => this.toggleOption(option)}
checked={!!~valueArray.indexOf(option)} checked={!!~valueArray.indexOf(option)}
disabled={disabled || option.disabled} disabled={disabled || option.disabled}
inline={inline}
labelClassName={labelClassName} labelClassName={labelClassName}
description={option.description} description={option.description}
> >
{option.label} {itemRender(option)}
</Checkbox> </Checkbox>
)); ));
} }
return ( return (
<div className={className}> <div className={cx('Checkboxes', className, inline ? 'Checkboxes--inline' : '')}>
{body && body.length ? body : placeholder} {body && body.length ? body : (
<div>{placeholder}</div>
)}
</div> </div>
); );
} }

View File

@ -47,16 +47,14 @@ export interface OptionProps {
delimiter?: string; delimiter?: string;
clearable?: boolean; clearable?: boolean;
placeholder?: string; placeholder?: string;
autoFill?: {[propName: string]: any}; disabled?: boolean;
creatable?: boolean; creatable?: boolean;
onAdd?: ( onAdd?: (
idx?: number | Array<number>, idx?: number | Array<number>,
value?: any, value?: any,
skipForm?: boolean skipForm?: boolean
) => void; ) => void;
addControls?: Array<any>;
editable?: boolean; editable?: boolean;
editControls?: Array<any>;
onEdit?: (value: Option, origin?: Option, skipForm?: boolean) => void; onEdit?: (value: Option, origin?: Option, skipForm?: boolean) => void;
removable?: boolean; removable?: boolean;
onDelete?: (value: Option) => void; onDelete?: (value: Option) => void;

View File

@ -17,14 +17,14 @@ export interface SelectionsProps extends ThemeProps {
disabled?: boolean; disabled?: boolean;
title?: string; title?: string;
placeholder: string; placeholder: string;
optionRender: (option: Option) => JSX.Element; itemRender: (option: Option) => JSX.Element;
itemClassName?: string; itemClassName?: string;
} }
export class Selections extends React.Component<SelectionsProps> { export class Selections extends React.Component<SelectionsProps> {
static defaultProps: Pick<SelectionsProps, 'placeholder' | 'optionRender'> = { static defaultProps: Pick<SelectionsProps, 'placeholder' | 'itemRender'> = {
placeholder: '请先选择数据', placeholder: '请先选择数据',
optionRender: (option: Option) => <span>{option.label}</span> itemRender: (option: Option) => <span>{option.label}</span>
}; };
id = guid(); id = guid();
@ -115,7 +115,7 @@ export class Selections extends React.Component<SelectionsProps> {
className, className,
value, value,
placeholder, placeholder,
optionRender, itemRender,
disabled, disabled,
title, title,
itemClassName, itemClassName,
@ -130,11 +130,11 @@ export class Selections extends React.Component<SelectionsProps> {
<div className={cx('Selections-items')}> <div className={cx('Selections-items')}>
{value.map((option, index) => ( {value.map((option, index) => (
<div className={cx('Selections-item', itemClassName, option?.className)} key={index}> <div className={cx('Selections-item', itemClassName, option?.className)} key={index}>
{sortable && !disabled ? ( {sortable && !disabled && value.length > 1 ? (
<Icon className={cx('Selections-dragbar')} icon="combo-dragger"/> <Icon className={cx('Selections-dragbar')} icon="combo-dragger"/>
) : null} ) : null}
<label>{optionRender(option)}</label> <label>{itemRender(option)}</label>
{!disabled ? ( {!disabled ? (
<a <a