This commit is contained in:
2026-05-25 17:08:18 +08:00
parent df501f6151
commit f1259b71b5
9178 changed files with 1626125 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
import * as React from 'react';
import type RcTree from '@rc-component/tree';
import type { BasicDataNode } from '@rc-component/tree';
import type { DataNode, Key } from '@rc-component/tree/lib/interface';
import type { TreeProps } from './Tree';
export type ExpandAction = false | 'click' | 'doubleClick';
export interface DirectoryTreeProps<T extends BasicDataNode = DataNode> extends TreeProps<T> {
expandAction?: ExpandAction;
}
type DirectoryTreeCompoundedComponent = (<T extends BasicDataNode | DataNode = DataNode>(props: React.PropsWithChildren<DirectoryTreeProps<T>> & React.RefAttributes<RcTree>) => React.ReactElement) & Pick<React.FC, 'displayName'>;
export interface DirectoryTreeState {
expandedKeys?: Key[];
selectedKeys?: Key[];
}
declare const DirectoryTree: DirectoryTreeCompoundedComponent;
export default DirectoryTree;
+168
View File
@@ -0,0 +1,168 @@
"use strict";
"use client";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var React = _interopRequireWildcard(require("react"));
var _FileOutlined = _interopRequireDefault(require("@ant-design/icons/FileOutlined"));
var _FolderOpenOutlined = _interopRequireDefault(require("@ant-design/icons/FolderOpenOutlined"));
var _FolderOutlined = _interopRequireDefault(require("@ant-design/icons/FolderOutlined"));
var _util = require("@rc-component/tree/lib/util");
var _treeUtil = require("@rc-component/tree/lib/utils/treeUtil");
var _clsx = require("clsx");
var _configProvider = require("../config-provider");
var _Tree = _interopRequireDefault(require("./Tree"));
var _dictUtil = require("./utils/dictUtil");
function getIcon(props) {
const {
isLeaf,
expanded
} = props;
if (isLeaf) {
return /*#__PURE__*/React.createElement(_FileOutlined.default, null);
}
return expanded ? /*#__PURE__*/React.createElement(_FolderOpenOutlined.default, null) : /*#__PURE__*/React.createElement(_FolderOutlined.default, null);
}
function getTreeData({
treeData,
children
}) {
return treeData || (0, _treeUtil.convertTreeToData)(children);
}
const DirectoryTree = /*#__PURE__*/React.forwardRef((oriProps, ref) => {
const {
defaultExpandAll,
defaultExpandParent,
defaultExpandedKeys,
...props
} = oriProps;
// Shift click usage
const lastSelectedKeyRef = React.useRef(null);
const cachedSelectedKeysRef = React.useRef(null);
const getInitExpandedKeys = () => {
const {
keyEntities
} = (0, _treeUtil.convertDataToEntities)(getTreeData(props), {
fieldNames: props.fieldNames
});
let initExpandedKeys;
const mergedExpandedKeys = props.expandedKeys || defaultExpandedKeys || [];
// Expanded keys
if (defaultExpandAll) {
initExpandedKeys = Object.keys(keyEntities);
} else if (defaultExpandParent) {
initExpandedKeys = (0, _util.conductExpandParent)(mergedExpandedKeys, keyEntities);
} else {
initExpandedKeys = mergedExpandedKeys;
}
return initExpandedKeys;
};
const [selectedKeys, setSelectedKeys] = React.useState(props.selectedKeys || props.defaultSelectedKeys || []);
const [expandedKeys, setExpandedKeys] = React.useState(() => getInitExpandedKeys());
React.useEffect(() => {
if ('selectedKeys' in props) {
setSelectedKeys(props.selectedKeys);
}
}, [props.selectedKeys]);
React.useEffect(() => {
if ('expandedKeys' in props) {
setExpandedKeys(props.expandedKeys);
}
}, [props.expandedKeys]);
const onExpand = (keys, info) => {
if (!('expandedKeys' in props)) {
setExpandedKeys(keys);
}
// Call origin function
return props.onExpand?.(keys, info);
};
const onSelect = (keys, event) => {
const {
multiple,
fieldNames
} = props;
const {
node,
nativeEvent
} = event;
const {
key = ''
} = node;
const treeData = getTreeData(props);
// We need wrap this event since some value is not same
const newEvent = {
...event,
selected: true // Directory selected always true
};
// Windows / Mac single pick
const ctrlPick = nativeEvent?.ctrlKey || nativeEvent?.metaKey;
const shiftPick = nativeEvent?.shiftKey;
// Generate new selected keys
let newSelectedKeys;
if (multiple && ctrlPick) {
// Control click
newSelectedKeys = keys;
lastSelectedKeyRef.current = key;
cachedSelectedKeysRef.current = newSelectedKeys;
newEvent.selectedNodes = (0, _dictUtil.convertDirectoryKeysToNodes)(treeData, newSelectedKeys, fieldNames);
} else if (multiple && shiftPick) {
// Shift click
newSelectedKeys = Array.from(new Set([].concat((0, _toConsumableArray2.default)(cachedSelectedKeysRef.current || []), (0, _toConsumableArray2.default)((0, _dictUtil.calcRangeKeys)({
treeData,
expandedKeys,
startKey: key,
endKey: lastSelectedKeyRef.current,
fieldNames
})))));
newEvent.selectedNodes = (0, _dictUtil.convertDirectoryKeysToNodes)(treeData, newSelectedKeys, fieldNames);
} else {
// Single click
newSelectedKeys = [key];
lastSelectedKeyRef.current = key;
cachedSelectedKeysRef.current = newSelectedKeys;
newEvent.selectedNodes = (0, _dictUtil.convertDirectoryKeysToNodes)(treeData, newSelectedKeys, fieldNames);
}
props.onSelect?.(newSelectedKeys, newEvent);
if (!('selectedKeys' in props)) {
setSelectedKeys(newSelectedKeys);
}
};
const {
getPrefixCls,
direction
} = React.useContext(_configProvider.ConfigContext);
const {
prefixCls: customizePrefixCls,
className,
showIcon = true,
expandAction = 'click',
...restProps
} = props;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
const connectClassName = (0, _clsx.clsx)(`${prefixCls}-directory`, {
[`${prefixCls}-directory-rtl`]: direction === 'rtl'
}, className);
return /*#__PURE__*/React.createElement(_Tree.default, {
icon: getIcon,
ref: ref,
blockNode: true,
...restProps,
showIcon: showIcon,
expandAction: expandAction,
prefixCls: prefixCls,
className: connectClassName,
expandedKeys: expandedKeys,
selectedKeys: selectedKeys,
onSelect: onSelect,
onExpand: onExpand
});
});
if (process.env.NODE_ENV !== 'production') {
DirectoryTree.displayName = 'DirectoryTree';
}
var _default = exports.default = DirectoryTree;
+154
View File
@@ -0,0 +1,154 @@
import type { Component } from 'react';
import React from 'react';
import type { BasicDataNode, TreeProps as RcTreeProps } from '@rc-component/tree';
import RcTree from '@rc-component/tree';
import type { DataNode, Key } from '@rc-component/tree/lib/interface';
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
export type SwitcherIcon = React.ReactNode | ((props: AntTreeNodeProps) => React.ReactNode);
export type TreeLeafIcon = React.ReactNode | ((props: AntTreeNodeProps) => React.ReactNode);
type TreeIcon = React.ReactNode | ((props: AntdTreeNodeAttribute) => React.ReactNode);
export interface AntdTreeNodeAttribute {
eventKey: string;
prefixCls: string;
className: string;
expanded: boolean;
selected: boolean;
checked: boolean;
halfChecked: boolean;
children: React.ReactNode;
title: React.ReactNode;
pos: string;
dragOver: boolean;
dragOverGapTop: boolean;
dragOverGapBottom: boolean;
isLeaf: boolean;
selectable: boolean;
disabled: boolean;
disableCheckbox: boolean;
}
export interface AntTreeNodeProps {
className?: string;
checkable?: boolean;
disabled?: boolean;
disableCheckbox?: boolean;
title?: React.ReactNode | ((data: DataNode) => React.ReactNode);
key?: Key;
eventKey?: Key;
isLeaf?: boolean;
checked?: boolean;
expanded?: boolean;
loading?: boolean;
selected?: boolean;
selectable?: boolean;
icon?: TreeIcon;
children?: React.ReactNode;
[customProp: string]: any;
}
export interface AntTreeNode extends Component<AntTreeNodeProps> {
}
export interface AntTreeNodeBaseEvent {
node: AntTreeNode;
nativeEvent: MouseEvent;
}
export interface AntTreeNodeCheckedEvent extends AntTreeNodeBaseEvent {
event: 'check';
checked?: boolean;
checkedNodes?: AntTreeNode[];
}
export interface AntTreeNodeSelectedEvent extends AntTreeNodeBaseEvent {
event: 'select';
selected?: boolean;
selectedNodes?: DataNode[];
}
export interface AntTreeNodeExpandedEvent extends AntTreeNodeBaseEvent {
expanded?: boolean;
}
export interface AntTreeNodeMouseEvent {
node: AntTreeNode;
event: React.DragEvent<HTMLElement>;
}
export interface AntTreeNodeDragEnterEvent extends AntTreeNodeMouseEvent {
expandedKeys: Key[];
}
export interface AntTreeNodeDropEvent {
node: AntTreeNode;
dragNode: AntTreeNode;
dragNodesKeys: Key[];
dropPosition: number;
dropToGap?: boolean;
event: React.MouseEvent<HTMLElement>;
}
export type TreeNodeNormal = DataNode;
type DraggableFn = (node: DataNode) => boolean;
interface DraggableConfig {
icon?: React.ReactNode;
nodeDraggable?: DraggableFn;
}
export type TreeSemanticName = keyof TreeSemanticClassNames & keyof TreeSemanticStyles;
export type TreeSemanticClassNames = {
root?: string;
item?: string;
itemIcon?: string;
itemTitle?: string;
};
export type TreeSemanticStyles = {
root?: React.CSSProperties;
item?: React.CSSProperties;
itemIcon?: React.CSSProperties;
itemTitle?: React.CSSProperties;
};
export type TreeClassNamesType = SemanticClassNamesType<TreeProps, TreeSemanticClassNames>;
export type TreeStylesType = SemanticStylesType<TreeProps, TreeSemanticStyles>;
export interface TreeProps<T extends BasicDataNode = DataNode> extends Omit<RcTreeProps<T>, 'prefixCls' | 'showLine' | 'direction' | 'draggable' | 'icon' | 'switcherIcon' | 'classNames' | 'styles'> {
showLine?: boolean | {
showLeafIcon: boolean | TreeLeafIcon;
};
className?: string;
classNames?: TreeClassNamesType;
styles?: TreeStylesType;
/** Whether to support multiple selection */
multiple?: boolean;
/** Whether to automatically expand the parent node */
autoExpandParent?: boolean;
/** Node selection in Checkable state is fully controlled (the selected state of parent and child nodes is no longer associated) */
checkStrictly?: boolean;
/** Whether to support selection */
checkable?: boolean;
/** whether to disable the tree */
disabled?: boolean;
/** Expand all tree nodes by default */
defaultExpandAll?: boolean;
/** Expand the corresponding tree node by default */
defaultExpandParent?: boolean;
/** Expand the specified tree node by default */
defaultExpandedKeys?: Key[];
/** (Controlled) Expand the specified tree node */
expandedKeys?: Key[];
/** (Controlled) Tree node with checked checkbox */
checkedKeys?: Key[] | {
checked: Key[];
halfChecked: Key[];
};
/** Tree node with checkbox checked by default */
defaultCheckedKeys?: Key[];
/** (Controlled) Set the selected tree node */
selectedKeys?: Key[];
/** Tree node selected by default */
defaultSelectedKeys?: Key[];
selectable?: boolean;
/** Click on the tree node to trigger */
filterAntTreeNode?: (node: AntTreeNode) => boolean;
loadedKeys?: Key[];
/** Set the node to be draggable (IE>8) */
draggable?: DraggableFn | boolean | DraggableConfig;
style?: React.CSSProperties;
showIcon?: boolean;
icon?: TreeIcon;
switcherIcon?: SwitcherIcon;
switcherLoadingIcon?: React.ReactNode;
prefixCls?: string;
children?: React.ReactNode;
blockNode?: boolean;
}
declare const Tree: React.ForwardRefExoticComponent<TreeProps<DataNode> & React.RefAttributes<RcTree<DataNode>>>;
export default Tree;
+148
View File
@@ -0,0 +1,148 @@
"use strict";
"use client";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _HolderOutlined = _interopRequireDefault(require("@ant-design/icons/HolderOutlined"));
var _tree = _interopRequireDefault(require("@rc-component/tree"));
var _clsx = require("clsx");
var _hooks = require("../_util/hooks");
var _motion = _interopRequireDefault(require("../_util/motion"));
var _configProvider = require("../config-provider");
var _context = require("../config-provider/context");
var _DisabledContext = _interopRequireDefault(require("../config-provider/DisabledContext"));
var _internal = require("../theme/internal");
var _style = _interopRequireDefault(require("./style"));
var _dropIndicator = _interopRequireDefault(require("./utils/dropIndicator"));
var _iconUtil = _interopRequireDefault(require("./utils/iconUtil"));
const Tree = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
const {
getPrefixCls,
direction,
className: contextClassName,
style: contextStyle,
classNames: contextClassNames,
styles: contextStyles
} = (0, _context.useComponentConfig)('tree');
const {
virtual
} = _react.default.useContext(_configProvider.ConfigContext);
const {
prefixCls: customizePrefixCls,
className,
showIcon = false,
showLine,
switcherIcon,
switcherLoadingIcon,
blockNode = false,
children,
checkable = false,
selectable = true,
draggable,
disabled,
motion: customMotion,
style,
rootClassName,
classNames,
styles,
icon
} = props;
const contextDisabled = _react.default.useContext(_DisabledContext.default);
const mergedDisabled = disabled ?? contextDisabled;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
const rootPrefixCls = getPrefixCls();
const motion = customMotion ?? {
...(0, _motion.default)(rootPrefixCls),
motionAppear: false
};
// =========== Merged Props for Semantic ==========
const mergedProps = {
...props,
showIcon,
blockNode,
checkable,
selectable,
disabled: mergedDisabled,
motion
};
const [mergedClassNames, mergedStyles] = (0, _hooks.useMergeSemantic)([contextClassNames, classNames], [contextStyles, styles], {
props: mergedProps
});
const newProps = {
...mergedProps,
showLine: Boolean(showLine),
icon: icon,
dropIndicatorRender: _dropIndicator.default
};
const [hashId, cssVarCls] = (0, _style.default)(prefixCls);
const [, token] = (0, _internal.useToken)();
const itemHeight = token.paddingXS / 2 + (token.Tree?.titleHeight || token.controlHeightSM);
const draggableConfig = _react.default.useMemo(() => {
if (!draggable) {
return false;
}
let mergedDraggable = {};
switch (typeof draggable) {
case 'function':
mergedDraggable.nodeDraggable = draggable;
break;
case 'object':
mergedDraggable = {
...draggable
};
break;
default:
break;
// Do nothing
}
if (mergedDraggable.icon !== false) {
mergedDraggable.icon = mergedDraggable.icon || /*#__PURE__*/_react.default.createElement(_HolderOutlined.default, null);
}
return mergedDraggable;
}, [draggable]);
const renderSwitcherIcon = nodeProps => (/*#__PURE__*/_react.default.createElement(_iconUtil.default, {
prefixCls: prefixCls,
switcherIcon: switcherIcon,
switcherLoadingIcon: switcherLoadingIcon,
treeNodeProps: nodeProps,
showLine: showLine
}));
return /*#__PURE__*/_react.default.createElement(_tree.default, {
itemHeight: itemHeight,
ref: ref,
virtual: virtual,
...newProps,
// newProps may contain style so declare style below it
prefixCls: prefixCls,
className: (0, _clsx.clsx)({
[`${prefixCls}-icon-hide`]: !showIcon,
[`${prefixCls}-block-node`]: blockNode,
[`${prefixCls}-unselectable`]: !selectable,
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-disabled`]: mergedDisabled
}, contextClassName, className, hashId, cssVarCls),
style: {
...contextStyle,
...style
},
rootClassName: (0, _clsx.clsx)(mergedClassNames.root, rootClassName),
rootStyle: mergedStyles.root,
classNames: mergedClassNames,
styles: mergedStyles,
direction: direction,
checkable: checkable ? /*#__PURE__*/_react.default.createElement("span", {
className: `${prefixCls}-checkbox-inner`
}) : checkable,
selectable: selectable,
switcherIcon: renderSwitcherIcon,
draggable: draggableConfig
}, children);
});
if (process.env.NODE_ENV !== 'production') {
Tree.displayName = 'Tree';
}
var _default = exports.default = Tree;
+16
View File
@@ -0,0 +1,16 @@
import type RcTree from '@rc-component/tree';
import type { BasicDataNode } from '@rc-component/tree';
import { TreeNode } from '@rc-component/tree';
import type { DataNode } from '@rc-component/tree/lib/interface';
import DirectoryTree from './DirectoryTree';
import type { TreeProps } from './Tree';
export type { ExpandAction as DirectoryTreeExpandAction, DirectoryTreeProps, } from './DirectoryTree';
export type { AntdTreeNodeAttribute, AntTreeNode, AntTreeNodeCheckedEvent, AntTreeNodeExpandedEvent, AntTreeNodeMouseEvent, AntTreeNodeProps, AntTreeNodeSelectedEvent, TreeProps, TreeSemanticClassNames, TreeSemanticName, TreeSemanticStyles, } from './Tree';
export type { EventDataNode } from '@rc-component/tree/lib/interface';
export type { BasicDataNode, DataNode };
type CompoundedComponent = (<T extends BasicDataNode | DataNode = DataNode>(props: React.PropsWithChildren<TreeProps<T>> & React.RefAttributes<RcTree>) => React.ReactElement) & {
TreeNode: typeof TreeNode;
DirectoryTree: typeof DirectoryTree;
};
declare const Tree: CompoundedComponent;
export default Tree;
+15
View File
@@ -0,0 +1,15 @@
"use strict";
"use client";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _tree = require("@rc-component/tree");
var _DirectoryTree = _interopRequireDefault(require("./DirectoryTree"));
var _Tree = _interopRequireDefault(require("./Tree"));
const Tree = _Tree.default;
Tree.DirectoryTree = _DirectoryTree.default;
Tree.TreeNode = _tree.TreeNode;
var _default = exports.default = Tree;
+3
View File
@@ -0,0 +1,3 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { TreeToken } from '.';
export declare const genDirectoryStyle: ({ treeCls, treeNodeCls, directoryNodeSelectedBg, directoryNodeSelectedColor, motionDurationMid, borderRadius, controlItemBgHover, }: TreeToken) => CSSObject;
+66
View File
@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.genDirectoryStyle = void 0;
// ============================ Directory =============================
const genDirectoryStyle = ({
treeCls,
treeNodeCls,
directoryNodeSelectedBg,
directoryNodeSelectedColor,
motionDurationMid,
borderRadius,
controlItemBgHover
}) => ({
[`${treeCls}${treeCls}-directory ${treeNodeCls}`]: {
// >>> Title
[`${treeCls}-node-content-wrapper`]: {
position: 'static',
[`&:has(${treeCls}-drop-indicator)`]: {
position: 'relative'
},
[`> *:not(${treeCls}-drop-indicator)`]: {
position: 'relative'
},
'&:hover': {
background: 'transparent'
},
// Expand interactive area to whole line
'&:before': {
position: 'absolute',
inset: 0,
transition: `background-color ${motionDurationMid}`,
content: '""',
borderRadius
},
'&:hover:before': {
background: controlItemBgHover
}
},
[`${treeCls}-switcher, ${treeCls}-checkbox, ${treeCls}-draggable-icon`]: {
zIndex: 1
},
// ============= Selected =============
'&-selected': {
background: directoryNodeSelectedBg,
borderRadius,
[`${treeCls}-switcher, ${treeCls}-draggable-icon`]: {
color: directoryNodeSelectedColor
},
// >>> Title
[`${treeCls}-node-content-wrapper`]: {
color: directoryNodeSelectedColor,
background: 'transparent',
'&, &:hover': {
color: directoryNodeSelectedColor
},
'&:before, &:hover:before': {
background: directoryNodeSelectedBg
}
}
}
}
});
exports.genDirectoryStyle = genDirectoryStyle;
+68
View File
@@ -0,0 +1,68 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import type { AliasToken, CSSUtil, FullToken, GetDefaultToken } from '../../theme/internal';
export interface TreeSharedToken {
/**
* @desc 节点标题高度
* @descEN Node title height
*/
titleHeight: number;
/**
* @desc 展开按钮宽度
* @descEN Switcher width of tree
*/
switcherSize?: number;
/**
* @desc 缩进宽度
* @descEN Indent width of tree
*/
indentSize?: number;
/**
* @desc 节点悬浮态背景色
* @descEN Background color of hovered node
*/
nodeHoverBg: string;
/**
* @desc 节点悬浮态态文字颜色
* @descEN Text color of hovered node
*/
nodeHoverColor: string;
/**
* @desc 节点选中态背景色
* @descEN Background color of selected node
*/
nodeSelectedBg: string;
/**
* @desc 节点选中态文字颜色
* @descEN Text color of selected node
*/
nodeSelectedColor: string;
}
export interface ComponentToken extends TreeSharedToken {
/**
* @desc 目录树节点选中文字颜色
* @descEN Text color of selected directory node
*/
directoryNodeSelectedColor: string;
/**
* @desc 目录树节点选中背景色
* @descEN Background color of selected directory node
*/
directoryNodeSelectedBg: string;
}
export type TreeToken = FullToken<'Tree'> & {
treeCls: string;
treeNodeCls: string;
treeNodePadding: number | string;
};
export declare const genBaseStyle: (prefixCls: string, token: TreeToken) => CSSObject;
export declare const genTreeStyle: (prefixCls: string, token: AliasToken & TreeSharedToken & CSSUtil,
/**
* @descCN 是否启用目录树样式
* @descEN Whether to enable directory style
* @default true
*/
enableDirectory?: boolean) => CSSInterpolation;
export declare const initComponentToken: (token: AliasToken) => TreeSharedToken;
export declare const prepareComponentToken: GetDefaultToken<'Tree'>;
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
export default _default;
+405
View File
@@ -0,0 +1,405 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.prepareComponentToken = exports.initComponentToken = exports.genTreeStyle = exports.genBaseStyle = exports.default = void 0;
var _cssinjs = require("@ant-design/cssinjs");
var _style = require("../../checkbox/style");
var _style2 = require("../../style");
var _motion = require("../../style/motion");
var _internal = require("../../theme/internal");
var _directory = require("./directory");
// ============================ Keyframes =============================
const treeNodeFX = new _cssinjs.Keyframes('ant-tree-node-fx-do-not-use', {
'0%': {
opacity: 0
},
'100%': {
opacity: 1
}
});
// ============================== Switch ==============================
const getSwitchStyle = (prefixCls, token) => ({
[`.${prefixCls}-switcher-icon`]: {
display: 'inline-block',
fontSize: 10,
verticalAlign: 'baseline',
svg: {
transition: `transform ${token.motionDurationSlow}`
}
}
});
// =============================== Drop ===============================
const getDropIndicatorStyle = (prefixCls, token) => ({
[`.${prefixCls}-drop-indicator`]: {
position: 'absolute',
// it should displayed over the following node
zIndex: 1,
height: 2,
backgroundColor: token.colorPrimary,
borderRadius: 1,
pointerEvents: 'none',
'&:after': {
position: 'absolute',
top: -3,
insetInlineStart: -6,
width: 8,
height: 8,
backgroundColor: 'transparent',
border: `${(0, _cssinjs.unit)(token.lineWidthBold)} solid ${token.colorPrimary}`,
borderRadius: '50%',
content: '""'
}
}
});
const genBaseStyle = (prefixCls, token) => {
const {
treeCls,
treeNodeCls,
treeNodePadding,
titleHeight,
indentSize,
switcherSize,
motionDurationMid,
nodeSelectedBg,
nodeHoverBg,
colorTextQuaternary,
controlItemBgActiveDisabled
} = token;
return {
[treeCls]: {
...(0, _style2.resetComponent)(token),
// fix https://github.com/ant-design/ant-design/issues/50316
['--rc-virtual-list-scrollbar-bg']: token.colorSplit,
background: token.colorBgContainer,
borderRadius: token.borderRadius,
transition: `background-color ${token.motionDurationSlow}`,
'&-rtl': {
direction: 'rtl'
},
[`&${treeCls}-rtl ${treeCls}-switcher_close ${treeCls}-switcher-icon svg`]: {
transform: 'rotate(90deg)'
},
// =================== Virtual List ===================
[`${treeCls}-list`]: {
'&:focus-visible': {
outline: 'none',
[`${treeNodeCls}-active ${treeCls}-node-content-wrapper`]: {
...(0, _style2.genFocusOutline)(token)
}
}
},
[`${treeCls}-list-holder-inner`]: {
alignItems: 'flex-start'
},
[`&${treeCls}-block-node`]: {
[`${treeCls}-list-holder-inner`]: {
alignItems: 'stretch',
// >>> Title
[`${treeCls}-node-content-wrapper`]: {
flex: 'auto'
},
// >>> Drag
[`${treeNodeCls}.dragging:after`]: {
position: 'absolute',
inset: 0,
border: `1px solid ${token.colorPrimary}`,
opacity: 0,
animationName: treeNodeFX,
animationDuration: token.motionDurationSlow,
animationPlayState: 'running',
animationFillMode: 'forwards',
content: '""',
pointerEvents: 'none',
borderRadius: token.borderRadius
}
}
},
// ===================== TreeNode =====================
[treeNodeCls]: {
display: 'flex',
alignItems: 'flex-start',
marginBottom: treeNodePadding,
lineHeight: (0, _cssinjs.unit)(titleHeight),
position: 'relative',
// 非常重要,避免 drop-indicator 在拖拽过程中闪烁
'&:before': {
content: '""',
position: 'absolute',
zIndex: 1,
insetInlineStart: 0,
width: '100%',
top: '100%',
height: treeNodePadding
},
// Disabled
[`&-disabled ${treeCls}-node-content-wrapper`]: {
color: token.colorTextDisabled,
cursor: 'not-allowed',
'&:hover': {
background: 'transparent'
}
},
[`${treeCls}-checkbox-disabled + ${treeCls}-node-selected,&${treeNodeCls}-disabled${treeNodeCls}-selected ${treeCls}-node-content-wrapper`]: {
backgroundColor: controlItemBgActiveDisabled
},
// we can not set pointer-events to none for checkbox in tree
// ref: https://github.com/ant-design/ant-design/issues/39822#issuecomment-2605234058
[`${treeCls}-checkbox-disabled`]: {
pointerEvents: 'unset'
},
// not disable
[`&:not(${treeNodeCls}-disabled)`]: {
// >>> Title
[`${treeCls}-node-content-wrapper`]: {
'&:hover': {
color: token.nodeHoverColor
}
}
},
[`&-active ${treeCls}-node-content-wrapper`]: {
background: token.controlItemBgHover
},
[`&:not(${treeNodeCls}-disabled).filter-node ${treeCls}-title`]: {
color: token.colorPrimary,
fontWeight: token.fontWeightStrong
},
'&-draggable': {
cursor: 'grab',
[`${treeCls}-draggable-icon`]: {
// https://github.com/ant-design/ant-design/issues/41915
flexShrink: 0,
width: switcherSize,
textAlign: 'center',
visibility: 'visible',
color: colorTextQuaternary
},
[`&${treeNodeCls}-disabled ${treeCls}-draggable-icon`]: {
visibility: 'hidden'
}
}
},
// >>> Indent
[`${treeCls}-indent`]: {
alignSelf: 'stretch',
whiteSpace: 'nowrap',
userSelect: 'none',
'&-unit': {
display: 'inline-block',
width: indentSize
}
},
// >>> Drag Handler
[`${treeCls}-draggable-icon`]: {
visibility: 'hidden'
},
// Switcher / Checkbox
[`${treeCls}-switcher, ${treeCls}-checkbox`]: {
marginInlineEnd: token.calc(token.calc(switcherSize).sub(token.controlInteractiveSize)).div(2).equal()
},
// >>> Checkbox
// https://github.com/ant-design/ant-design/issues/56957
[`${treeCls}-checkbox`]: {
flexShrink: 0,
// When the title spans multiple lines, the checkbox aligns vertically centered with other elements
// However, the switcher aligns to flex-start, causing a vertical alignment discrepancy in the parent node
// Currently, the checkbox uses start alignment, but this causes it to stick to the top, resulting in a visually higher position
// By setting the switcher's lineHeight to titleHeight, the required margin-block-start distance can be calculated to correct the alignment
alignSelf: 'flex-start',
marginBlockStart: token.calc(token.calc(titleHeight).sub(token.controlInteractiveSize)).div(2).equal()
},
// >>> Switcher
[`${treeCls}-switcher`]: {
...getSwitchStyle(prefixCls, token),
position: 'relative',
flex: 'none',
alignSelf: 'stretch',
width: switcherSize,
textAlign: 'center',
cursor: 'pointer',
userSelect: 'none',
transition: `all ${token.motionDurationSlow}`,
'&-noop': {
cursor: 'unset'
},
'&:before': {
pointerEvents: 'none',
content: '""',
width: switcherSize,
height: titleHeight,
position: 'absolute',
left: {
_skip_check_: true,
value: 0
},
top: 0,
borderRadius: token.borderRadius,
transition: `all ${token.motionDurationSlow}`
},
[`&:not(${treeCls}-switcher-noop):hover:before`]: {
backgroundColor: token.colorBgTextHover
},
[`&_close ${treeCls}-switcher-icon svg`]: {
transform: 'rotate(-90deg)'
},
'&-loading-icon': {
color: token.colorPrimary
},
'&-leaf-line': {
position: 'relative',
zIndex: 1,
display: 'inline-block',
width: '100%',
height: '100%',
// https://github.com/ant-design/ant-design/issues/31884
'&:before': {
position: 'absolute',
top: 0,
insetInlineEnd: token.calc(switcherSize).div(2).equal(),
bottom: token.calc(treeNodePadding).mul(-1).equal(),
marginInlineStart: -1,
borderInlineEnd: `1px solid ${token.colorBorder}`,
content: '""'
},
'&:after': {
position: 'absolute',
width: token.calc(token.calc(switcherSize).div(2).equal()).mul(0.8).equal(),
height: token.calc(titleHeight).div(2).equal(),
borderBottom: `1px solid ${token.colorBorder}`,
content: '""'
}
}
},
// >>> Title
// add `${treeCls}-checkbox + span` to cover checkbox `${checkboxCls} + span`
[`${treeCls}-node-content-wrapper`]: {
position: 'relative',
minHeight: titleHeight,
paddingBlock: 0,
paddingInline: token.paddingXS,
background: 'transparent',
borderRadius: token.borderRadius,
cursor: 'pointer',
transition: [`all ${motionDurationMid}`, 'border 0s', 'line-height 0s', 'box-shadow 0s'].join(', '),
...getDropIndicatorStyle(prefixCls, token),
'&:hover': {
backgroundColor: nodeHoverBg
},
[`&${treeCls}-node-selected`]: {
color: token.nodeSelectedColor,
backgroundColor: nodeSelectedBg
},
// Icon
[`${treeCls}-iconEle`]: {
display: 'inline-block',
width: switcherSize,
height: titleHeight,
textAlign: 'center',
verticalAlign: 'top',
'&:empty': {
display: 'none'
}
}
},
// https://github.com/ant-design/ant-design/issues/28217
[`${treeCls}-unselectable ${treeCls}-node-content-wrapper:hover`]: {
backgroundColor: 'transparent'
},
[`${treeNodeCls}.drop-container > [draggable]`]: {
boxShadow: `0 0 0 2px ${token.colorPrimary}`
},
// ==================== Show Line =====================
'&-show-line': {
// ================ Indent lines ================
[`${treeCls}-indent-unit`]: {
position: 'relative',
height: '100%',
'&:before': {
position: 'absolute',
top: 0,
insetInlineEnd: token.calc(switcherSize).div(2).equal(),
bottom: token.calc(treeNodePadding).mul(-1).equal(),
borderInlineEnd: `1px solid ${token.colorBorder}`,
content: '""'
},
'&-end:before': {
display: 'none'
}
},
// ============== Cover Background ==============
[`${treeCls}-switcher`]: {
background: 'transparent',
'&-line-icon': {
// https://github.com/ant-design/ant-design/issues/32813
verticalAlign: '-0.15em'
}
}
},
[`${treeNodeCls}-leaf-last ${treeCls}-switcher-leaf-line:before`]: {
top: 'auto !important',
bottom: 'auto !important',
height: `${(0, _cssinjs.unit)(token.calc(titleHeight).div(2).equal())} !important`
}
}
};
};
// ============================== Merged ==============================
exports.genBaseStyle = genBaseStyle;
const genTreeStyle = (prefixCls, token,
/**
* @descCN 是否启用目录树样式
* @descEN Whether to enable directory style
* @default true
*/
enableDirectory = true) => {
const treeCls = `.${prefixCls}`;
const treeNodeCls = `${treeCls}-treenode`;
const treeNodePadding = token.calc(token.paddingXS).div(2).equal();
const treeToken = (0, _internal.mergeToken)(token, {
treeCls,
treeNodeCls,
treeNodePadding
});
return [
// Basic
genBaseStyle(prefixCls, treeToken),
// Directory
enableDirectory && (0, _directory.genDirectoryStyle)(treeToken)].filter(Boolean);
};
exports.genTreeStyle = genTreeStyle;
const initComponentToken = token => {
const {
controlHeightSM,
controlItemBgHover,
controlItemBgActive
} = token;
const titleHeight = controlHeightSM;
return {
titleHeight,
switcherSize: titleHeight,
indentSize: titleHeight,
nodeHoverBg: controlItemBgHover,
nodeHoverColor: token.colorText,
nodeSelectedBg: controlItemBgActive,
nodeSelectedColor: token.colorText
};
};
exports.initComponentToken = initComponentToken;
const prepareComponentToken = token => {
const {
colorTextLightSolid,
colorPrimary
} = token;
return {
...initComponentToken(token),
directoryNodeSelectedColor: colorTextLightSolid,
directoryNodeSelectedBg: colorPrimary
};
};
exports.prepareComponentToken = prepareComponentToken;
var _default = exports.default = (0, _internal.genStyleHooks)('Tree', (token, {
prefixCls
}) => [{
[token.componentCls]: (0, _style.getStyle)(`${prefixCls}-checkbox`, token)
}, genTreeStyle(prefixCls, token), (0, _motion.genCollapseMotion)(token)], prepareComponentToken);
+13
View File
@@ -0,0 +1,13 @@
import type { DataNode, Key } from '@rc-component/tree/lib/interface';
import type { TreeProps } from '../Tree';
type FieldNames = TreeProps['fieldNames'];
/** 计算选中范围,只考虑expanded情况以优化性能 */
export declare function calcRangeKeys({ treeData, expandedKeys, startKey, endKey, fieldNames, }: {
treeData: DataNode[];
expandedKeys: Key[];
startKey?: Key;
endKey?: Key;
fieldNames?: FieldNames;
}): Key[];
export declare function convertDirectoryKeysToNodes(treeData: DataNode[], keys: Key[], fieldNames?: FieldNames): DataNode[];
export {};
+80
View File
@@ -0,0 +1,80 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.calcRangeKeys = calcRangeKeys;
exports.convertDirectoryKeysToNodes = convertDirectoryKeysToNodes;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _treeUtil = require("@rc-component/tree/lib/utils/treeUtil");
const RECORD_NONE = 0;
const RECORD_START = 1;
const RECORD_END = 2;
function traverseNodesKey(treeData, callback, fieldNames) {
const {
key: fieldKey,
children: fieldChildren
} = fieldNames;
function processNode(dataNode) {
const key = dataNode[fieldKey];
const children = dataNode[fieldChildren];
if (callback(key, dataNode) !== false) {
traverseNodesKey(children || [], callback, fieldNames);
}
}
treeData.forEach(processNode);
}
/** 计算选中范围,只考虑expanded情况以优化性能 */
function calcRangeKeys({
treeData,
expandedKeys,
startKey,
endKey,
fieldNames
}) {
const keys = [];
let record = RECORD_NONE;
if (startKey && startKey === endKey) {
return [startKey];
}
if (!startKey || !endKey) {
return [];
}
function matchKey(key) {
return key === startKey || key === endKey;
}
traverseNodesKey(treeData, key => {
if (record === RECORD_END) {
return false;
}
if (matchKey(key)) {
// Match test
keys.push(key);
if (record === RECORD_NONE) {
record = RECORD_START;
} else if (record === RECORD_START) {
record = RECORD_END;
return false;
}
} else if (record === RECORD_START) {
// Append selection
keys.push(key);
}
return expandedKeys.includes(key);
}, (0, _treeUtil.fillFieldNames)(fieldNames));
return keys;
}
function convertDirectoryKeysToNodes(treeData, keys, fieldNames) {
const restKeys = (0, _toConsumableArray2.default)(keys);
const nodes = [];
traverseNodesKey(treeData, (key, node) => {
const index = restKeys.indexOf(key);
if (index !== -1) {
nodes.push(node);
restKeys.splice(index, 1);
}
return !!restKeys.length;
}, (0, _treeUtil.fillFieldNames)(fieldNames));
return nodes;
}
+12
View File
@@ -0,0 +1,12 @@
import React from 'react';
import type { DirectionType } from '../../config-provider';
export declare const offset = 4;
interface DropIndicatorProps {
dropPosition: -1 | 0 | 1;
dropLevelOffset: number;
indent: number;
prefixCls: string;
direction: DirectionType;
}
declare const dropIndicatorRender: (props: DropIndicatorProps) => React.JSX.Element;
export default dropIndicatorRender;
+43
View File
@@ -0,0 +1,43 @@
"use strict";
"use client";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.offset = exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
const offset = exports.offset = 4;
const dropIndicatorRender = props => {
const {
dropPosition,
dropLevelOffset,
prefixCls,
indent,
direction = 'ltr'
} = props;
const startPosition = direction === 'ltr' ? 'left' : 'right';
const endPosition = direction === 'ltr' ? 'right' : 'left';
const style = {
[startPosition]: -dropLevelOffset * indent + offset,
[endPosition]: 0
};
switch (dropPosition) {
case -1:
style.top = -3;
break;
case 1:
style.bottom = -3;
break;
default:
// dropPosition === 0
style.bottom = -3;
style[startPosition] = indent + offset;
break;
}
return /*#__PURE__*/_react.default.createElement("div", {
style: style,
className: `${prefixCls}-drop-indicator`
});
};
var _default = exports.default = dropIndicatorRender;
+13
View File
@@ -0,0 +1,13 @@
import * as React from 'react';
import type { AntTreeNodeProps, SwitcherIcon, TreeLeafIcon } from '../Tree';
interface SwitcherIconProps {
prefixCls: string;
treeNodeProps: AntTreeNodeProps;
switcherIcon?: SwitcherIcon;
switcherLoadingIcon?: React.ReactNode;
showLine?: boolean | {
showLeafIcon: boolean | TreeLeafIcon;
};
}
declare const SwitcherIconCom: React.FC<SwitcherIconProps>;
export default SwitcherIconCom;
+85
View File
@@ -0,0 +1,85 @@
"use strict";
"use client";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var React = _interopRequireWildcard(require("react"));
var _CaretDownFilled = _interopRequireDefault(require("@ant-design/icons/CaretDownFilled"));
var _FileOutlined = _interopRequireDefault(require("@ant-design/icons/FileOutlined"));
var _LoadingOutlined = _interopRequireDefault(require("@ant-design/icons/LoadingOutlined"));
var _MinusSquareOutlined = _interopRequireDefault(require("@ant-design/icons/MinusSquareOutlined"));
var _PlusSquareOutlined = _interopRequireDefault(require("@ant-design/icons/PlusSquareOutlined"));
var _clsx = require("clsx");
var _is = require("../../_util/is");
var _reactNode = require("../../_util/reactNode");
const SwitcherIconCom = props => {
const {
prefixCls,
switcherIcon,
treeNodeProps,
showLine,
switcherLoadingIcon
} = props;
const {
isLeaf,
expanded,
loading
} = treeNodeProps;
if (loading) {
if (/*#__PURE__*/React.isValidElement(switcherLoadingIcon)) {
return switcherLoadingIcon;
}
return /*#__PURE__*/React.createElement(_LoadingOutlined.default, {
className: `${prefixCls}-switcher-loading-icon`
});
}
let showLeafIcon;
if ((0, _is.isPlainObject)(showLine)) {
showLeafIcon = showLine.showLeafIcon;
}
if (isLeaf) {
if (!showLine) {
return null;
}
if (typeof showLeafIcon !== 'boolean' && !!showLeafIcon) {
const leafIcon = typeof showLeafIcon === 'function' ? showLeafIcon(treeNodeProps) : showLeafIcon;
const leafCls = `${prefixCls}-switcher-line-custom-icon`;
if (/*#__PURE__*/React.isValidElement(leafIcon)) {
return (0, _reactNode.cloneElement)(leafIcon, {
className: (0, _clsx.clsx)(leafIcon.props?.className, leafCls)
});
}
return leafIcon;
}
return showLeafIcon ? (/*#__PURE__*/React.createElement(_FileOutlined.default, {
className: `${prefixCls}-switcher-line-icon`
})) : (/*#__PURE__*/React.createElement("span", {
className: `${prefixCls}-switcher-leaf-line`
}));
}
const switcherCls = `${prefixCls}-switcher-icon`;
const switcher = typeof switcherIcon === 'function' ? switcherIcon(treeNodeProps) : switcherIcon;
if (/*#__PURE__*/React.isValidElement(switcher)) {
return (0, _reactNode.cloneElement)(switcher, {
className: (0, _clsx.clsx)(switcher.props?.className, showLine ? `${prefixCls}-switcher-line-icon` : switcherCls)
});
}
if (switcher !== undefined) {
return switcher;
}
if (showLine) {
return expanded ? (/*#__PURE__*/React.createElement(_MinusSquareOutlined.default, {
className: `${prefixCls}-switcher-line-icon`
})) : (/*#__PURE__*/React.createElement(_PlusSquareOutlined.default, {
className: `${prefixCls}-switcher-line-icon`
}));
}
return /*#__PURE__*/React.createElement(_CaretDownFilled.default, {
className: switcherCls
});
};
var _default = exports.default = SwitcherIconCom;