Browse Source

Disable pointer-events on node images and content during pan/drag

Browser hit-testing against large base64 <img> elements is expensive
even when no React state updates occur. Two CSS-level fixes:

1. pointer-events: none on all .react-flow__node img — images never
   need direct mouse events (parent containers handle clicks)
2. .canvas-interacting class on <html> during pan/drag disables
   pointer-events on all node content via CSS descendant selector,
   toggled via direct DOM access (zero React overhead)

https://claude.ai/code/session_01MvD1n4QeXutgwUpKJuDGHa
handoff-20260429-1057
Claude 4 months ago
parent
commit
56ad9250e4
Failed to extract signature
  1. 13
      src/app/globals.css
  2. 8
      src/components/WorkflowCanvas.tsx

13
src/app/globals.css

@ -40,6 +40,19 @@ body {
font-family: inherit; font-family: inherit;
} }
/* Skip hit-testing on images inside nodes parent containers handle all
click/hover events. Prevents expensive bitmap decoding during mouse movement. */
.react-flow__node img {
pointer-events: none;
}
/* During active panning or node dragging, disable pointer events on all node
content to eliminate expensive browser hit-testing against the DOM tree.
The class is toggled on <html> via direct DOM access (no React re-render). */
.canvas-interacting .react-flow__node > * {
pointer-events: none;
}
/* Remove default React Flow styling for output nodes to match custom nodes */ /* Remove default React Flow styling for output nodes to match custom nodes */
.react-flow__node-output { .react-flow__node-output {
border: none !important; border: none !important;

8
src/components/WorkflowCanvas.tsx

@ -1964,10 +1964,10 @@ export function WorkflowCanvas() {
onEdgesChange={onEdgesChange} onEdgesChange={onEdgesChange}
onConnect={handleConnect} onConnect={handleConnect}
onConnectEnd={handleConnectEnd} onConnectEnd={handleConnectEnd}
onMoveStart={() => { isPanningRef.current = true; setHoveredNodeId(null); }} onMoveStart={() => { isPanningRef.current = true; setHoveredNodeId(null); document.documentElement.classList.add("canvas-interacting"); }}
onMoveEnd={() => { isPanningRef.current = false; }} onMoveEnd={() => { isPanningRef.current = false; document.documentElement.classList.remove("canvas-interacting"); }}
onNodeDragStart={() => { isDraggingNodeRef.current = true; }} onNodeDragStart={() => { isDraggingNodeRef.current = true; document.documentElement.classList.add("canvas-interacting"); }}
onNodeDragStop={(event, node) => { isDraggingNodeRef.current = false; handleNodeDragStop(event, node); }} onNodeDragStop={(event, node) => { isDraggingNodeRef.current = false; document.documentElement.classList.remove("canvas-interacting"); handleNodeDragStop(event, node); }}
onSelectionChange={handleSelectionChange} onSelectionChange={handleSelectionChange}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
edgeTypes={edgeTypes} edgeTypes={edgeTypes}

Loading…
Cancel
Save