2023-09-11 17:28:04 +08:00
import * as React from 'react' ;
2015-12-28 19:16:02 +08:00
import classNames from 'classnames' ;
2021-12-21 21:38:11 +08:00
import type { BaseSelectRef } from 'rc-select' ;
2023-03-30 14:55:34 +08:00
import type { Placement } from 'rc-select/lib/BaseSelect' ;
2022-06-22 14:57:09 +08:00
import type { TreeSelectProps as RcTreeSelectProps } from 'rc-tree-select' ;
2024-10-16 21:17:56 +08:00
import type { DataNode } from 'rc-tree-select/lib/interface' ;
2022-06-22 14:57:09 +08:00
import RcTreeSelect , { SHOW_ALL , SHOW_CHILD , SHOW_PARENT , TreeNode } from 'rc-tree-select' ;
import omit from 'rc-util/lib/omit' ;
2023-09-11 17:28:04 +08:00
2023-12-27 11:53:19 +08:00
import { useZIndex } from '../_util/hooks/useZIndex' ;
2023-03-30 14:55:34 +08:00
import type { SelectCommonPlacement } from '../_util/motion' ;
2023-07-25 10:54:58 +08:00
import { getTransitionName } from '../_util/motion' ;
2023-09-11 17:28:04 +08:00
import genPurePanel from '../_util/PurePanel' ;
2023-03-30 14:55:34 +08:00
import type { InputStatus } from '../_util/statusUtils' ;
import { getMergedStatus , getStatusClassNames } from '../_util/statusUtils' ;
2023-09-11 17:28:04 +08:00
import { devUseWarning } from '../_util/warning' ;
2020-11-08 15:27:30 +08:00
import { ConfigContext } from '../config-provider' ;
2024-07-12 10:18:17 +08:00
import type { Variant } from '../config-provider' ;
2023-03-30 14:55:34 +08:00
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty' ;
2023-09-11 17:28:04 +08:00
import DisabledContext from '../config-provider/DisabledContext' ;
2023-12-27 11:53:19 +08:00
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls' ;
2023-05-12 14:53:47 +08:00
import useSize from '../config-provider/hooks/useSize' ;
2023-09-11 17:28:04 +08:00
import type { SizeType } from '../config-provider/SizeContext' ;
2022-06-22 14:57:09 +08:00
import { FormItemInputContext } from '../form/context' ;
2023-12-27 14:42:51 +08:00
import useVariant from '../form/hooks/useVariants' ;
2023-12-28 07:07:32 +08:00
import mergedBuiltinPlacements from '../select/mergedBuiltinPlacements' ;
2022-06-22 15:18:03 +08:00
import useSelectStyle from '../select/style' ;
2023-09-11 17:28:04 +08:00
import useIcons from '../select/useIcons' ;
2023-12-27 11:53:19 +08:00
import useShowArrow from '../select/useShowArrow' ;
2023-03-30 14:55:34 +08:00
import { useCompactItemContext } from '../space/Compact' ;
2022-05-07 14:31:54 +08:00
import type { AntTreeNodeProps , TreeProps } from '../tree' ;
import type { SwitcherIcon } from '../tree/Tree' ;
2023-04-01 13:38:34 +08:00
import SwitcherIconCom from '../tree/utils/iconUtil' ;
2024-11-11 15:07:15 +08:00
import { useToken } from '../theme/internal' ;
2022-06-22 15:18:03 +08:00
import useStyle from './style' ;
2019-09-28 11:31:28 +08:00
type RawValue = string | number ;
export interface LabeledValue {
key? : string ;
value : RawValue ;
label : React.ReactNode ;
}
2015-12-28 19:16:02 +08:00
2019-09-28 11:31:28 +08:00
export type SelectValue = RawValue | RawValue [ ] | LabeledValue | LabeledValue [ ] ;
2016-08-01 16:35:01 +08:00
2024-10-16 21:17:56 +08:00
export interface TreeSelectProps < ValueType = any , OptionType extends DataNode = DataNode >
extends Omit <
2021-12-21 21:38:11 +08:00
RcTreeSelectProps < ValueType , OptionType > ,
2021-05-27 14:48:48 +08:00
| 'showTreeIcon'
| 'treeMotion'
| 'mode'
| 'getInputElement'
| 'backfill'
| 'treeLine'
2022-06-23 12:17:05 +08:00
| 'switcherIcon'
2019-09-28 11:31:28 +08:00
> {
2020-02-29 23:35:57 +08:00
suffixIcon? : React.ReactNode ;
2020-01-03 13:38:16 +08:00
size? : SizeType ;
2022-04-29 20:48:10 +08:00
disabled? : boolean ;
2022-01-20 16:54:47 +08:00
placement? : SelectCommonPlacement ;
2022-08-05 11:21:07 +08:00
popupClassName? : string ;
2022-09-08 14:33:11 +08:00
/** @deprecated Please use `popupClassName` instead */
dropdownClassName? : string ;
2023-12-21 13:39:04 +08:00
/** @deprecated Use `variant` instead. */
2020-02-06 10:02:02 +08:00
bordered? : boolean ;
2021-05-27 14:48:48 +08:00
treeLine? : TreeProps [ 'showLine' ] ;
2022-02-17 16:41:12 +08:00
status? : InputStatus ;
2022-06-23 12:17:05 +08:00
switcherIcon? : SwitcherIcon | RcTreeSelectProps < ValueType , OptionType > [ 'switcherIcon' ] ;
2023-01-20 11:03:50 +08:00
rootClassName? : string ;
2023-04-25 15:27:00 +08:00
[ key : ` aria- ${ string } ` ] : React . AriaAttributes [ keyof React . AriaAttributes ] ;
2023-04-04 17:17:36 +08:00
/** @deprecated Please use `popupMatchSelectWidth` instead */
dropdownMatchSelectWidth? : boolean | number ;
popupMatchSelectWidth? : boolean | number ;
2023-07-19 20:27:09 +08:00
/ * *
* @deprecated ` showArrow ` is deprecated which will be removed in next major version . It will be a
* default behavior , you can hide it by setting ` suffixIcon ` to null .
* /
showArrow? : boolean ;
2023-12-21 13:39:04 +08:00
/ * *
* @since 5.13 . 0
* @default "outlined"
* /
2023-12-22 10:05:15 +08:00
variant? : Variant ;
2019-09-28 11:31:28 +08:00
}
2024-10-16 21:17:56 +08:00
const InternalTreeSelect = < ValueType = any , OptionType extends DataNode = DataNode > (
2024-08-08 19:28:32 +08:00
props : TreeSelectProps < ValueType , OptionType > ,
ref : React.Ref < BaseSelectRef > ,
) = > {
const {
2020-11-08 15:27:30 +08:00
prefixCls : customizePrefixCls ,
size : customizeSize ,
2022-04-29 20:48:10 +08:00
disabled : customDisabled ,
2020-11-08 15:27:30 +08:00
bordered = true ,
className ,
2023-01-20 11:03:50 +08:00
rootClassName ,
2020-11-08 15:27:30 +08:00
treeCheckable ,
multiple ,
listHeight = 256 ,
2024-11-11 15:07:15 +08:00
listItemHeight : customListItemHeight ,
2022-01-20 16:54:47 +08:00
placement ,
2020-11-08 15:27:30 +08:00
notFoundContent ,
switcherIcon ,
treeLine ,
getPopupContainer ,
2022-08-05 11:21:07 +08:00
popupClassName ,
2022-09-08 14:33:11 +08:00
dropdownClassName ,
2020-11-08 15:27:30 +08:00
treeIcon = false ,
2021-02-08 17:09:13 +08:00
transitionName ,
2020-11-08 15:27:30 +08:00
choiceTransitionName = '' ,
2022-02-17 16:41:12 +08:00
status : customStatus ,
2022-06-06 18:44:58 +08:00
treeExpandAction ,
2023-04-04 13:43:53 +08:00
builtinPlacements ,
2023-04-04 17:17:36 +08:00
dropdownMatchSelectWidth ,
popupMatchSelectWidth ,
2023-08-02 14:21:11 +08:00
allowClear ,
2023-12-21 13:39:04 +08:00
variant : customVariant ,
2023-12-27 19:40:42 +08:00
dropdownStyle ,
tagRender ,
2024-08-08 19:28:32 +08:00
. . . restProps
} = props ;
2020-11-08 15:27:30 +08:00
const {
2018-12-26 16:01:00 +08:00
getPopupContainer : getContextPopupContainer ,
getPrefixCls ,
renderEmpty ,
2020-01-02 19:10:16 +08:00
direction ,
2020-05-05 15:00:43 +08:00
virtual ,
2023-04-04 17:17:36 +08:00
popupMatchSelectWidth : contextPopupMatchSelectWidth ,
2023-04-07 10:17:00 +08:00
popupOverflow ,
2020-11-08 15:27:30 +08:00
} = React . useContext ( ConfigContext ) ;
2024-11-11 15:07:15 +08:00
const [ , token ] = useToken ( ) ;
const listItemHeight = customListItemHeight ? ? token ? . controlHeightSM + token ? . paddingXXS ;
2022-09-08 14:33:11 +08:00
if ( process . env . NODE_ENV !== 'production' ) {
2023-09-13 22:07:33 +08:00
const warning = devUseWarning ( 'TreeSelect' ) ;
2023-09-11 17:28:04 +08:00
2022-09-08 14:33:11 +08:00
warning (
multiple !== false || ! treeCheckable ,
2023-09-11 17:28:04 +08:00
'usage' ,
2022-09-08 14:33:11 +08:00
'`multiple` will always be `true` when `treeCheckable` is true' ,
) ;
2023-09-13 22:07:33 +08:00
warning . deprecated ( ! dropdownClassName , 'dropdownClassName' , 'popupClassName' ) ;
2023-04-04 17:17:36 +08:00
2023-09-13 22:07:33 +08:00
warning . deprecated (
2023-04-04 17:17:36 +08:00
dropdownMatchSelectWidth === undefined ,
2023-09-13 22:07:33 +08:00
'dropdownMatchSelectWidth' ,
'popupMatchSelectWidth' ,
2023-04-04 17:17:36 +08:00
) ;
2023-07-19 20:27:09 +08:00
warning (
! ( 'showArrow' in props ) ,
2023-09-11 17:28:04 +08:00
'deprecated' ,
2023-07-19 20:27:09 +08:00
'`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.' ,
) ;
2023-12-21 13:39:04 +08:00
warning . deprecated ( ! ( 'bordered' in props ) , 'bordered' , 'variant' ) ;
2022-09-08 14:33:11 +08:00
}
2020-11-08 15:27:30 +08:00
2022-03-09 15:33:39 +08:00
const rootPrefixCls = getPrefixCls ( ) ;
2020-11-08 15:27:30 +08:00
const prefixCls = getPrefixCls ( 'select' , customizePrefixCls ) ;
const treePrefixCls = getPrefixCls ( 'select-tree' , customizePrefixCls ) ;
const treeSelectPrefixCls = getPrefixCls ( 'tree-select' , customizePrefixCls ) ;
2022-10-18 16:23:10 +08:00
const { compactSize , compactItemClassnames } = useCompactItemContext ( prefixCls , direction ) ;
2020-11-08 15:27:30 +08:00
2023-11-14 19:17:23 +08:00
const rootCls = useCSSVarCls ( prefixCls ) ;
const treeSelectRootCls = useCSSVarCls ( treeSelectPrefixCls ) ;
2023-12-14 14:58:53 +08:00
const [ wrapCSSVar , hashId , cssVarCls ] = useSelectStyle ( prefixCls , rootCls ) ;
2023-11-29 17:23:45 +08:00
const [ treeSelectWrapCSSVar ] = useStyle ( treeSelectPrefixCls , treePrefixCls , treeSelectRootCls ) ;
2022-03-09 15:33:39 +08:00
2024-06-21 17:47:09 +08:00
const [ variant , enableVariantCls ] = useVariant ( 'treeSelect' , customVariant , bordered ) ;
2023-12-21 13:39:04 +08:00
2022-03-09 15:33:39 +08:00
const mergedDropdownClassName = classNames (
2022-09-08 14:33:11 +08:00
popupClassName || dropdownClassName ,
2022-03-09 15:33:39 +08:00
` ${ treeSelectPrefixCls } -dropdown ` ,
{
[ ` ${ treeSelectPrefixCls } -dropdown-rtl ` ] : direction === 'rtl' ,
} ,
2023-01-20 11:03:50 +08:00
rootClassName ,
2023-12-14 14:58:53 +08:00
cssVarCls ,
2023-11-14 19:17:23 +08:00
rootCls ,
treeSelectRootCls ,
2022-03-09 15:33:39 +08:00
hashId ,
) ;
2020-11-08 15:27:30 +08:00
const isMultiple = ! ! ( treeCheckable || multiple ) ;
2023-12-30 02:40:22 +08:00
2023-07-19 20:27:09 +08:00
const showSuffixIcon = useShowArrow ( props . suffixIcon , props . showArrow ) ;
2022-02-17 16:41:12 +08:00
2023-04-04 17:17:36 +08:00
const mergedPopupMatchSelectWidth =
popupMatchSelectWidth ? ? dropdownMatchSelectWidth ? ? contextPopupMatchSelectWidth ;
2022-03-24 21:54:20 +08:00
// ===================== Form =====================
2022-03-25 17:48:12 +08:00
const {
status : contextStatus ,
hasFeedback ,
isFormItemInput ,
feedbackIcon ,
2022-12-06 21:09:59 +08:00
} = React . useContext ( FormItemInputContext ) ;
2022-02-17 16:41:12 +08:00
const mergedStatus = getMergedStatus ( contextStatus , customStatus ) ;
2020-11-08 15:27:30 +08:00
// ===================== Icons =====================
2023-09-11 17:28:04 +08:00
const { suffixIcon , removeIcon , clearIcon } = useIcons ( {
2024-08-08 19:28:32 +08:00
. . . restProps ,
2020-11-08 15:27:30 +08:00
multiple : isMultiple ,
2023-07-19 20:27:09 +08:00
showSuffixIcon ,
2022-02-17 16:41:12 +08:00
hasFeedback ,
2022-03-25 17:48:12 +08:00
feedbackIcon ,
2020-11-08 15:27:30 +08:00
prefixCls ,
2023-08-02 14:21:11 +08:00
componentName : 'TreeSelect' ,
2020-11-08 15:27:30 +08:00
} ) ;
2023-08-02 14:21:11 +08:00
const mergedAllowClear = allowClear === true ? { clearIcon } : allowClear ;
2020-11-08 15:27:30 +08:00
// ===================== Empty =====================
let mergedNotFound : React.ReactNode ;
if ( notFoundContent !== undefined ) {
mergedNotFound = notFoundContent ;
} else {
2023-01-09 10:04:35 +08:00
mergedNotFound = renderEmpty ? . ( 'Select' ) || < DefaultRenderEmpty componentName = "Select" / > ;
2017-10-20 14:54:38 +08:00
}
2020-11-08 15:27:30 +08:00
// ==================== Render =====================
2024-08-08 19:28:32 +08:00
const selectProps = omit ( restProps , [
2020-11-08 15:27:30 +08:00
'suffixIcon' ,
'removeIcon' ,
'clearIcon' ,
2023-12-27 19:40:42 +08:00
'itemIcon' as any ,
'switcherIcon' as any ,
2020-11-08 15:27:30 +08:00
] ) ;
2022-01-20 16:54:47 +08:00
// ===================== Placement =====================
2023-02-24 22:35:22 +08:00
const memoizedPlacement = React . useMemo < Placement > ( ( ) = > {
2022-01-20 16:54:47 +08:00
if ( placement !== undefined ) {
return placement ;
}
2023-01-09 10:04:35 +08:00
return direction === 'rtl' ? 'bottomRight' : 'bottomLeft' ;
2023-02-24 22:35:22 +08:00
} , [ placement , direction ] ) ;
2022-01-20 16:54:47 +08:00
2023-06-19 14:26:48 +08:00
const mergedSize = useSize ( ( ctx ) = > customizeSize ? ? compactSize ? ? ctx ) ;
2023-05-12 14:53:47 +08:00
2022-04-29 20:48:10 +08:00
// ===================== Disabled =====================
const disabled = React . useContext ( DisabledContext ) ;
2022-09-20 16:48:59 +08:00
const mergedDisabled = customDisabled ? ? disabled ;
2022-04-29 20:48:10 +08:00
2020-11-08 15:27:30 +08:00
const mergedClassName = classNames (
! customizePrefixCls && treeSelectPrefixCls ,
{
[ ` ${ prefixCls } -lg ` ] : mergedSize === 'large' ,
[ ` ${ prefixCls } -sm ` ] : mergedSize === 'small' ,
[ ` ${ prefixCls } -rtl ` ] : direction === 'rtl' ,
2023-12-21 13:39:04 +08:00
[ ` ${ prefixCls } - ${ variant } ` ] : enableVariantCls ,
2022-03-24 21:54:20 +08:00
[ ` ${ prefixCls } -in-form-item ` ] : isFormItemInput ,
2020-11-08 15:27:30 +08:00
} ,
2022-02-17 16:41:12 +08:00
getStatusClassNames ( prefixCls , mergedStatus , hasFeedback ) ,
2022-10-18 16:23:10 +08:00
compactItemClassnames ,
2020-11-08 15:27:30 +08:00
className ,
2023-01-20 11:03:50 +08:00
rootClassName ,
2023-12-14 14:58:53 +08:00
cssVarCls ,
2023-11-14 19:17:23 +08:00
rootCls ,
treeSelectRootCls ,
2022-03-09 15:33:39 +08:00
hashId ,
2020-11-08 15:27:30 +08:00
) ;
2024-07-12 10:18:17 +08:00
const renderSwitcherIcon = ( nodeProps : AntTreeNodeProps ) = > (
2023-04-01 13:38:34 +08:00
< SwitcherIconCom
prefixCls = { treePrefixCls }
2024-07-09 16:26:35 +08:00
switcherIcon = { switcherIcon as SwitcherIcon }
2023-04-01 13:38:34 +08:00
treeNodeProps = { nodeProps }
showLine = { treeLine }
/ >
) ;
2023-10-24 11:49:30 +08:00
// ============================ zIndex ============================
2023-12-27 19:40:42 +08:00
const [ zIndex ] = useZIndex ( 'SelectLike' , dropdownStyle ? . zIndex as number ) ;
2023-10-24 11:49:30 +08:00
2022-03-09 15:33:39 +08:00
const returnNode = (
2020-11-08 15:27:30 +08:00
< RcTreeSelect
virtual = { virtual }
2022-04-29 20:48:10 +08:00
disabled = { mergedDisabled }
2020-11-08 15:27:30 +08:00
{ . . . selectProps }
2023-04-04 17:17:36 +08:00
dropdownMatchSelectWidth = { mergedPopupMatchSelectWidth }
2023-12-28 07:07:32 +08:00
builtinPlacements = { mergedBuiltinPlacements ( builtinPlacements , popupOverflow ) }
2023-03-30 14:55:34 +08:00
ref = { ref }
2020-11-08 15:27:30 +08:00
prefixCls = { prefixCls }
className = { mergedClassName }
listHeight = { listHeight }
listItemHeight = { listItemHeight }
treeCheckable = {
treeCheckable ? < span className = { ` ${ prefixCls } -tree-checkbox-inner ` } / > : treeCheckable
}
2021-05-27 14:48:48 +08:00
treeLine = { ! ! treeLine }
2023-07-19 20:27:09 +08:00
suffixIcon = { suffixIcon }
2023-04-07 10:18:16 +08:00
multiple = { isMultiple }
2023-02-24 22:35:22 +08:00
placement = { memoizedPlacement }
2020-11-08 15:27:30 +08:00
removeIcon = { removeIcon }
2023-08-02 14:21:11 +08:00
allowClear = { mergedAllowClear }
2024-07-09 16:26:35 +08:00
switcherIcon = { renderSwitcherIcon as RcTreeSelectProps [ 'switcherIcon' ] }
showTreeIcon = { treeIcon as boolean }
2020-11-08 15:27:30 +08:00
notFoundContent = { mergedNotFound }
getPopupContainer = { getPopupContainer || getContextPopupContainer }
treeMotion = { null }
dropdownClassName = { mergedDropdownClassName }
2023-12-27 19:40:42 +08:00
dropdownStyle = { { . . . dropdownStyle , zIndex } }
2021-02-08 17:09:13 +08:00
choiceTransitionName = { getTransitionName ( rootPrefixCls , '' , choiceTransitionName ) }
2023-07-25 10:54:58 +08:00
transitionName = { getTransitionName ( rootPrefixCls , 'slide-up' , transitionName ) }
2022-06-06 18:44:58 +08:00
treeExpandAction = { treeExpandAction }
2023-12-30 02:40:22 +08:00
tagRender = { isMultiple ? tagRender : undefined }
2020-11-08 15:27:30 +08:00
/ >
) ;
2022-03-09 15:33:39 +08:00
2023-11-14 19:17:23 +08:00
return wrapCSSVar ( treeSelectWrapCSSVar ( returnNode ) ) ;
2020-11-08 15:27:30 +08:00
} ;
2021-12-21 21:38:11 +08:00
const TreeSelectRef = React . forwardRef ( InternalTreeSelect ) as <
ValueType = any ,
2024-10-16 21:17:56 +08:00
OptionType extends DataNode = DataNode ,
2021-12-21 21:38:11 +08:00
> (
2023-12-27 11:53:19 +08:00
props : React.PropsWithChildren < TreeSelectProps < ValueType , OptionType > > &
React . RefAttributes < BaseSelectRef > ,
2020-11-08 15:27:30 +08:00
) = > React . ReactElement ;
type InternalTreeSelectType = typeof TreeSelectRef ;
2022-11-19 16:56:23 +08:00
type CompoundedComponent = InternalTreeSelectType & {
2023-07-17 23:43:32 +08:00
displayName? : string ;
2020-11-08 15:27:30 +08:00
TreeNode : typeof TreeNode ;
SHOW_ALL : typeof SHOW_ALL ;
SHOW_PARENT : typeof SHOW_PARENT ;
SHOW_CHILD : typeof SHOW_CHILD ;
2022-07-07 20:05:19 +08:00
_InternalPanelDoNotUseOrYouWillBeFired : typeof PurePanel ;
2022-11-19 16:56:23 +08:00
} ;
2019-09-28 11:31:28 +08:00
2022-11-19 16:56:23 +08:00
const TreeSelect = TreeSelectRef as CompoundedComponent ;
2020-11-08 15:27:30 +08:00
2022-07-07 20:05:19 +08:00
// We don't care debug panel
2023-06-07 21:59:21 +08:00
/* istanbul ignore next */
2022-07-07 20:05:19 +08:00
const PurePanel = genPurePanel ( TreeSelect ) ;
2020-11-08 15:27:30 +08:00
TreeSelect . TreeNode = TreeNode ;
TreeSelect . SHOW_ALL = SHOW_ALL ;
TreeSelect . SHOW_PARENT = SHOW_PARENT ;
TreeSelect . SHOW_CHILD = SHOW_CHILD ;
2022-07-07 20:05:19 +08:00
TreeSelect . _InternalPanelDoNotUseOrYouWillBeFired = PurePanel ;
2020-11-08 15:27:30 +08:00
2023-07-17 23:43:32 +08:00
if ( process . env . NODE_ENV !== 'production' ) {
TreeSelect . displayName = 'TreeSelect' ;
}
2019-09-28 11:31:28 +08:00
export { TreeNode } ;
export default TreeSelect ;