mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
144 lines
4.5 KiB
TypeScript
Executable File
144 lines
4.5 KiB
TypeScript
Executable File
import React, { useMemo } from 'react';
|
|
|
|
import {
|
|
DndContext,
|
|
DragOverlay,
|
|
DropAnimation,
|
|
MeasuringStrategy,
|
|
PointerSensor,
|
|
defaultDropAnimation,
|
|
useSensor,
|
|
useSensors,
|
|
} from '@dnd-kit/core';
|
|
import {
|
|
SortableContext,
|
|
verticalListSortingStrategy,
|
|
} from '@dnd-kit/sortable';
|
|
|
|
import { DndTreeItem } from './tree-item';
|
|
import type { TreeItems } from './types';
|
|
import { usePageTree } from './use-page-tree';
|
|
import { getChildCount } from './utils';
|
|
|
|
const measuring = {
|
|
droppable: {
|
|
strategy: MeasuringStrategy.Always,
|
|
},
|
|
};
|
|
|
|
const dropAnimation: DropAnimation = {
|
|
...defaultDropAnimation,
|
|
// dragSourceOpacity: 0.5,
|
|
};
|
|
|
|
export type DndTreeProps = {
|
|
defaultItems?: TreeItems;
|
|
indentationWidth?: number;
|
|
collapsible?: boolean;
|
|
removable?: boolean;
|
|
};
|
|
|
|
/**
|
|
* Currently does not support drag and drop using the keyboard.
|
|
*/
|
|
export function DndTree(props: DndTreeProps) {
|
|
const { indentationWidth = 20, collapsible, removable } = props;
|
|
|
|
const sensors = useSensors(
|
|
useSensor(PointerSensor, { activationConstraint: { distance: 8 } })
|
|
);
|
|
|
|
const {
|
|
items,
|
|
activeId,
|
|
flattenedItems,
|
|
projected,
|
|
handleDragStart,
|
|
handleDragMove,
|
|
handleDragOver,
|
|
handleDragEnd,
|
|
handleDragCancel,
|
|
handleRemove,
|
|
handleCollapse,
|
|
} = usePageTree(props);
|
|
|
|
const sortedIds = useMemo(
|
|
() => flattenedItems.map(({ id }) => id),
|
|
[flattenedItems]
|
|
);
|
|
|
|
const activeItem = useMemo(
|
|
() =>
|
|
activeId ? flattenedItems.find(({ id }) => id === activeId) : null,
|
|
[activeId, flattenedItems]
|
|
);
|
|
|
|
return (
|
|
<DndContext
|
|
sensors={sensors}
|
|
measuring={measuring}
|
|
onDragStart={handleDragStart}
|
|
onDragMove={handleDragMove}
|
|
onDragOver={handleDragOver}
|
|
onDragEnd={handleDragEnd}
|
|
onDragCancel={handleDragCancel}
|
|
>
|
|
<SortableContext
|
|
items={sortedIds}
|
|
strategy={verticalListSortingStrategy}
|
|
>
|
|
{/* <button onClick={() => handleAdd()}> add top node</button> */}
|
|
{flattenedItems.map(
|
|
({ id, title, children, collapsed, depth }) => {
|
|
return (
|
|
<DndTreeItem
|
|
key={id}
|
|
id={id}
|
|
// value={id}
|
|
value={title}
|
|
collapsed={Boolean(
|
|
collapsed && children.length
|
|
)}
|
|
depth={
|
|
id === activeId && projected
|
|
? projected.depth
|
|
: depth
|
|
}
|
|
indentationWidth={indentationWidth}
|
|
childCount={children.length}
|
|
onCollapse={
|
|
collapsible && children.length
|
|
? () => handleCollapse(id)
|
|
: undefined
|
|
}
|
|
onRemove={
|
|
removable
|
|
? () => handleRemove(id)
|
|
: undefined
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
)}
|
|
<DragOverlay
|
|
dropAnimation={dropAnimation}
|
|
// TODO fix drag offset when the position of the page tree changes
|
|
style={{ marginTop: '-100px' }}
|
|
>
|
|
{activeId && activeItem ? (
|
|
<DndTreeItem
|
|
id={activeId}
|
|
// value={activeId}
|
|
value={activeItem.title}
|
|
depth={activeItem.depth}
|
|
clone={true}
|
|
childCount={getChildCount(items, activeId) + 1}
|
|
indentationWidth={indentationWidth}
|
|
/>
|
|
) : null}
|
|
</DragOverlay>
|
|
</SortableContext>
|
|
</DndContext>
|
|
);
|
|
}
|