feat(canvas): add double-click functionality to create nodes from blank canvas area

This commit is contained in:
HouYunFei
2026-07-13 10:43:37 +08:00
parent ebd8ae2de7
commit 301fbce472
4 changed files with 63 additions and 9 deletions
@@ -11,12 +11,13 @@ type InfiniteCanvasProps = {
onViewportChange: (viewport: ViewportTransform) => void;
onCanvasMouseDown?: (event: React.PointerEvent<HTMLDivElement>) => void;
onCanvasDeselect?: () => void;
onCanvasDoubleClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
onContextMenu?: (event: React.MouseEvent) => void;
onDrop?: (event: React.DragEvent<HTMLDivElement>) => void;
children: React.ReactNode;
};
export function InfiniteCanvas({ containerRef, viewport, backgroundMode = "lines", onViewportChange, onCanvasMouseDown, onCanvasDeselect, onContextMenu, onDrop, children }: InfiniteCanvasProps) {
export function InfiniteCanvas({ containerRef, viewport, backgroundMode = "lines", onViewportChange, onCanvasMouseDown, onCanvasDeselect, onCanvasDoubleClick, onContextMenu, onDrop, children }: InfiniteCanvasProps) {
const theme = canvasThemes[useThemeStore((state) => state.theme)];
const panState = useRef({
isPanning: false,
@@ -116,6 +117,12 @@ export function InfiniteCanvas({ containerRef, viewport, backgroundMode = "lines
}
};
const handleDoubleClick = (event: React.MouseEvent<HTMLDivElement>) => {
const target = event.target instanceof Element ? event.target : null;
if (target?.closest("[data-canvas-no-zoom],[data-node-id],[data-connection-id]")) return;
onCanvasDoubleClick?.(event);
};
useEffect(() => {
const handlePointerMove = (event: PointerEvent) => {
if (!panState.current.isPanning) return;
@@ -171,6 +178,7 @@ export function InfiniteCanvas({ containerRef, viewport, backgroundMode = "lines
className="relative h-full w-full cursor-grab select-none overflow-hidden"
style={{ background: theme.canvas.background }}
onPointerDown={handlePointerDown}
onDoubleClick={handleDoubleClick}
onWheel={handleWheel}
onContextMenu={onContextMenu}
onDragOver={(event) => event.preventDefault()}