From 5cf4c92f5216610ba35c4cc898c88a80ba7809b9 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Tue, 3 Mar 2026 23:07:20 +1300 Subject: [PATCH] feat: show header controls on node body hover, not just header hover Add hoveredNodeId to store, set from BaseNode mouse events, read in FloatingNodeHeader. Controls now appear when hovering any part of the node, not just the floating header strip. Co-Authored-By: Claude Opus 4.6 --- src/components/nodes/BaseNode.tsx | 3 +++ src/components/nodes/FloatingNodeHeader.tsx | 9 ++++++--- src/store/workflowStore.ts | 7 +++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/nodes/BaseNode.tsx b/src/components/nodes/BaseNode.tsx index d1093d1f..2c061f27 100644 --- a/src/components/nodes/BaseNode.tsx +++ b/src/components/nodes/BaseNode.tsx @@ -32,6 +32,7 @@ export function BaseNode({ }: BaseNodeProps) { const currentNodeIds = useWorkflowStore((state) => state.currentNodeIds); const nodes = useWorkflowStore((state) => state.nodes); + const setHoveredNodeId = useWorkflowStore((state) => state.setHoveredNodeId); const isCurrentlyExecuting = currentNodeIds.includes(id); const { getNodes, setNodes } = useReactFlow(); @@ -82,6 +83,8 @@ export function BaseNode({ ${!fullBleed && selected ? "border-blue-500 ring-2 ring-blue-500/40 shadow-lg shadow-blue-500/25" : ""} ${className} `} + onMouseEnter={() => setHoveredNodeId(id)} + onMouseLeave={() => setHoveredNodeId(null)} >
{children}
diff --git a/src/components/nodes/FloatingNodeHeader.tsx b/src/components/nodes/FloatingNodeHeader.tsx index 49b710b8..8da8f732 100644 --- a/src/components/nodes/FloatingNodeHeader.tsx +++ b/src/components/nodes/FloatingNodeHeader.tsx @@ -4,6 +4,7 @@ import { ReactNode, useState, useEffect, useRef, useCallback } from "react"; import { createPortal } from "react-dom"; import { useReactFlow } from "@xyflow/react"; import { NodeType } from "@/types"; +import { useWorkflowStore } from "@/store/workflowStore"; export interface CommentNavigationProps { currentIndex: number; @@ -51,7 +52,9 @@ export function FloatingNodeHeader({ onCommentChange, commentNavigation, }: FloatingNodeHeaderProps) { - const [isHovered, setIsHovered] = useState(false); + const [isHeaderHovered, setIsHeaderHovered] = useState(false); + const isBodyHovered = useWorkflowStore((state) => state.hoveredNodeId === id); + const isHovered = isHeaderHovered || isBodyHovered; const [isEditingTitle, setIsEditingTitle] = useState(false); const [editTitleValue, setEditTitleValue] = useState(customTitle || ""); const [isEditingComment, setIsEditingComment] = useState(false); @@ -278,8 +281,8 @@ export function FloatingNodeHeader({ width: `${width}px`, zIndex: selected ? 10000 : 9000, }} - onMouseEnter={() => setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} + onMouseEnter={() => setIsHeaderHovered(true)} + onMouseLeave={() => setIsHeaderHovered(false)} onMouseDown={handleHeaderMouseDown} >
diff --git a/src/store/workflowStore.ts b/src/store/workflowStore.ts index a8528e26..d0f19244 100644 --- a/src/store/workflowStore.ts +++ b/src/store/workflowStore.ts @@ -243,9 +243,11 @@ interface WorkflowStore { openModalCount: number; isModalOpen: boolean; showQuickstart: boolean; + hoveredNodeId: string | null; incrementModalCount: () => void; decrementModalCount: () => void; setShowQuickstart: (show: boolean) => void; + setHoveredNodeId: (id: string | null) => void; // Execution isRunning: boolean; @@ -450,6 +452,7 @@ const workflowStoreImpl: StateCreator = (set, get) => ({ openModalCount: 0, isModalOpen: false, showQuickstart: true, + hoveredNodeId: null, isRunning: false, currentNodeIds: [], // Changed from currentNodeId for parallel execution pausedAtNodeId: null, @@ -522,6 +525,10 @@ const workflowStoreImpl: StateCreator = (set, get) => ({ set({ showQuickstart: show }); }, + setHoveredNodeId: (id: string | null) => { + set({ hoveredNodeId: id }); + }, + addNode: (type: NodeType, position: XYPosition, initialData?: Partial) => { const id = `${type}-${++nodeIdCounter}`;