mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 04:48:53 +00:00
123 lines
3.0 KiB
TypeScript
123 lines
3.0 KiB
TypeScript
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
import type { Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
import { cssVar } from '@toeverything/theme';
|
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
|
import clsx from 'clsx';
|
|
import { type ReactElement } from 'react';
|
|
|
|
import * as styles from './drop-indicator.css';
|
|
|
|
export type DropIndicatorProps = {
|
|
instruction?: Instruction | null;
|
|
edge?: Edge | null;
|
|
};
|
|
|
|
function getTreeElement({
|
|
instruction,
|
|
isBlocked,
|
|
}: {
|
|
instruction: Exclude<Instruction, { type: 'instruction-blocked' }>;
|
|
isBlocked: boolean;
|
|
}): ReactElement | null {
|
|
const style = {
|
|
[styles.horizontalIndent]: `${instruction.currentLevel * instruction.indentPerLevel}px`,
|
|
[styles.indicatorColor]: !isBlocked
|
|
? cssVar('--affine-primary-color')
|
|
: cssVar('--affine-warning-color'),
|
|
};
|
|
|
|
if (instruction.type === 'reorder-above') {
|
|
return (
|
|
<div
|
|
className={clsx(styles.treeLine, styles.lineAboveStyles)}
|
|
style={assignInlineVars(style)}
|
|
/>
|
|
);
|
|
}
|
|
if (instruction.type === 'reorder-below') {
|
|
return (
|
|
<div
|
|
className={clsx(styles.treeLine, styles.lineBelowStyles)}
|
|
style={assignInlineVars(style)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (instruction.type === 'make-child') {
|
|
return (
|
|
<div
|
|
className={clsx(styles.outlineStyles)}
|
|
style={assignInlineVars(style)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (instruction.type === 'reparent') {
|
|
style[styles.horizontalIndent] = `${
|
|
instruction.desiredLevel * instruction.indentPerLevel
|
|
}px`;
|
|
|
|
return (
|
|
<div
|
|
className={clsx(styles.treeLine, styles.lineBelowStyles)}
|
|
style={assignInlineVars(style)}
|
|
/>
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
type Orientation = 'horizontal' | 'vertical';
|
|
|
|
const edgeToOrientationMap: Record<Edge, Orientation> = {
|
|
top: 'horizontal',
|
|
bottom: 'horizontal',
|
|
left: 'vertical',
|
|
right: 'vertical',
|
|
};
|
|
|
|
const orientationStyles: Record<Orientation, string> = {
|
|
horizontal: styles.horizontal,
|
|
vertical: styles.vertical,
|
|
};
|
|
|
|
const edgeStyles: Record<Edge, string> = {
|
|
top: styles.top,
|
|
bottom: styles.bottom,
|
|
left: styles.left,
|
|
right: styles.right,
|
|
};
|
|
|
|
function getEdgeElement(edge: Edge, gap: number = 0) {
|
|
const lineOffset = `calc(-0.5 * (${gap}px + 2px))`;
|
|
|
|
const orientation = edgeToOrientationMap[edge];
|
|
|
|
return (
|
|
<div
|
|
className={clsx([
|
|
styles.edgeLine,
|
|
orientationStyles[orientation],
|
|
edgeStyles[edge],
|
|
])}
|
|
style={assignInlineVars({ [styles.localLineOffset]: lineOffset })}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function DropIndicator({ instruction, edge }: DropIndicatorProps) {
|
|
if (edge) {
|
|
return getEdgeElement(edge, 0);
|
|
}
|
|
if (instruction) {
|
|
if (instruction.type === 'instruction-blocked') {
|
|
return getTreeElement({
|
|
instruction: instruction.desired,
|
|
isBlocked: true,
|
|
});
|
|
}
|
|
return getTreeElement({ instruction, isBlocked: false });
|
|
}
|
|
return;
|
|
}
|