feat: improve mouse events

This commit is contained in:
2026-03-11 10:27:17 +01:00
parent c330713fa7
commit deb1be0d66
3 changed files with 29 additions and 1 deletions

View File

@@ -188,6 +188,8 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
const flowActionsRef = useRef<{ pasteAtViewportCenter: () => void; fitView: () => void } | null>(null)
const [contextTarget, setContextTarget] = React.useState<null | { type: 'canvas'; clientX: number; clientY: number }>(null)
const [lastCreatedNodeId, setLastCreatedNodeId] = React.useState<string | null>(null)
const [isPanning, setIsPanning] = React.useState(false)
const [isSelecting, setIsSelecting] = React.useState(false)
const [ariaAnnouncement, setAriaAnnouncement] = React.useState<string | null>(null)
const nodesRef = useRef(nodes)
nodesRef.current = nodes
@@ -286,6 +288,11 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
const onInit = useCallback((instance: unknown) => setRfInstance(instance), [])
const onMoveStart = useCallback(() => setIsPanning(true), [])
const onMoveEnd = useCallback(() => setIsPanning(false), [])
const onSelectionDragStart = useCallback(() => setIsSelecting(true), [])
const onSelectionDragStop = useCallback(() => setIsSelecting(false), [])
const onNodeDragStart = useCallback(() => saveForDragEnd(), [saveForDragEnd])
const onNodeDragStop = useCallback(() => commitDragEnd(), [commitDragEnd])
@@ -612,6 +619,7 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
<FlowFitViewOnLoad />
<FlowKeyboardShortcuts />
<ReactFlow
className={isPanning ? 'react-flow--panning' : isSelecting ? 'react-flow--selecting' : undefined}
nodes={nodes.map((n) => ({
...n,
className: [n.className, 'nowheel'].filter(Boolean).join(' '),
@@ -624,6 +632,10 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
onConnectEnd={onConnectEnd}
onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop}
onMoveStart={onMoveStart}
onMoveEnd={onMoveEnd}
onSelectionDragStart={onSelectionDragStart}
onSelectionDragStop={onSelectionDragStop}
isValidConnection={isValidConnection}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
@@ -639,6 +651,11 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
nodesDraggable
nodesConnectable
elementsSelectable
panOnScroll
zoomOnScroll
zoomActivationKeyCode="Meta"
panOnDrag={[1]}
selectionOnDrag
>
{/* BackgroundVariant from @xyflow/system expects enum; 'dots' is valid at runtime */}
<Background variant={'dots' as React.ComponentProps<typeof Background>['variant']} gap={20} />

View File

@@ -13,7 +13,7 @@ import { cn } from '@/lib/utils'
const MIN_ZOOM = 0.1
const MAX_ZOOM = 2
/** When zoom <= this value, show compact icon view (bottom ~30% of zoom range). */
export const CONTEXTUAL_ZOOM_THRESHOLD = MIN_ZOOM + 0.3 * (MAX_ZOOM - MIN_ZOOM)
export const CONTEXTUAL_ZOOM_THRESHOLD = MIN_ZOOM + 0.1 * (MAX_ZOOM - MIN_ZOOM)
/** Handle id per type for compact view (input, output). */
const COMPACT_HANDLES: Record<string, { input?: string; output?: string }> = {

View File

@@ -20,6 +20,17 @@ body {
min-height: 0;
}
/* Canvas pane cursors: crosshair for selection box, grab/grabbing for middle-click pan */
.react-flow__pane {
cursor: crosshair;
}
.react-flow.react-flow--panning .react-flow__pane {
cursor: grabbing;
}
.react-flow.react-flow--selecting .react-flow__pane {
cursor: crosshair;
}
/* Node specific overrides */
.react-flow__node {
display: block;