@lupinum/board-history
Deterministic structural undo/redo with connection-aware state restoration.
Install
pnpm add @lupinum/board-history @lupinum/board-corehistoryPlugin
Creates the history plugin. Install it during engine creation via createBoardEngine({ plugins }).
const plugin = historyPlugin({ maxSteps: 100 })Options
| Name | Type | Default | Description |
|---|---|---|---|
maxSteps | number | 200 | Maximum number of undo steps to retain. |
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.
undo(): voidengine.plugins.history.undo()redo
Re-applies the next state. No-op if there is nothing to redo.
redo(): voidcanUndo
Returns true if there is at least one undo step available.
canUndo(): booleancanRedo
Returns true if there is at least one redo step available.
canRedo(): booleanclear
Clears the entire history stack (both undo and redo).
clear(): voidgetState
Returns the current history state.
getState(): HistoryStateconst 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
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
interface HistoryEntry {
label: string // command name that created this entry
timestamp: number // Date.now() when the entry was created
}HistoryPluginOptions
interface HistoryPluginOptions {
maxSteps?: number // default: 200
}Events
The history plugin adds these events to BoardEventMap:
| Event | Handler | Description |
|---|---|---|
history:push | (entry: HistoryEntry) => void | A new entry was added to the undo stack. |
history:undo | (entry: HistoryEntry | null) => void | An undo operation was performed. |
history:redo | (entry: HistoryEntry | null) => void | A redo operation was performed. |
history:clear | () => void | The history stack was cleared. |
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)
})