Hooks
Read or drive every slice of WireProvider state from your own components — diagram, selection, viewport, mode, history, validation, and events.
Usage
All hooks must be called inside a WireProvider subtree. They re-render their host when the slice they read changes — the targeted hooks (useWireSelection, useWireMode, …) are tighter than reaching into the full context.
import {
WireProvider,
WireCanvas,
useWireSelection,
useWireMode,
useWireHistory
} from "@aigentive/wire-react";
function Toolbar() {
const [mode, setMode] = useWireMode();
const { canUndo, canRedo, undo, redo } = useWireHistory();
const [selection, { clear }] = useWireSelection();
return (
<div className="flex gap-2">
<button onClick={() => setMode(mode === "edit" ? "view" : "edit")}>
{mode === "edit" ? "Done" : "Edit"}
</button>
<button disabled={!canUndo} onClick={undo}>Undo</button>
<button disabled={!canRedo} onClick={redo}>Redo</button>
<button disabled={!selection.nodeIds.length} onClick={clear}>Deselect</button>
</div>
);
}
export function App({ diagram }) {
return (
<WireProvider defaultDiagram={diagram}>
<Toolbar />
<WireCanvas mode="edit" fitView />
</WireProvider>
);
}Reference
useWireDiagram(): WireDiagramRead the live diagram in any descendant of WireProvider. Re-renders on diagram change.
Returns: Current diagram (read-only).
useWireValidation(): ValidationResultLatest validation result. Pair with `validateOnChange` on WireProvider to keep it fresh.
Returns: { valid, issues }
useWireSelection(): readonly [WireSelection, SelectionActions]Read or drive selection state. Use `clear()` from a custom panel; `setNodeIds([id])` to focus a node.
Returns: [selection, { setNodeIds, setEdgeIds, clear, … }]
useWireViewport(): readonly [WireViewport, ViewportActions]Read or drive pan/zoom. Useful when a sidebar action needs to recenter the canvas.
Returns: [{ x, y, zoom }, { setViewport, fitView, … }]
useWireMode(): readonly ["view" | "edit", (next) => void]Read and toggle the editor mode. Bind to a top-bar button; canvas + cards respond automatically.
Returns: [mode, setMode]
useWireActions(): { dispatch, dispatchMany, validate }Lower-level access when you need to dispatch a batch atomically (`dispatchMany`).
Returns: Action dispatchers + on-demand validate.
useWireDispatch(): (action: WireAction) => voidCompact `dispatch` for one-off mutations from custom UI (rename a node, change tone).
Returns: Single-action shorthand.
useWireHistory(): { canUndo, canRedo, undo, redo }Wire to a toolbar's undo/redo buttons. Provider tracks history automatically.
Returns: Undo/redo state + actions.
useWireEvents(): { emit }Emit a WireEvent from app code (e.g., `node.inspect` from a side panel) — flows through `onEvent` like canvas-emitted events.
Returns: Programmatic event emitter.
useWireContext(): WireContextValueEscape hatch — direct access to every slice. Prefer the targeted hooks above.
Returns: Raw context.
Common patterns
Custom inspector tied to selection
Combine useWireSelection with useWireDiagram to render a panel that always reflects the active node — without prop drilling.
function Inspector() {
const diagram = useWireDiagram();
const [{ nodeIds }] = useWireSelection();
const node = diagram.nodes.find((n) => n.id === nodeIds[0]);
if (!node) return <Empty />;
return <NodeForm node={node} />;
}Programmatic edits
Use useWireDispatch for one-off mutations and useWireActions’s dispatchMany for atomic batches.
function RenameButton({ id }: { id: string }) {
const dispatch = useWireDispatch();
return (
<button onClick={() => dispatch({ type: "node.patch", id, patch: { title: "Renamed" } })}>
Rename
</button>
);
}
function ApplyTemplate() {
const { dispatchMany } = useWireActions();
return (
<button onClick={() => dispatchMany([
{ type: "node.add", node: { id: "in", kind: "trigger", title: "Webhook" } },
{ type: "node.add", node: { id: "ai", kind: "ai", title: "Plan", from: "in", model: "gpt-5.4-mini" } }
])}>
Insert template
</button>
);
}