mobx-bonsai
Version:
A fast lightweight alternative to MobX-State-Tree + Y.js two-way binding
169 lines (168 loc) • 4.86 kB
TypeScript
import { UndoEvent, UndoStore } from './UndoStore';
/**
* Interface for managing attached state with undo events.
*/
export interface AttachedStateHandler<TAttachedState = unknown> {
save(): TAttachedState;
restore(state: TAttachedState): void;
}
/**
* Options for creating an UndoManager.
*/
export interface UndoManagerOptions<TAttachedState = unknown> {
/**
* The subtree root to track changes on.
*/
rootNode: object;
/**
* Optional UndoStore to use. If not provided, a new one will be created.
*
* Note: The UndoStore is not subject to the undo manager, even if it is
* a child of the rootNode. Changes to the UndoStore itself will not
* be tracked or undoable.
*/
store?: UndoStore;
/**
* Maximum number of undo levels to keep.
* @default Infinity
*/
maxUndoLevels?: number;
/**
* Maximum number of redo levels to keep.
* @default Infinity
*/
maxRedoLevels?: number;
/**
* Attached state management for storing additional state with each undo event.
*/
attachedState?: AttachedStateHandler<TAttachedState>;
/**
* Time window in milliseconds for grouping changes into a single undo event.
* If undefined (default), changes are only grouped within the same MobX action.
* If set to a number, changes that occur within this time window will be merged
* into the last undo event, even if they come from different actions.
*
* @default undefined
*/
groupingDebounceMs?: number;
}
/**
* Manages undo/redo functionality for a mobx-bonsai node tree.
* Automatically groups changes that occur within a single MobX action.
*/
export declare class UndoManager<TAttachedState = unknown> {
private disposer;
private interceptDisposer;
private isRecordingDisabled;
private readonly _maxUndoLevels;
private readonly _maxRedoLevels;
private readonly attachedState?;
private readonly groupingDebounceMs?;
/**
* Timestamp (performance.now()) of when the last undo event was recorded.
* Used for grouping debounce logic.
*/
private lastEventTimestamp;
/**
* The root node being tracked.
*/
readonly rootNode: object;
/**
* The UndoStore holding the undo/redo queues.
*/
readonly store: UndoStore;
/**
* Array of changes accumulated during the current action.
* These will be flushed as a single UndoEvent when the action completes.
* If length > 0, a flush is already enqueued.
*/
private pendingChanges;
/**
* State saved at the start of the current pending event (before any changes).
* This is captured lazily when the first change is intercepted.
* Undefined means it hasn't been captured yet for the current event.
*/
private attachedStateBeforeNextEvent;
constructor(options: UndoManagerOptions<TAttachedState>);
/**
* Starts tracking changes on the root node.
*/
private startTracking;
/**
* Records a change. If this is the first change in an action, schedules a flush.
*/
private recordChange;
/**
* Schedules a flush to occur when the current action completes.
*/
private scheduleFlush;
/**
* Flushes pending changes as a single UndoEvent.
*/
private flushPendingChanges;
/**
* The undo queue.
*/
get undoQueue(): ReadonlyArray<UndoEvent>;
/**
* The redo queue.
*/
get redoQueue(): ReadonlyArray<UndoEvent>;
/**
* Number of undo steps available.
*/
get undoLevels(): number;
/**
* Whether undo is possible.
*/
get canUndo(): boolean;
/**
* Number of redo steps available.
*/
get redoLevels(): number;
/**
* Whether redo is possible.
*/
get canRedo(): boolean;
/**
* Maximum number of undo levels to keep.
*/
get maxUndoLevels(): number;
/**
* Maximum number of redo levels to keep.
*/
get maxRedoLevels(): number;
/**
* Undoes the last change.
* @throws if called while inside a MobX action
* @throws if there are no undo events
*/
undo(): void;
/**
* Redoes the last undone change.
* @throws if called while inside a MobX action
* @throws if there are no redo events
*/
redo(): void;
/**
* Clears the undo queue.
*/
clearUndo: () => void;
/**
* Clears the redo queue.
*/
clearRedo: () => void;
/**
* Executes a function without recording changes.
*/
withoutUndo<T>(fn: () => T): T;
/**
* Whether undo recording is currently disabled.
*/
get isUndoRecordingDisabled(): boolean;
/**
* Disposes the undo manager, stopping change tracking.
*/
dispose(): void;
}