ant-design/components/checkbox/Group.tsx

190 lines
5.3 KiB
TypeScript
Raw Normal View History

import * as React from 'react';
2018-08-07 21:07:52 +08:00
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import shallowEqual from 'shallowequal';
import omit from 'omit.js';
import Checkbox, { CheckboxChangeEvent } from './Checkbox';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
2017-07-08 17:46:18 +08:00
export type CheckboxValueType = string | number | boolean;
export interface CheckboxOptionType {
2018-12-06 08:28:31 +08:00
label: React.ReactNode;
value: CheckboxValueType;
style?: React.CSSProperties;
2016-07-13 11:14:24 +08:00
disabled?: boolean;
onChange?: (e: CheckboxChangeEvent) => void;
}
export interface AbstractCheckboxGroupProps {
prefixCls?: string;
className?: string;
options?: Array<CheckboxOptionType | string>;
disabled?: boolean;
style?: React.CSSProperties;
}
export interface CheckboxGroupProps extends AbstractCheckboxGroupProps {
2019-03-30 10:47:03 +08:00
name?: string;
defaultValue?: Array<CheckboxValueType>;
value?: Array<CheckboxValueType>;
onChange?: (checkedValue: Array<CheckboxValueType>) => void;
}
2016-07-07 20:25:03 +08:00
export interface CheckboxGroupState {
value: CheckboxValueType[];
registeredValues: CheckboxValueType[];
}
2017-11-21 21:15:36 +08:00
export interface CheckboxGroupContext {
checkboxGroup: {
toggleOption: (option: CheckboxOptionType) => void;
2019-06-24 11:29:58 +08:00
value: any;
2017-11-21 21:15:36 +08:00
disabled: boolean;
};
}
export const GroupContext = React.createContext<{ checkboxGroup: any }>({
checkboxGroup: undefined,
});
class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupState> {
static defaultProps = {
options: [],
2016-07-13 11:14:24 +08:00
};
static propTypes = {
defaultValue: PropTypes.array,
value: PropTypes.array,
options: PropTypes.array.isRequired,
onChange: PropTypes.func,
2016-07-13 11:14:24 +08:00
};
static getDerivedStateFromProps(nextProps: CheckboxGroupProps) {
if ('value' in nextProps) {
return {
value: nextProps.value || [],
};
}
return null;
}
2017-11-21 21:15:36 +08:00
constructor(props: CheckboxGroupProps) {
super(props);
this.state = {
value: props.value || props.defaultValue || [],
registeredValues: [],
2018-12-07 20:02:01 +08:00
};
}
2017-11-21 21:15:36 +08:00
shouldComponentUpdate(nextProps: CheckboxGroupProps, nextState: CheckboxGroupState) {
2018-12-07 20:02:01 +08:00
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
}
2018-11-22 23:35:40 +08:00
getOptions() {
const { options } = this.props;
2016-08-22 17:26:14 +08:00
// https://github.com/Microsoft/TypeScript/issues/7960
return (options as Array<CheckboxOptionType>).map(option => {
if (typeof option === 'string') {
return {
label: option,
value: option,
2016-08-24 16:09:55 +08:00
} as CheckboxOptionType;
}
return option;
});
}
2018-11-22 23:35:40 +08:00
2019-08-05 18:38:10 +08:00
cancelValue = (value: string) => {
this.setState(({ registeredValues }) => ({
registeredValues: registeredValues.filter(val => val !== value),
}));
};
registerValue = (value: string) => {
this.setState(({ registeredValues }) => ({
registeredValues: [...registeredValues, value],
}));
};
2017-11-21 21:15:36 +08:00
toggleOption = (option: CheckboxOptionType) => {
const { registeredValues } = this.state;
const optionIndex = this.state.value.indexOf(option.value);
2016-03-01 17:01:03 +08:00
const value = [...this.state.value];
2018-12-07 20:02:01 +08:00
if (optionIndex === -1) {
value.push(option.value);
} else {
value.splice(optionIndex, 1);
}
if (!('value' in this.props)) {
this.setState({ value });
}
2019-08-05 18:38:10 +08:00
const { onChange } = this.props;
2016-10-24 12:04:26 +08:00
if (onChange) {
const options = this.getOptions();
2019-06-28 10:26:55 +08:00
onChange(
value
.filter(val => registeredValues.indexOf(val) !== -1)
.sort((a, b) => {
const indexA = options.findIndex(opt => opt.value === a);
const indexB = options.findIndex(opt => opt.value === b);
2019-06-28 10:31:40 +08:00
return indexA - indexB;
2019-06-28 10:26:55 +08:00
}),
);
2016-10-24 12:04:26 +08:00
}
2018-12-07 20:02:01 +08:00
};
2018-11-22 23:35:40 +08:00
renderGroup = ({ getPrefixCls }: ConfigConsumerProps) => {
const { props, state } = this;
2018-12-07 20:02:01 +08:00
const { prefixCls: customizePrefixCls, className, style, options, ...restProps } = props;
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
const domProps = omit(restProps, ['children', 'defaultValue', 'value', 'onChange', 'disabled']);
2019-08-05 18:38:10 +08:00
let { children } = props;
if (options && options.length > 0) {
children = this.getOptions().map(option => (
<Checkbox
prefixCls={prefixCls}
key={option.value.toString()}
disabled={'disabled' in option ? option.disabled : props.disabled}
value={option.value}
checked={state.value.indexOf(option.value) !== -1}
onChange={option.onChange}
className={`${groupPrefixCls}-item`}
style={option.style}
>
{option.label}
</Checkbox>
));
}
const context = {
checkboxGroup: {
toggleOption: this.toggleOption,
value: this.state.value,
disabled: this.props.disabled,
name: this.props.name,
// https://github.com/ant-design/ant-design/issues/16376
registerValue: this.registerValue,
cancelValue: this.cancelValue,
},
};
const classString = classNames(groupPrefixCls, className);
return (
<div className={classString} style={style} {...domProps}>
<GroupContext.Provider value={context}>{children}</GroupContext.Provider>
</div>
);
2018-12-07 20:02:01 +08:00
};
render() {
2018-12-07 20:02:01 +08:00
return <ConfigConsumer>{this.renderGroup}</ConfigConsumer>;
}
}
export default CheckboxGroup;