@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.
BoardHistoryShortcuts
Import BoardHistoryShortcuts from @lupinum/board-history/vue and render it
inside BoardRoot with
<BoardHistoryShortcuts :history="engine.plugins.history" />. The required
prop identifies the history API, while the enclosing root identifies which DOM
events it may handle. Editable controls and events already handled by another
component keep their native behavior.
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)
})