import * as React from 'react'; import RcTreeSelect, { TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD, TreeSelectProps as RcTreeSelectProps, } from 'rc-tree-select'; import classNames from 'classnames'; import omit from 'omit.js'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import warning from '../_util/warning'; import { AntTreeNodeProps } from '../tree'; import getIcons from '../select/utils/iconUtil'; import renderSwitcherIcon from '../tree/utils/iconUtil'; import SizeContext, { SizeType } from '../config-provider/SizeContext'; type RawValue = string | number; export interface LabeledValue { key?: string; value: RawValue; label: React.ReactNode; } export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[]; export interface TreeSelectProps extends Omit< RcTreeSelectProps, 'showTreeIcon' | 'treeMotion' | 'inputIcon' | 'mode' | 'getInputElement' | 'backfill' > { suffixIcon?: React.ReactNode; size?: SizeType; bordered?: boolean; } class TreeSelect extends React.Component, {}> { static TreeNode = TreeNode; static SHOW_ALL: typeof SHOW_ALL = SHOW_ALL; static SHOW_PARENT: typeof SHOW_PARENT = SHOW_PARENT; static SHOW_CHILD: typeof SHOW_CHILD = SHOW_CHILD; static defaultProps = { transitionName: 'slide-up', choiceTransitionName: 'zoom', bordered: true, }; selectRef = React.createRef(); constructor(props: TreeSelectProps) { super(props); warning( props.multiple !== false || !props.treeCheckable, 'TreeSelect', '`multiple` will alway be `true` when `treeCheckable` is true', ); } focus() { if (this.selectRef.current) { this.selectRef.current.focus(); } } blur() { if (this.selectRef.current) { this.selectRef.current.blur(); } } renderTreeSelect = ({ getPopupContainer: getContextPopupContainer, getPrefixCls, renderEmpty, direction, }: ConfigConsumerProps) => { const { prefixCls: customizePrefixCls, size: customizeSize, className, treeCheckable, multiple, listHeight = 256, listItemHeight = 32, notFoundContent, switcherIcon, treeLine, getPopupContainer, dropdownClassName, bordered, treeIcon = false, } = this.props; const prefixCls = getPrefixCls('select', customizePrefixCls); const treePrefixCls = getPrefixCls('select-tree', customizePrefixCls); const treeSelectPrefixCls = getPrefixCls('tree-select', customizePrefixCls); const mergedDropdownClassName = classNames( dropdownClassName, `${treeSelectPrefixCls}-dropdown`, { [`${treeSelectPrefixCls}-dropdown-rtl`]: direction === 'rtl', }, ); const isMultiple = !!(treeCheckable || multiple); // ===================== Icons ===================== const { suffixIcon, itemIcon, removeIcon, clearIcon } = getIcons({ ...this.props, multiple: isMultiple, }); // ===================== Empty ===================== let mergedNotFound: React.ReactNode; if (notFoundContent !== undefined) { mergedNotFound = notFoundContent; } else { mergedNotFound = renderEmpty('Select'); } // ==================== Render ===================== const selectProps = omit(this.props, [ 'prefixCls', 'suffixIcon', 'itemIcon', 'removeIcon', 'clearIcon', 'switcherIcon', 'size', 'bordered', ]); return ( {size => { const mergedSize = customizeSize || size; const mergedClassName = classNames( !customizePrefixCls && treeSelectPrefixCls, { [`${prefixCls}-lg`]: mergedSize === 'large', [`${prefixCls}-sm`]: mergedSize === 'small', [`${prefixCls}-rtl`]: direction === 'rtl', [`${prefixCls}-borderless`]: !bordered, }, className, ); return ( ) : ( treeCheckable ) } inputIcon={suffixIcon} menuItemSelectedIcon={itemIcon} removeIcon={removeIcon} clearIcon={clearIcon} switcherIcon={(nodeProps: AntTreeNodeProps) => renderSwitcherIcon(treePrefixCls, switcherIcon, treeLine, nodeProps) } showTreeIcon={treeIcon} notFoundContent={mergedNotFound} getPopupContainer={getPopupContainer || getContextPopupContainer} treeMotion={null} dropdownClassName={mergedDropdownClassName} /> ); }} ); }; render() { return {this.renderTreeSelect}; } } export { TreeNode }; export default TreeSelect;