import type { NodeBase, EdgeBase, InternalNodeBase, Viewport, NodeLookup, ParentLookup, EdgeLookup, ConnectionLookup, CoordinateExtent, SnapGrid, NodeOrigin, Transform, PanZoomInstance, XYPosition, FitViewOptionsBase, OnConnect, OnConnectStart, OnConnectEnd, IsValidConnection, NodeDragItem, ConnectionMode, Connection, } from '@xyflow/system' import type { Signal, Memo } from '@barefootjs/client' import type { ComponentDef } from '@barefootjs/client/runtime' export type FitViewOptions = FitViewOptionsBase export type { NodeBase, EdgeBase, InternalNodeBase, Viewport, NodeLookup, ParentLookup, EdgeLookup, ConnectionLookup, CoordinateExtent, SnapGrid, NodeOrigin, Transform, PanZoomInstance, XYPosition, OnConnect, OnConnectStart, OnConnectEnd, IsValidConnection, NodeDragItem, ConnectionMode, Connection, } /** * Callback fired when an edge is reconnected to a new handle. */ export type OnReconnect = ( oldEdge: EdgeType, newConnection: Connection, ) => void /** * Options for creating a flow store. */ export type FlowStoreOptions< NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase, > = { nodes?: NodeType[] edges?: EdgeType[] defaultViewport?: Viewport minZoom?: number maxZoom?: number nodeOrigin?: NodeOrigin nodeExtent?: CoordinateExtent snapToGrid?: boolean snapGrid?: SnapGrid fitView?: boolean fitViewOptions?: FitViewOptions // Custom component types nodeTypes?: Record) => void)> edgeTypes?: Record) => void)> // Edge reconnection edgesReconnectable?: boolean onReconnect?: OnReconnect // Connection callbacks onConnect?: OnConnect onConnectStart?: OnConnectStart onConnectEnd?: OnConnectEnd isValidConnection?: IsValidConnection // Lifecycle callbacks onInit?: (store: FlowStore) => void onNodeDragStart?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void onNodeDragStop?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void onMoveEnd?: (event: MouseEvent | TouchEvent | null, viewport: Viewport) => void onPaneClick?: (event: MouseEvent) => void onPaneMouseMove?: (event: MouseEvent) => void onNodesDelete?: (nodes: NodeType[]) => void onEdgesDelete?: (edges: EdgeType[]) => void // Interactivity config panOnDrag?: boolean panOnScroll?: boolean zoomOnScroll?: boolean zoomOnDoubleClick?: boolean zoomActivationKeyCode?: string | null nodesDraggable?: boolean nodesConnectable?: boolean elementsSelectable?: boolean deleteKeyCode?: string[] | null selectionKeyCode?: string | null connectionLineStyle?: Record defaultEdgeOptions?: Partial elevateNodesOnSelect?: boolean reconnectRadius?: number } /** * The reactive flow store — all state exposed as signal getters. */ export type FlowStore< NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase, > = { // Reactive state (signal getters) nodes: Signal[0] edges: Signal[0] viewport: Signal[0] width: Signal[0] height: Signal[0] dragging: Signal[0] nodesInitialized: Memo // Lookups (signal getters) nodeLookup: Signal>>[0] parentLookup: Signal>>[0] edgeLookup: Signal>[0] connectionLookup: Signal[0] /** * Fine-grained per-node subscription. Returns the current internal * entry for the given id, and tracks it for reactivity — the * surrounding effect / memo will re-run only when **this** node's * entry changes (data, selected, position via setNodes, or in-place * drag updates), not on changes to sibling nodes. * * Use this in per-node consumers (data / selected / position * observers). For iteration-style consumers that walk all nodes, * keep using `nodeLookup()`. */ nodeSignal: (id: string) => InternalNodeBase | undefined // Lightweight position change counter — subscribers re-run without // triggering the full adoptUserNodes pipeline. positionEpoch: Signal[0] triggerPositionUpdate: () => void // Internal refs panZoom: Signal[0] domNode: Signal[0] // Setters setNodes: Signal[1] setEdges: Signal[1] setViewport: Signal[1] setWidth: Signal[1] setHeight: Signal[1] // Selection state multiSelectionActive: Signal[0] // Interactivity — when false, nodes cannot be dragged/connected/deleted nodesDraggable: Signal[0] setNodesDraggable: Signal[1] // Actions fitView: (options?: FitViewOptions) => void updateNodePositions: ( dragItems: Map>, dragging?: boolean, ) => void unselectNodesAndEdges: (params?: { nodes?: NodeType[] edges?: EdgeType[] }) => void panByDelta: (delta: XYPosition) => Promise addEdge: (edge: EdgeType) => void deleteElements: (params: { nodes?: NodeType[] edges?: EdgeType[] }) => void // Configuration minZoom: number maxZoom: number nodeOrigin: NodeOrigin nodeExtent: CoordinateExtent snapToGrid: boolean snapGrid: SnapGrid // Viewport transform as [tx, ty, scale] getTransform: () => Transform // Custom component types nodeTypes?: Record) => void)> edgeTypes?: Record) => void)> // Edge reconnection edgesReconnectable: boolean onReconnect?: OnReconnect // Connection callbacks onConnect?: OnConnect onConnectStart?: OnConnectStart onConnectEnd?: OnConnectEnd isValidConnection?: IsValidConnection // Lifecycle callbacks onInit?: (store: FlowStore) => void onNodeDragStart?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void onNodeDragStop?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void onMoveEnd?: (event: MouseEvent | TouchEvent | null, viewport: Viewport) => void onPaneClick?: (event: MouseEvent) => void onPaneMouseMove?: (event: MouseEvent) => void onNodesDelete?: (nodes: NodeType[]) => void onEdgesDelete?: (edges: EdgeType[]) => void // Interactivity (reactive signals) nodesConnectable: Signal[0] setNodesConnectable: Signal[1] elementsSelectable: Signal[0] setElementsSelectable: Signal[1] panOnDrag: Signal[0] setPanOnDrag: Signal[1] panOnScroll: Signal[0] setPanOnScroll: Signal[1] zoomOnScroll: Signal[0] setZoomOnScroll: Signal[1] // Static config deleteKeyCode: string[] | null selectionKeyCode: string | null connectionLineStyle?: Record defaultEdgeOptions?: Partial elevateNodesOnSelect: boolean reconnectRadius: number } /** * Internal setters exposed by createFlowStore but not part of the public API. * Used only by initFlow during initialization. */ export type InternalFlowStore< NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase, > = FlowStore & { setDragging: Signal[1] setPanZoom: Signal[1] setDomNode: Signal[1] setMultiSelectionActive: Signal[1] updatePanZoomConfig: () => void } /** * Props passed to custom node components. */ export type NodeComponentProps = { id: string data: NodeType['data'] type: string /** * Reactive getter for this node's selected state. Call inside a * createEffect to observe selection changes at runtime — reading it once * at mount time only yields the initial value. */ selected: () => boolean dragging: boolean positionAbsoluteX: number positionAbsoluteY: number width?: number height?: number isConnectable: boolean } /** * Props passed to custom edge components. */ export type EdgeComponentProps = { id: string source: string target: string sourceX: number sourceY: number targetX: number targetY: number sourcePosition: string targetPosition: string data: EdgeType['data'] selected: boolean animated: boolean label?: string /** SVG group element to render custom edge content into */ svgGroup: SVGGElement } /** * Selection mode for rectangle selection. * - 'partial': selects nodes that partially overlap the rectangle (default) * - 'full': only selects nodes fully contained in the rectangle */ export type SelectionMode = 'partial' | 'full' /** * Props for the Flow init function. */ export type FlowProps< NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase, > = FlowStoreOptions & { class?: string /** When true, dragging on empty pane starts selection without Shift key */ selectionOnDrag?: boolean /** Selection mode: 'partial' (default) or 'full' */ selectionMode?: SelectionMode }