Skip to content
Shapemetry

@huukhanhnguyen/model / schema/editHistory

schema/editHistory

EditHistory

EditHistory = { apply: LaneEditCall | null; beginGroup: void; canRedo: boolean; canUndo: boolean; clear: void; endGroup: void; future: readonly HistoryStep[]; note: void; onChange: () => void; past: readonly HistoryStep[]; record: void; redo: boolean; undo: boolean; withGroup: T; withTransaction: T; }

canRedo

readonly canRedo: boolean

canUndo

readonly canUndo: boolean

future

readonly future: readonly HistoryStep[]

Steps undone and available to redo (oldest first among future).

past

readonly past: readonly HistoryStep[]

Completed undo steps (oldest first).

Methods

apply()

apply(call): LaneEditCall | null

Apply a call through the door and record the inverse when present.

Parameters

call

LaneEditCall

Returns

LaneEditCall | null

beginGroup()

beginGroup(): void

Returns

void

clear()

clear(): void

Drop past/future (model load / switch). Open groups are discarded.

Returns

void

endGroup()

endGroup(): void

Returns

void

note()

note(call, inverse): void

Door helpers call this after a successful mutation. No-op when inverse is null (blocked remove, no-op move) or while undo/redo is replaying through the door.

Parameters

call

LaneEditCall

inverse

LaneEditCall | null | undefined

Returns

void

onChange()

onChange(listener): () => void

Subscribe to stack changes (canUndo/canRedo UI). Returns unsubscribe.

Parameters

listener

() => void

Returns

() => void

record()

record(entry): void

Push a single entry (clears redo). Used by tests and apply.

Parameters

entry

HistoryEntry

Returns

void

redo()

redo(): boolean

Returns

boolean

undo()

undo(): boolean

Returns

boolean

withGroup()

withGroup<T>(fn): T

Type Parameters

T

T

Parameters

fn

() => T

Returns

T

withTransaction()

withTransaction<T>(fn): T

Atomic multi-edit: run fn inside a group. On success the whole body is one undo step (same as withGroup). On throw, every edit captured so far is inverted in reverse order so the document is byte-identical to the pre-transaction state, then the error is rethrown — no undo step is left on the stack. Nested calls flatten into the outer transaction (inner begin only deepens the group; only the outermost rolls back or commits). Dirty / re-eval still fires per door edit during the body (preserves the current group contract — batching evaluation is a separate concern).

Type Parameters

T

T

Parameters

fn

() => T

Returns

T


HistoryEntry

HistoryEntry = { call: LaneEditCall; inverse: LaneEditCall; }

One door edit and the inverse that restores the pre-edit document.

call

call: LaneEditCall

inverse

inverse: LaneEditCall


HistoryStep

HistoryStep = { entries: HistoryEntry[]; }

One undo step. Ungrouped edits have a single entry; a user gesture that emits several door calls is one step with multiple entries (undone in reverse order, redone in original order).

entries

entries: HistoryEntry[]

Last updated: 📖 3 min readEdit on GitHub