Skip to main content

Selection and interaction

Selection modes, box selection, and the interaction state machine.

Selection and interaction are how users communicate with the board. Select nodes to act on them, drag to move, resize from handles, and box-select on empty canvas.

Interact with the board and watch the mode change in the sidebar.

Current interaction

idle

Selection

Nothing selected yet.

Selecting nodes

ts
engine.select(nodeId) // replace selection
engine.select([nodeA, nodeB]) // replace with multiple
engine.select(nodeId, 'append') // add to selection
engine.select(nodeId, 'toggle') // flip in/out
engine.selectAll() // all visible nodes
engine.clearSelection() // deselect everything
const selected = engine.getSelection() // NodeId[]
ModeBehavior
'replace'Clears existing selection, selects the given IDs (default).
'append'Adds IDs to the existing selection.
'toggle'Flips each ID in/out of the selection.

Keyboard shortcuts: + A to select all, Escape to deselect.

In Vue, use the useBoardSelection() composable for reactive access:

vue
<script setup lang="ts">
const selection = useBoardSelection()
// selection.value is readonly NodeId[]
</script>

Interaction state machine

The engine tracks pointer interactions through six modes. Only one mode is active at a time.

Pointer event flow

When a pointer event hits BoardRoot:

  1. Middle mouse / Space starts panning.
  2. Resize handle selects the node, then starts resizing after the drag threshold.
  3. Node selects the node, then starts dragging after the drag threshold.
  4. Empty canvas clears selection, then starts a box-selection session after the drag threshold.

Pointer movement is throttled through requestAnimationFrame and translated by BoardRoot; the low-level start, update, commit, and cancellation methods are absent from the normal engine API and available only through the unsupported first-party framework ABI. Pointer up commits the session, while pointer cancellation or Escape restores its starting geometry.

BoardRoot handles two-finger pinch gestures on touch devices automatically.
Implementation detail

Text editing commands

BoardRoot exclusively owns pointer sessions. Applications can still control the meaningful text-edit boundary directly:

ts
engine.beginTextEdit(nodeId)
engine.commitTextEdit(nodeId, 'New text')
engine.cancelTextEdit()
Implementation detail

Interaction events

ts
engine.on('interaction:start', (state) => console.log('Started:', state.mode))
engine.on('interaction:update', (state) => {
  /* high-frequency during drag */
})
engine.on('interaction:end', (state) => console.log('Ended:', state.mode))