import React, { ReactNode, CSSProperties, useCallback, useMemo } from 'react' import RcTree, { BasicDataNode } from 'rc-tree' import cns from 'classnames' import { usePrefix } from '../ConfigProvider' import { concat } from '../utils' import { Key, NodeData, NodeEvent } from './TreeNode' import { children2TreeData, treeData2RcTreeData } from './utils' import { DownTriangleIcon, RightTriangleIcon } from '../icons' export interface Props { /** * 根结点( 组) */ children?: ReactNode /** * 自动生成 TreeNodes,设置 treeData 后 children 会被忽略 */ treeData?: T[] /** * 是否展示 TreeNode 图标(只是给图标留个空位,没有默认图标) * @default false */ showIcon?: boolean /** * 自定义 TreeNode 图标,showIcon 需要设置为 true */ icon?: ReactNode | ((e: NodeEvent) => ReactNode) /** * 自定义展开/折叠图标 */ switcherIcon?: ReactNode | ((e: NodeEvent) => ReactNode) /** * 可展开/收起父节点的 action * @default false */ expandAction?: false | 'click' | 'doubleClick' /** * 是否默认展开所有父节点 * @default false */ defaultExpandAll?: boolean /** * 默认展开的 TreeNodeKeys, 当 defaultExpandAll = true 时会被忽略 */ defaultExpandedKeys?: Key[] /** * (受控)展开的 TreeNodeKeys */ expandedKeys?: Key[] /** * 展开/收起 TreeNode 时触发 */ onExpandedKeysChange?: (expandedKeys: Key[]) => void /** * 是否可选中高亮某个 TreeNode * @default false */ selectable?: boolean /** * 默认选中高亮的 TreeNodeKey */ defaultSelectedKey?: Key /** * (受控)选中高亮的 TreeNodeKey */ selectedKey?: Key /** * 点击 TreeNode 触发 */ onSelect?: (selectedKey?: Key) => void /** * 是否在 TreeNode 前添加 Checkbox 复选框 * @default false */ checkable?: boolean /** * 默认选中复选框的 TreeNodeKeys */ defaultCheckedKeys?: Key[] /** * (受控)选中复选框的 TreeNodeKeys */ checkedKeys?: Key[] /** * 点击复选框触发 */ onCheckedKeysChange?: (checkedKeys: Key[]) => void /** * 自定义样式名 */ className?: string /** * 自定义样式 */ style?: CSSProperties } export interface RcNodeData extends BasicDataNode { // rc-tree 实际用的属性, key === nodeKey key: Key // 保留 nodeKey 是为了 NodeEvent 的 data 可以带上 nodeKey nodeKey: Key title?: ReactNode | ((data: RcNodeData) => ReactNode) children?: RcNodeData[] } export default function Tree({ children, treeData, showIcon = false, switcherIcon = defaultSwitcherIcon, expandAction, onExpandedKeysChange, selectable = false, defaultSelectedKey, selectedKey, onSelect, checkable, onCheckedKeysChange, className, ...restProps }: Props) { const prefix = usePrefix('tree') const rcTreeData: RcNodeData[] = useMemo(() => { const rawTreeData = treeData ?? children2TreeData(children) return treeData2RcTreeData(rawTreeData) }, [treeData, children]) // rc-tree 的受控 props 会判断 name in props,传 {selectedKeys: undefined} 也会被认为是设置了的.. const selectedKeysProps = useMemo( () => (selectedKey == null ? undefined : { selectedKeys: [selectedKey] }), [selectedKey] ) const handleSelect = useCallback((v: Key[]) => onSelect?.(v[0]), [onSelect]) // rc-tree 的 checkStrictly 模式暂时不考虑支持,onCheck 参数类型确定是 Key[] const handleCheck = useCallback(v => onCheckedKeysChange?.(v as Key[]), [onCheckedKeysChange]) const nodeClickable = selectable || checkable || !!expandAction return ( ) } function defaultSwitcherIcon({ isLeaf, expanded }: NodeEvent) { if (isLeaf) { return null } return expanded ? : }