import React, { useMemo } from 'react' import type { Connection } from '@xyflow/react' import type { AppNode, AppEdge } from '@/lib/nodeTypes' export type ConnectionFrom = { nodeId: string; sourceHandle?: string } | null /** Role of a node in the current connection path update: pushing data, receiving/loading, or just on path. */ export type ConnectionPathRole = 'trigger' | 'updating' | 'on-path' export type FlowActions = { pasteAtViewportCenter: () => void fitView: () => void } export type FlowContextValue = { nodes: AppNode[] setNodes: (updater: AppNode[] | ((prev: AppNode[]) => AppNode[])) => void edges: AppEdge[] setEdges: (updater: AppEdge[] | ((prev: AppEdge[]) => AppEdge[])) => void renamingNodeId: string | null setRenamingNodeId: (id: string | null) => void /** Set when user starts dragging from an output handle; cleared on connect end. Used to highlight valid targets. */ connectionFrom: ConnectionFrom setConnectionFrom: (v: ConnectionFrom) => void isValidConnection: (connection: Connection) => boolean /** Set by FlowKeyboardShortcuts so Node menubar can trigger paste / fit view. */ flowActionsRef: React.MutableRefObject /** When set, graph centers on this node and a fullscreen dialog shows the node. Cleared on close. */ fullscreenNodeId: string | null setFullscreenNodeId: (id: string | null) => void /** Node ids currently updating (e.g. render loading, agent running). Only edges on those paths show the ant trail. */ connectionPathUpdatingNodeIds: string[] /** Node ids that triggered the current update (e.g. variable/config that changed). Path is restricted to downstream(trigger) ∩ upstream(updating). */ connectionPathTriggerNodeIds: string[] /** Call when this node's output changed and may trigger downstream updates (e.g. variable value, config content). */ addConnectionPathTrigger: (nodeId: string) => void /** All node ids on the path of an update. Edges with both endpoints in this set animate. */ connectionPathNodeIds: Set /** Call when a path update starts for this node. Animation runs at least CONNECTION_PATH_UPDATE_MIN_MS. */ startConnectionPathUpdate: (nodeId: string) => void /** Call when a path update ends for this node. If min duration not reached, animation continues until then. */ endConnectionPathUpdate: (nodeId: string) => void } const FlowContext = React.createContext(null) export default FlowContext /** * Returns this node's role in the current path update for styling (pushing vs receiving). * Use with BaseNode's connectionPathRole prop or data-path-role for CSS. */ export function useConnectionPathRole(nodeId: string | undefined): ConnectionPathRole | null { const ctx = React.useContext(FlowContext) return useMemo(() => { if (!nodeId) return null const triggers = ctx?.connectionPathTriggerNodeIds const updating = ctx?.connectionPathUpdatingNodeIds const path = ctx?.connectionPathNodeIds if (!path?.has(nodeId)) return null if (triggers?.includes(nodeId)) return 'trigger' if (updating?.includes(nodeId)) return 'updating' return 'on-path' }, [nodeId, ctx?.connectionPathTriggerNodeIds, ctx?.connectionPathUpdatingNodeIds, ctx?.connectionPathNodeIds]) }