import { Direction, IGraphEdge, IGraphNode, IPoint } from '../../lib/graph'; /** The default keyboard map. Every binding is overridable. */ export declare const DEFAULT_GRAPH_KEYS: { /** Move focus to the nearest node in a direction. */ readonly moveFocus: readonly ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]; /** Create a connected node in a direction. */ readonly createConnected: "Tab"; /** Edit the focused node. */ readonly edit: "Enter"; /** Leave edit mode, cancel a pending connection, or clear focus. */ readonly cancel: "Escape"; /** Delete the focused node. */ readonly delete: readonly ["Delete", "Backspace"]; /** Begin connecting from the focused node. */ readonly connect: "c"; /** Nudge the focused node. Held with the arrow keys. */ readonly nudgeModifier: "shiftKey"; }; export interface GraphKeyboardActions { /** * Create a node at a position, returning its id so focus can follow it. The * library never invents node content — you decide what a new node is. */ onCreateNode?: (position: IPoint, context: { from?: string; direction?: Direction; }) => string | undefined; /** Connect two nodes. */ onConnect?: (sourceId: string, targetId: string) => void; /** Delete a node and its edges. */ onDeleteNode?: (id: string) => void; /** Move a node, used by nudging. */ onMoveNode?: (id: string, position: IPoint) => void; /** Enter edit mode for a node. */ onEditNode?: (id: string) => void; } export interface UseGraphKeyboardOptions extends GraphKeyboardActions { /** The current nodes. Traversal and placement are computed from these. */ nodes: IGraphNode[]; /** The current edges. Used to reason about existing connections. */ edges: IGraphEdge[]; /** Take control of which node has keyboard focus. */ focusedId?: string | null; /** Starting focus when uncontrolled. */ defaultFocusedId?: string | null; /** Called whenever focus moves. */ onFocusChange?: (id: string | null) => void; /** * Element the listener attaches to. Bindings only fire while focus is inside * it, so several graphs can coexist on one page. */ targetRef: React.RefObject; /** How far a nudge moves a node, in graph units. Defaults to `16`. */ nudgeDistance?: number; /** Turn the whole thing off. */ disabled?: boolean; } export interface UseGraphKeyboardResult { /** The node the next keystroke applies to. */ focusedId: string | null; setFocusedId: (id: string | null) => void; /** Node currently being edited, if any. */ editingId: string | null; setEditingId: (id: string | null) => void; /** Source of a connection awaiting a target, if any. */ connectingFrom: string | null; setConnectingFrom: (id: string | null) => void; /** Move focus as an arrow key would. Exposed for toolbar buttons. */ moveFocus: (direction: Direction) => void; /** Create a connected node as Tab would. */ createConnected: (direction?: Direction) => void; } /** * Keyboard-driven graph navigation and editing. * * Headless: it owns the focus, editing and connection cursors and reports what * should happen, but renders nothing and mutates nothing. That means it works * with `GraphNode` or with your own node rendering, and every mutation stays * subject to your validation and undo. * * The default map, all overridable: * * | Key | Action | * | :-- | :-- | * | Arrows | Move focus to the nearest node in that direction | * | Shift + Arrows | Nudge the focused node | * | Tab / Shift+Tab | Create a node connected to the focused one | * | Enter | Edit the focused node | * | `c` then a node | Connect from the focused node | * | Delete / Backspace | Delete the focused node | * | Escape | Leave edit mode, cancel a connection, or clear focus | * * Arrow traversal is spatial rather than by insertion order — it picks the * nearest node in the direction travelled, penalising lateral offset, which is * what makes a hand-arranged diagram navigable without a mouse. * * @example * ```tsx * const canvasRef = useRef(null); * * const keyboard = useGraphKeyboard({ * nodes, edges, targetRef: canvasRef, * onCreateNode: (position) => { * const id = nextId('node', nodes); * setNodes([...nodes, { id, position, data: { label: 'New' } }]); * return id; * }, * onConnect: (source, target) => * setEdges([...edges, { id: nextId('edge', edges), source, target }]), * onDeleteNode: (id) => { … }, * }); * ``` */ export declare const useGraphKeyboard: ({ nodes, edges, focusedId: controlledFocusedId, defaultFocusedId, onFocusChange, targetRef, nudgeDistance, disabled, onCreateNode, onConnect, onDeleteNode, onMoveNode, onEditNode, }: UseGraphKeyboardOptions) => UseGraphKeyboardResult;