feat: support pivots menu (#1755)

This commit is contained in:
Qi
2023-03-30 17:37:41 +08:00
committed by GitHub
parent 4dd1490eef
commit b6ded30770
40 changed files with 1513 additions and 665 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { useDrag, useDrop } from 'react-dnd';
import {
@@ -14,21 +14,21 @@ import type {
TreeNodeProps,
} from './types';
const NodeLine = <N,>({
const NodeLine = <RenderProps,>({
node,
onDrop,
allowDrop = true,
isTop = false,
}: NodeLIneProps<N>) => {
}: NodeLIneProps<RenderProps>) => {
const [{ isOver }, drop] = useDrop(
() => ({
accept: 'node',
drop: (item: Node<N>, monitor) => {
drop: (item: Node<RenderProps>, monitor) => {
const didDrop = monitor.didDrop();
if (didDrop) {
return;
}
onDrop?.(item, node, {
onDrop?.(item.id, node.id, {
internal: false,
topLine: isTop,
bottomLine: !isTop,
@@ -44,24 +44,23 @@ const NodeLine = <N,>({
return <StyledNodeLine ref={drop} show={isOver && allowDrop} isTop={isTop} />;
};
const TreeNodeItem = <N,>({
const TreeNodeItemWithDnd = <RenderProps,>({
node,
allowDrop,
collapsed,
setCollapsed,
...otherProps
}: TreeNodeItemProps<N>) => {
}: TreeNodeItemProps<RenderProps>) => {
const { onAdd, onDelete, onDrop } = otherProps;
const [{ canDrop, isOver }, drop] = useDrop(
() => ({
accept: 'node',
drop: (item: Node<N>, monitor) => {
drop: (item: Node<RenderProps>, monitor) => {
const didDrop = monitor.didDrop();
if (didDrop || item.id === node.id || !allowDrop) {
return;
}
onDrop?.(item, node, {
onDrop?.(item.id, node.id, {
internal: true,
topLine: false,
bottomLine: false,
@@ -77,44 +76,79 @@ const TreeNodeItem = <N,>({
useEffect(() => {
if (isOver && canDrop) {
setCollapsed(false);
setCollapsed(node.id, false);
}
}, [isOver, canDrop]);
return (
<div ref={drop}>
<TreeNodeItem
dropRef={drop}
onAdd={onAdd}
onDelete={onDelete}
node={node}
allowDrop={allowDrop}
setCollapsed={setCollapsed}
isOver={isOver}
canDrop={canDrop}
{...otherProps}
/>
);
};
const TreeNodeItem = <RenderProps,>({
node,
collapsed,
setCollapsed,
selectedId,
isOver = false,
canDrop = false,
onAdd,
onDelete,
dropRef,
}: TreeNodeItemProps<RenderProps>) => {
return (
<div ref={dropRef}>
{node.render?.(node, {
isOver: !!(isOver && canDrop),
isOver: isOver && canDrop,
onAdd: () => onAdd?.(node),
onDelete: () => onDelete?.(node),
collapsed,
setCollapsed,
isSelected: selectedId === node.id,
})}
</div>
);
};
export const TreeNode = <N,>({
node,
index,
allowDrop = true,
...otherProps
}: TreeNodeProps<N>) => {
const { indent } = otherProps;
const [collapsed, setCollapsed] = useState(false);
export const TreeNodeWithDnd = <RenderProps,>(
props: TreeNodeProps<RenderProps>
) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: 'node',
item: node,
item: props.node,
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
}));
return <TreeNode dragRef={drag} isDragging={isDragging} {...props} />;
};
export const TreeNode = <RenderProps,>({
node,
index,
isDragging = false,
allowDrop = true,
dragRef,
...otherProps
}: TreeNodeProps<RenderProps>) => {
const { indent, enableDnd, collapsedIds } = otherProps;
const collapsed = collapsedIds.includes(node.id);
return (
<StyledTreeNodeContainer ref={drag} isDragging={isDragging}>
<StyledTreeNodeContainer ref={dragRef} isDragging={isDragging}>
<StyledTreeNodeWrapper>
{index === 0 && (
{enableDnd && index === 0 && (
<NodeLine
node={node}
{...otherProps}
@@ -122,15 +156,25 @@ export const TreeNode = <N,>({
isTop={true}
/>
)}
<TreeNodeItem
node={node}
index={index}
allowDrop={allowDrop}
collapsed={collapsed}
setCollapsed={setCollapsed}
{...otherProps}
/>
{(!node.children?.length || collapsed) && (
{enableDnd ? (
<TreeNodeItemWithDnd
node={node}
index={index}
allowDrop={allowDrop}
collapsed={collapsed}
{...otherProps}
/>
) : (
<TreeNodeItem
node={node}
index={index}
allowDrop={allowDrop}
collapsed={collapsed}
{...otherProps}
/>
)}
{enableDnd && (!node.children?.length || collapsed) && (
<NodeLine
node={node}
{...otherProps}
@@ -140,18 +184,26 @@ export const TreeNode = <N,>({
</StyledTreeNodeWrapper>
<StyledCollapse in={!collapsed} indent={indent}>
{node.children &&
node.children.map((childNode, index) => (
<TreeNode
key={childNode.id}
node={childNode}
index={index}
allowDrop={isDragging ? false : allowDrop}
{...otherProps}
/>
))}
node.children.map((childNode, index) =>
enableDnd ? (
<TreeNodeWithDnd
key={childNode.id}
node={childNode}
index={index}
allowDrop={isDragging ? false : allowDrop}
{...otherProps}
/>
) : (
<TreeNode
key={childNode.id}
node={childNode}
index={index}
allowDrop={false}
{...otherProps}
/>
)
)}
</StyledCollapse>
</StyledTreeNodeContainer>
);
};
export default TreeNode;