Events surface
Five event types, two built-in emitters, seven source labels, one onEvent handler. Canvas gestures and list selections share the same shape.
Why a separate event channel
Wire splits data changes from UI gestures. WireAction objects move through the reducer; WireEvent objects move through onEvent. That separation is what lets a sidebar follow selection without re-rendering the canvas, or lets you fire a router push without dispatching an action.
The five types
| Type | Meaning | Sources | Payload |
|---|---|---|---|
| node.click | Pointer click on a node body | canvasnode-list | { nodeId } |
| node.inspect | Open the inspector for this node (double-click on canvas, configurable on list) | canvasnode-list | { nodeId } |
| edge.click | Click on an edge polyline | canvas | { edgeId } |
| selection.change | Selection set changed (single or multi-select) | canvasnode-list | { selection: { nodeIds, edgeIds } } |
| pane.click | Click on empty canvas (clears selection) | canvas | {} |
Source labels
Built-in components emit from canvas and node-list. The other labels are reserved so custom cards, panels, workspaces, or integrations can use the same event shape.
| Source | Status | Emitted by | Notes |
|---|---|---|---|
| canvas | Built-in | WireCanvas | Node, edge, pane, and selection events from the interactive canvas. |
| node-list | Built-in | WireNodeList | Row clicks plus configurable inspect/selection emissions. |
| node-card | Reserved | Custom app code | Use when an app-owned card wrapper emits events. |
| option-panel | Reserved | Custom app code | Use for app-specific option panel interactions. |
| validation-panel | Reserved | Custom app code | Use for app-specific validation panel interactions. |
| workspace | Reserved | Custom app code | Use for workspace-level events not tied to canvas/list. |
| api | Reserved | Programmatic code | Use for non-pointer or integration-driven emissions. |
Click recipes
One handler, narrow by type:
<WireWorkspace
onEvent={(event) => {
if (event.type === "node.inspect") {
router.push(`?node=${event.nodeId}`);
} else if (event.type === "edge.click") {
openEdgeInspector(event.edgeId);
} else if (event.type === "selection.change") {
setSelected(event.selection);
} else if (event.type === "pane.click") {
router.push(""); // deselect
}
}}
/>;Try it
Both inputs share a single WireProvider, so every gesture flows through the same onEvent handler. The source tells you which surface fired it. Try clicking a node on the canvas, an empty area on the canvas (fires pane.click), and a row in the list.