Skip to main content

@lupinum/board-history

Deterministic structural undo/redo with connection-aware state restoration.

Install

pnpm add @lupinum/board-history @lupinum/board-core
npm install @lupinum/board-history @lupinum/board-core

historyPlugin

Creates the history plugin. Install it during engine creation via createBoardEngine({ plugins }).

ts
const plugin = historyPlugin({ maxSteps: 100 })

Options

NameTypeDefaultDescription
maxStepsnumber200Maximum number of undo steps to retain.
ts
import { createBoardEngine } from '@lupinum/board-core'
import { historyPlugin } from '@lupinum/board-history'

const engine = createBoardEngine({
  plugins: [historyPlugin({ maxSteps: 100 })],
})

Command capture

History capture is driven by command metadata emitted by the engine and internal features. Camera movement, transient pointer setup/teardown, text-edit begin, imports, and selection-only commands mark themselves as ignored; geometry and content mutations mark themselves as recorded.


Plugin API

After installing the plugin, the history API is available on engine.plugins.history.

undo

Restores the previous state. No-op if there is nothing to undo.

ts
undo(): void
ts
engine.plugins.history.undo()

redo

Re-applies the next state. No-op if there is nothing to redo.

ts
redo(): void

canUndo

Returns true if there is at least one undo step available.

ts
canUndo(): boolean

canRedo

Returns true if there is at least one redo step available.

ts
canRedo(): boolean

clear

Clears the entire history stack (both undo and redo).

ts
clear(): void

getState

Returns the current history state.

ts
getState(): HistoryState
ts
const state = engine.plugins.history.getState()
console.log(`${state.undoDepth} undo steps, ${state.redoDepth} redo steps`)

History boundaries

History has no timers or implicit coalescing. A completed gesture, text edit, or outer batch() call creates one step. Separate programmatic commands create separate steps.


Connection-aware restoration

When the connections plugin is also installed, the history plugin automatically captures and restores edge state. Undoing a node deletion also restores any edges that were connected to that node.


Types

HistoryState

ts
interface HistoryState {
  undoDepth: number // number of undo steps available
  redoDepth: number // number of redo steps available
  current: string | null // label of the current history entry
}

HistoryEntry

ts
interface HistoryEntry {
  label: string // command name that created this entry
  timestamp: number // Date.now() when the entry was created
}

HistoryPluginOptions

ts
interface HistoryPluginOptions {
  maxSteps?: number // default: 200
}

Events

The history plugin adds these events to BoardEventMap:

EventHandlerDescription
history:push(entry: HistoryEntry) => voidA new entry was added to the undo stack.
history:undo(entry: HistoryEntry | null) => voidAn undo operation was performed.
history:redo(entry: HistoryEntry | null) => voidA redo operation was performed.
history:clear() => voidThe history stack was cleared.
ts
engine.on('history:push', (entry) => {
  console.log('New undo step:', entry.label)
})

engine.on('history:undo', () => {
  console.log('Undo depth:', engine.plugins.history.getState().undoDepth)
})