import * as React from 'react'; import PropTypes from 'prop-types'; import RcSelect, { Option, OptGroup } from 'rc-select'; import classNames from 'classnames'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import defaultLocale from '../locale-provider/default'; export interface AbstractSelectProps { prefixCls?: string; className?: string; size?: 'default' | 'large' | 'small'; notFoundContent?: React.ReactNode | null; transitionName?: string; choiceTransitionName?: string; showSearch?: boolean; allowClear?: boolean; disabled?: boolean; style?: React.CSSProperties; placeholder?: string; defaultActiveFirstOption?: boolean; dropdownClassName?: string; dropdownStyle?: React.CSSProperties; dropdownMenuStyle?: React.CSSProperties; onSearch?: (value: string) => any; filterOption?: boolean | ((inputValue: string, option: React.ReactElement) => any); } export interface LabeledValue { key: string; label: React.ReactNode; } export type SelectValue = string | any[] | LabeledValue | LabeledValue[]; export interface SelectProps extends AbstractSelectProps { value?: SelectValue; defaultValue?: SelectValue; mode?: 'default' | 'multiple' | 'tags' | 'combobox'; optionLabelProp?: string; onChange?: (value: SelectValue) => void; onSelect?: (value: SelectValue, option: Object) => any; onDeselect?: (value: SelectValue) => any; onBlur?: () => any; onFocus?: () => any; onInputKeyDown?: (e: React.KeyboardEvent) => void; maxTagCount?: number; maxTagPlaceholder?: React.ReactNode | ((omittedValues: SelectValue[]) => React.ReactNode); dropdownMatchSelectWidth?: boolean; optionFilterProp?: string; labelInValue?: boolean; getPopupContainer?: (triggerNode: Element) => HTMLElement; tokenSeparators?: string[]; getInputElement?: () => React.ReactElement; autoFocus?: boolean; } export interface OptionProps { disabled?: boolean; value?: any; title?: string; children?: React.ReactNode; } export interface OptGroupProps { label?: React.ReactNode; } export interface SelectLocale { notFoundContent?: string; } const SelectPropTypes = { prefixCls: PropTypes.string, className: PropTypes.string, size: PropTypes.oneOf(['default', 'large', 'small']), combobox: PropTypes.bool, notFoundContent: PropTypes.any, showSearch: PropTypes.bool, optionLabelProp: PropTypes.string, transitionName: PropTypes.string, choiceTransitionName: PropTypes.string, }; // => It is needless to export the declaration of below two inner components. // export { Option, OptGroup }; export default class Select extends React.Component { static Option = Option as React.ClassicComponentClass; static OptGroup = OptGroup as React.ClassicComponentClass; static defaultProps = { prefixCls: 'ant-select', showSearch: false, transitionName: 'slide-up', choiceTransitionName: 'zoom', }; static propTypes = SelectPropTypes; private rcSelect: any; focus() { this.rcSelect.focus(); } blur() { this.rcSelect.blur(); } saveSelect = (node: any) => { this.rcSelect = node; } getNotFoundContent(locale: SelectLocale) { const { notFoundContent, mode } = this.props; const isCombobox = mode === 'combobox'; if (isCombobox) { // AutoComplete don't have notFoundContent defaultly return notFoundContent === undefined ? null : notFoundContent; } return notFoundContent === undefined ? locale.notFoundContent : notFoundContent; } renderSelect = (locale: SelectLocale) => { const { prefixCls, className = '', size, mode, ...restProps, } = this.props; const cls = classNames({ [`${prefixCls}-lg`]: size === 'large', [`${prefixCls}-sm`]: size === 'small', }, className); let { optionLabelProp } = this.props; const isCombobox = mode === 'combobox'; if (isCombobox) { // children 带 dom 结构时,无法填入输入框 optionLabelProp = optionLabelProp || 'value'; } const modeConfig = { multiple: mode === 'multiple', tags: mode === 'tags', combobox: isCombobox, }; return ( ); } render() { return ( {this.renderSelect} ); } }