fix: update tree title render & switchIcon

pull/4577/head
tangjinzhou 2021-08-25 21:15:39 +08:00
parent eff286d0e5
commit e8b1f68899
12 changed files with 124 additions and 80 deletions

View File

@ -162,6 +162,7 @@ export { default as Table, TableColumn, TableColumnGroup } from './table';
export type { TransferProps } from './transfer';
export { default as Transfer } from './transfer';
export type { TreeProps, DirectoryTreeProps } from './tree';
export { default as Tree, TreeNode, DirectoryTree } from './tree';
export type { TreeSelectProps } from './tree-select';

View File

@ -7,7 +7,7 @@ import VcTree, { TreeNode } from '../vc-tree';
import PropTypes from '../_util/vue-types';
import { filterEmpty } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import type { DataNode, DragNodeEvent, FieldNames, Key } from '../vc-tree/interface';
import type { DataNode, EventDataNode, FieldNames, Key } from '../vc-tree/interface';
import type { TreeNodeProps } from '../vc-tree/props';
import { treeProps as vcTreeProps } from '../vc-tree/props';
import useConfigInject from '../_util/hooks/useConfigInject';
@ -42,7 +42,7 @@ export type AntTreeNodeProps = TreeNodeProps;
export type TreeDataItem = DataNode;
export interface AntTreeNodeBaseEvent {
node: DataNode;
node: EventDataNode;
nativeEvent: MouseEvent;
}
@ -63,7 +63,7 @@ export interface AntTreeNodeExpandedEvent extends AntTreeNodeBaseEvent {
}
export interface AntTreeNodeMouseEvent {
node: DataNode;
node: EventDataNode;
event: DragEvent;
}
@ -72,8 +72,8 @@ export interface AntTreeNodeDragEnterEvent extends AntTreeNodeMouseEvent {
}
export interface AntTreeNodeDropEvent {
node: DragNodeEvent;
dragNode: DragNodeEvent;
node: EventDataNode;
dragNode: EventDataNode;
dragNodesKeys: Key[];
dropPosition: number;
dropToGap?: boolean;
@ -192,7 +192,7 @@ export default defineComponent({
const {
showIcon,
showLine,
switcherIcon = slots.switcherIcon?.(),
switcherIcon = slots.switcherIcon,
icon = slots.icon,
blockNode,
checkable,

View File

@ -2,19 +2,24 @@ import type { App, Plugin } from 'vue';
import Tree from './Tree';
import DirectoryTree from './DirectoryTree';
export { EventDataNode, DataNode } from '../vc-tree/interface';
export type { EventDataNode, DataNode } from '../vc-tree/interface';
export {
export type {
TreeProps,
AntTreeNodeMouseEvent,
AntTreeNodeExpandedEvent,
AntTreeNodeCheckedEvent,
AntTreeNodeSelectedEvent,
AntTreeNodeDragEnterEvent,
AntTreeNodeDropEvent,
AntdTreeNodeAttribute,
TreeDataItem,
} from './Tree';
export { ExpandAction as DirectoryTreeExpandAction, DirectoryTreeProps } from './DirectoryTree';
export type {
ExpandAction as DirectoryTreeExpandAction,
DirectoryTreeProps,
} from './DirectoryTree';
Tree.TreeNode.name = 'ATreeNode';
Tree.DirectoryTree = DirectoryTree;

View File

@ -12,41 +12,46 @@ export default function renderSwitcherIcon(
prefixCls: string,
switcherIcon: any,
showLine: boolean | { showLeafIcon: boolean } | undefined,
{ isLeaf, expanded, loading }: AntTreeNodeProps,
props: AntTreeNodeProps,
) {
const { isLeaf, expanded, loading } = props;
let icon = switcherIcon;
if (loading) {
return <LoadingOutlined class={`${prefixCls}-switcher-loading-icon`} />;
}
let showLeafIcon;
let showLeafIcon: boolean;
if (showLine && typeof showLine === 'object') {
showLeafIcon = showLine.showLeafIcon;
}
let defaultIcon = null;
const switcherCls = `${prefixCls}-switcher-icon`;
if (isLeaf) {
if (showLine) {
if (typeof showLine === 'object' && !showLeafIcon) {
return <span class={`${prefixCls}-switcher-leaf-line`} />;
defaultIcon = <span class={`${prefixCls}-switcher-leaf-line`} />;
} else {
defaultIcon = <FileOutlined class={`${prefixCls}-switcher-line-icon`} />;
}
return <FileOutlined class={`${prefixCls}-switcher-line-icon`} />;
}
return null;
return defaultIcon;
} else {
defaultIcon = <CaretDownFilled class={switcherCls} />;
if (showLine) {
defaultIcon = expanded ? (
<MinusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
) : (
<PlusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
);
}
}
const switcherCls = `${prefixCls}-switcher-icon`;
if (isValidElement(switcherIcon)) {
return cloneVNode(switcherIcon, {
if (typeof switcherIcon === 'function') {
icon = switcherIcon({ ...props, defaultIcon, switcherCls });
} else if (isValidElement(icon)) {
icon = cloneVNode(icon, {
class: switcherCls,
});
}
if (switcherIcon) {
return switcherIcon;
}
if (showLine) {
return expanded ? (
<MinusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
) : (
<PlusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
);
}
return <CaretDownFilled class={switcherCls} />;
return icon || defaultIcon;
}

View File

@ -101,15 +101,16 @@ const SingleSelector = defineComponent<SelectorProps>({
// custom tree-select title by slot
if (item && treeSelectContext.value.slots) {
titleNode =
item.label ||
treeSelectContext.value.slots[item?.option?.data?.slots?.title] ||
treeSelectContext.value.slots.title;
treeSelectContext.value.slots.title ||
item.label;
if (typeof titleNode === 'function') {
titleNode = titleNode(item.option?.data || {});
} else if (treeSelectContext.value.slots.titleRender) {
// title titleRender title titleRender
titleNode = treeSelectContext.value.slots.titleRender(item.option?.data || {});
}
// else if (treeSelectContext.value.slots.titleRender) {
// // title titleRender title titleRender
// titleNode = treeSelectContext.value.slots.titleRender(item.option?.data || {});
// }
} else {
titleNode = item?.label;
}

View File

@ -1,3 +1,4 @@
import { filterEmpty } from '../../_util/props-util';
import type { VNodeChild } from 'vue';
import { camelize } from 'vue';
import { warning } from '../../vc-util/warning';
@ -16,7 +17,7 @@ function isTreeSelectNode(node: any) {
}
export function convertChildrenToData(rootNodes: VNodeChild): DataNode[] {
function dig(treeNodes: any[] = []): DataNode[] {
return treeNodes.map(treeNode => {
return filterEmpty(treeNodes).map(treeNode => {
// Filter invalidate node
if (!isTreeSelectNode(treeNode)) {
warning(!treeNode, 'TreeSelect/TreeSelectNode can only accept TreeSelectNode as children.');

View File

@ -245,7 +245,7 @@ export default defineComponent({
cleanDragState();
if (onDragend && !outsideTree) {
onDragend({ event, node: node.eventData.value });
onDragend({ event, node: node.eventData });
}
dragNode = null;
@ -267,17 +267,17 @@ export default defineComponent({
y: event.clientY,
};
const newExpandedKeys = arrDel(expandedKeys.value, eventKey.value);
const newExpandedKeys = arrDel(expandedKeys.value, eventKey);
dragState.dragging = true;
dragState.dragChildrenKeys = getDragChildrenKeys(eventKey.value, keyEntities.value);
dragState.dragChildrenKeys = getDragChildrenKeys(eventKey, keyEntities.value);
indent.value = listRef.value.getIndentWidth();
setExpandedKeys(newExpandedKeys);
window.addEventListener('dragend', onWindowDragEnd);
if (onDragstart) {
onDragstart({ event, node: eventData.value });
onDragstart({ event, node: eventData });
}
};
@ -339,25 +339,25 @@ export default defineComponent({
clearTimeout(delayedDragEnterLogic[key]);
});
if (dragNode.eventKey.value !== node.eventKey.value) {
if (dragNode.eventKey !== node.eventKey) {
// hoist expand logic here
// since if logic is on the bottom
// it will be blocked by abstract dragover node check
// => if you dragenter from top, you mouse will still be consider as in the top node
delayedDragEnterLogic[node.pos.value] = window.setTimeout(() => {
delayedDragEnterLogic[node.pos] = window.setTimeout(() => {
if (!dragState.dragging) return;
let newExpandedKeys = [...expandedKeys.value];
const entity = keyEntities.value[node.eventKey.value];
const entity = keyEntities.value[node.eventKey];
if (entity && (entity.children || []).length) {
newExpandedKeys = arrAdd(expandedKeys.value, node.eventKey.value);
newExpandedKeys = arrAdd(expandedKeys.value, node.eventKey);
}
setExpandedKeys(newExpandedKeys);
if (onExpand) {
onExpand(newExpandedKeys, {
node: node.eventData.value,
node: node.eventData,
expanded: true,
nativeEvent: event,
});
@ -366,7 +366,7 @@ export default defineComponent({
}
// Skip if drag node is self
if (dragNode.eventKey.value === dropTargetKey && dropLevelOffset === 0) {
if (dragNode.eventKey === dropTargetKey && dropLevelOffset === 0) {
Object.assign(dragState, {
dragOverNodeKey: null,
dropPosition: null,
@ -393,7 +393,7 @@ export default defineComponent({
if (onDragenter) {
onDragenter({
event,
node: node.eventData.value,
node: node.eventData,
expandedKeys: expandedKeys.value,
});
}
@ -431,7 +431,7 @@ export default defineComponent({
// Update drag position
if (dragNode.eventKey.value === dropTargetKey && dropLevelOffset === 0) {
if (dragNode.eventKey === dropTargetKey && dropLevelOffset === 0) {
if (
!(
dragState.dropPosition === null &&
@ -476,7 +476,7 @@ export default defineComponent({
}
if (onDragover) {
onDragover({ event, node: node.eventData.value });
onDragover({ event, node: node.eventData });
}
};
@ -484,7 +484,7 @@ export default defineComponent({
const { onDragleave } = props;
if (onDragleave) {
onDragleave({ event, node: node.eventData.value });
onDragleave({ event, node: node.eventData });
}
};
const onNodeDrop = (event: MouseEvent, _node, outsideTree = false) => {
@ -517,8 +517,8 @@ export default defineComponent({
const dropResult = {
event,
node: convertNodePropsToEventData(abstractDropNodeProps),
dragNode: dragNode ? dragNode.eventData.value : null,
dragNodesKeys: [dragNode.eventKey.value].concat(dragChildrenKeys),
dragNode: dragNode ? dragNode.eventData : null,
dragNodesKeys: [dragNode.eventKey].concat(dragChildrenKeys),
dropToGap: dropPosition !== 0,
dropPosition: dropPosition + Number(posArr[posArr.length - 1]),
};

View File

@ -2,11 +2,20 @@ import { useInjectTreeContext } from './contextTypes';
import { getDataAndAria } from './util';
import Indent from './Indent';
import { convertNodePropsToEventData } from './utils/treeUtil';
import { computed, defineComponent, onMounted, onUpdated, ref } from 'vue';
import {
computed,
defineComponent,
getCurrentInstance,
onMounted,
onUpdated,
reactive,
ref,
} from 'vue';
import { treeNodeProps } from './props';
import classNames from '../_util/classNames';
import { warning } from '../vc-util/warning';
import type { DragNodeEvent } from './interface';
import type { DragNodeEvent, Key } from './interface';
import pick from 'lodash-es/pick';
const ICON_OPEN = 'open';
const ICON_CLOSE = 'close';
@ -87,16 +96,36 @@ export default defineComponent({
return treeSelectable;
});
const renderArgsData = computed(() => {
return {
...pick(props, [
'active',
'checkable',
'checked',
'disableCheckbox',
'disabled',
'expanded',
'isLeaf',
'loading',
'selectable',
'selected',
'halfChecked',
]),
...props.data,
dataRef: props.data,
isLeaf: isLeaf.value,
};
});
const eventData = computed(() => {
return convertNodePropsToEventData(props);
});
const dragNodeEvent: DragNodeEvent = {
const dragNodeEvent: DragNodeEvent = reactive({
eventData,
eventKey: computed(() => props.eventKey),
selectHandle,
pos: computed(() => props.pos),
};
key: getCurrentInstance().vnode.key as Key,
});
expose(dragNodeEvent);
const onSelectorDoubleClick = (e: MouseEvent) => {
const { onNodeDoubleClick } = context.value;
@ -214,7 +243,7 @@ export default defineComponent({
onNodeExpand(e, eventData.value);
};
const renderSwitcherIconDom = (isLeaf: boolean) => {
const renderSwitcherIconDom = () => {
const {
switcherIcon: switcherIconFromProps = slots.switcherIcon ||
context.value.slots?.[props.data?.slots?.switcherIcon],
@ -224,7 +253,7 @@ export default defineComponent({
const switcherIcon = switcherIconFromProps || switcherIconFromCtx;
// if switcherIconDom is null, no render switcher span
if (typeof switcherIcon === 'function') {
return switcherIcon({ ...props, isLeaf });
return switcherIcon(renderArgsData.value);
}
return switcherIcon;
};
@ -259,11 +288,9 @@ export default defineComponent({
const renderSwitcher = () => {
const { expanded } = props;
const { prefixCls } = context.value;
// if switcherIconDom is null, no render switcher span
const switcherIconDom = renderSwitcherIconDom();
if (isLeaf.value) {
// if switcherIconDom is null, no render switcher span
const switcherIconDom = renderSwitcherIconDom(true);
return switcherIconDom !== false ? (
<span class={classNames(`${prefixCls}-switcher`, `${prefixCls}-switcher-noop`)}>
{switcherIconDom}
@ -276,8 +303,6 @@ export default defineComponent({
`${prefixCls}-switcher_${expanded ? ICON_OPEN : ICON_CLOSE}`,
);
const switcherIconDom = renderSwitcherIconDom(false);
return switcherIconDom !== false ? (
<span onClick={onExpand} class={switcherCls}>
{switcherIconDom}
@ -348,14 +373,19 @@ export default defineComponent({
// Icon + Title
const renderSelector = () => {
const {
title = slots.title ||
context.value.slots?.[props.data?.slots?.title] ||
context.value.slots?.title,
// title = slots.title ||
// context.value.slots?.[props.data?.slots?.title] ||
// context.value.slots?.title,
selected,
icon = slots.icon,
loading,
data,
} = props;
const title =
slots.title ||
context.value.slots?.[props.data?.slots?.title] ||
context.value.slots?.title ||
props.title;
const {
prefixCls,
showIcon,
@ -377,7 +407,7 @@ export default defineComponent({
$icon = currentIcon ? (
<span class={classNames(`${prefixCls}-iconEle`, `${prefixCls}-icon__customize`)}>
{typeof currentIcon === 'function' ? currentIcon(props) : currentIcon}
{typeof currentIcon === 'function' ? currentIcon(renderArgsData.value) : currentIcon}
</span>
) : (
renderIcon()
@ -389,9 +419,9 @@ export default defineComponent({
// Title
let titleNode: any;
if (typeof title === 'function') {
titleNode = title(data);
titleNode = title(renderArgsData.value);
} else if (contextSlots.titleRender) {
titleNode = contextSlots.titleRender(data);
titleNode = contextSlots.titleRender(renderArgsData.value);
} else {
titleNode = title;
}

View File

@ -1,4 +1,4 @@
import type { ComputedRef, CSSProperties, Ref, VNode } from 'vue';
import type { CSSProperties, VNode } from 'vue';
import type { TreeNodeProps } from './props';
export type { ScrollTo } from '../vc-virtual-list/List';
@ -43,10 +43,11 @@ export type Key = string | number;
export type NodeElement = VNode<TreeNodeProps>;
export type DragNodeEvent = {
eventData: ComputedRef<EventDataNode>;
eventKey: ComputedRef<Key>;
selectHandle: Ref<HTMLSpanElement>;
pos: ComputedRef<string>;
key: Key;
eventData: EventDataNode;
eventKey: Key;
selectHandle: HTMLSpanElement;
pos: string;
};
export interface Entity {
node: NodeElement;

View File

@ -108,7 +108,7 @@ export function calcDropPosition(
const rawDropLevelOffset = (horizontalMouseOffset - 12) / indent;
// find abstract drop node by horizontal offset
let abstractDropNodeEntity: DataEntity = keyEntities[targetNode.eventKey.value];
let abstractDropNodeEntity: DataEntity = keyEntities[targetNode.eventKey];
if (clientY < top + height / 2) {
// first half, set abstract drop node to previous node
@ -150,7 +150,7 @@ export function calcDropPosition(
dropNode: abstractDropDataNode,
dropPosition: -1,
}) &&
abstractDropNodeEntity.key === targetNode.eventKey.value
abstractDropNodeEntity.key === targetNode.eventKey
) {
// first half of first node in first level
dropPosition = -1;

View File

@ -14,6 +14,7 @@ import Omit from 'omit.js';
import type { VNodeChild } from 'vue';
import { camelize } from 'vue';
import type { TreeNodeProps } from '../props';
import { filterEmpty } from '../../_util/props-util';
export function getKey(key: Key, pos: string) {
if (key !== null && key !== undefined) {
@ -66,7 +67,7 @@ export function warningWithoutKey(treeData: DataNode[], fieldNames: FieldNames)
*/
export function convertTreeToData(rootNodes: VNodeChild): DataNode[] {
function dig(node: VNodeChild = []): DataNode[] {
const treeNodes = node as NodeElement[];
const treeNodes = filterEmpty(node as NodeElement[]);
return treeNodes.map(treeNode => {
// Filter invalidate node
if (!isTreeNode(treeNode)) {
@ -114,7 +115,6 @@ export function convertTreeToData(rootNodes: VNodeChild): DataNode[] {
return dataNode;
});
}
return dig(rootNodes);
}

2
v2-doc

@ -1 +1 @@
Subproject commit 3f94a02d16bac2377d71e26948ffe45571dae49e
Subproject commit bf82708b6f320f1e9b185c6eba58b4ce08593fc3