import type { ActionMiddlewareDisposer } from "../action/middleware";
import type { Path } from "../parent/pathTypes";
import { Patch } from "../patch";
/**
 * An undo/redo event without attached state.
 */
export declare type UndoEventWithoutAttachedState = UndoSingleEvent | UndoEventGroup;
/**
 * An undo/redo event.
 */
export declare type UndoEvent = UndoEventWithoutAttachedState & {
    /**
     * The state saved before the event actions started / after the event actions finished.
     */
    attachedState: {
        /**
         * The state saved before the event actions started.
         */
        beforeEvent?: unknown;
        /**
         * The state saved after the event actions finished.
         */
        afterEvent?: unknown;
    };
};
/**
 * Undo event type.
 */
export declare enum UndoEventType {
    Single = "single",
    Group = "group"
}
/**
 * An undo/redo single event.
 */
export interface UndoSingleEvent {
    /**
     * Expresses this is a single event.
     */
    readonly type: UndoEventType.Single;
    /**
     * Path to the object that invoked the action from its root.
     */
    readonly targetPath: Path;
    /**
     * Name of the action that was invoked.
     */
    readonly actionName: string;
    /**
     * Patches with changes done inside the action.
     * Use `redo()` in the `UndoManager` to apply them.
     */
    readonly patches: ReadonlyArray<Patch>;
    /**
     * Patches to undo the changes done inside the action.
     * Use `undo()` in the `UndoManager` to apply them.
     */
    readonly inversePatches: ReadonlyArray<Patch>;
}
/**
 * An undo/redo event group.
 */
export interface UndoEventGroup {
    /**
     * Expresses this is an event group.
     */
    readonly type: UndoEventType.Group;
    /**
     * Name of the group (if any).
     */
    readonly groupName?: string;
    /**
     * Events that conform this group (might be single events or other nested groups).
     */
    readonly events: ReadonlyArray<UndoEventWithoutAttachedState>;
}
declare const UndoStore_base: import("../model/Model")._Model<unknown, {
    undoEvents: import("..").OptionalModelProp<UndoEvent[]>;
    redoEvents: import("..").OptionalModelProp<UndoEvent[]>;
} & {
    $modelId: import("..").ModelProp<string, string, string, true, never>;
}>;
/**
 * Store model instance for undo/redo actions.
 * Do not manipulate directly, other that creating it.
 */
export declare class UndoStore extends UndoStore_base {
    /**
     * @ignore
     */
    _clearUndo(): void;
    /**
     * @ignore
     */
    _clearRedo(): void;
    /**
     * @ignore
     */
    _undo(): void;
    /**
     * @ignore
     */
    _redo(): void;
    /**
     * @ignore
     */
    _addUndo(event: UndoEvent): void;
    private _groupStack;
    /**
     * @ignore
     */
    _addUndoToParentGroup(parentGroup: UndoEventGroup, event: UndoEventWithoutAttachedState): void;
    /**
     * @ignore
     */
    get _currentGroup(): UndoEventGroup | undefined;
    /**
     * @ignore
     */
    _startGroup(groupName: string | undefined, startRunning: boolean, options: UndoMiddlewareOptions<unknown> | undefined): {
        pause: () => void;
        resume: () => void;
        end: () => void;
    };
}
/**
 * Manager class returned by `undoMiddleware` that allows you to perform undo/redo actions.
 */
export declare class UndoManager {
    private readonly disposer;
    private readonly subtreeRoot;
    private readonly options;
    /**
     * The store currently being used to store undo/redo action events.
     */
    readonly store: UndoStore;
    /**
     * The undo stack, where the first operation to undo will be the last of the array.
     * Do not manipulate this array directly.
     */
    get undoQueue(): ReadonlyArray<UndoEvent>;
    /**
     * The redo stack, where the first operation to redo will be the last of the array.
     * Do not manipulate this array directly.
     */
    get redoQueue(): ReadonlyArray<UndoEvent>;
    /**
     * The number of undo actions available.
     */
    get undoLevels(): number;
    /**
     * If undo can be performed (if there is at least one undo action available).
     */
    get canUndo(): boolean;
    /**
     * Clears the undo queue.
     */
    clearUndo(): void;
    /**
     * The number of redo actions available.
     */
    get redoLevels(): number;
    /**
     * If redo can be performed (if there is at least one redo action available)
     */
    get canRedo(): boolean;
    /**
     * Clears the redo queue.
     */
    clearRedo(): void;
    /**
     * Undoes the last action.
     * Will throw if there is no action to undo.
     */
    undo(): void;
    /**
     * Redoes the previous action.
     * Will throw if there is no action to redo.
     */
    redo(): void;
    /**
     * Disposes the undo middleware.
     */
    dispose(): void;
    private _isUndoRecordingDisabled;
    /**
     * Returns if undo recording is currently disabled or not for this particular `UndoManager`.
     */
    get isUndoRecordingDisabled(): boolean;
    /**
     * Skips the undo recording mechanism for the code block that gets run synchronously inside.
     *
     * @typeparam T Code block return type.
     * @param fn Code block to run.
     * @returns The value returned by the code block.
     */
    withoutUndo<T>(fn: () => T): T;
    /**
     * Creates a custom group that can be continued multiple times and then ended.
     * @param groupName Optional group name.
     * @returns An API to continue/end the group.
     */
    createGroup(groupName?: string): {
        continue<T>(fn: () => T): T;
        end(): void;
    };
    /**
     * Runs a synchronous code block as an undo group.
     * Note that nested groups are allowed.
     *
     * @param groupName Group name.
     * @param fn Code block.
     * @returns Code block return value.
     */
    withGroup<T>(groupName: string, fn: () => T): T;
    /**
     * Runs a synchronous code block as an undo group.
     * Note that nested groups are allowed.
     *
     * @param fn Code block.
     * @returns Code block return value.
     */
    withGroup<T>(fn: () => T): T;
    /**
     * Runs an asynchronous code block as an undo group.
     * Note that nested groups are allowed.
     *
     * @param groupName Group name.
     * @param fn Flow function.
     * @returns Flow function return value.
     */
    withGroupFlow<R>(groupName: string, fn: () => Generator<any, R, any>): Promise<R>;
    /**
     * Runs an asynchronous code block as an undo group.
     * Note that nested groups are allowed.
     *
     * @param fn Flow function.
     * @returns Flow function return value.
     */
    withGroupFlow<R>(fn: () => Generator<any, R, any>): Promise<R>;
    /**
     * Creates an instance of `UndoManager`.
     * Do not use directly, use `undoMiddleware` instead.
     *
     * @param disposer
     * @param subtreeRoot
     * @param [store]
     */
    constructor(disposer: ActionMiddlewareDisposer, subtreeRoot: object, store: UndoStore | undefined, options: UndoMiddlewareOptions<unknown> | undefined);
}
/**
 * Undo middleware options.
 */
export interface UndoMiddlewareOptions<S> {
    attachedState?: {
        save(): S;
        restore(s: S): void;
    };
}
/**
 * Creates an undo middleware.
 *
 * @param subtreeRoot Subtree root target object.
 * @param store Optional `UndoStore` where to store the undo/redo queues. Use this if you want to
 * store such queues somewhere in your models. If none is provided it will reside in memory.
 * @param options Extra options, such as how to save / restore certain snapshot of the state to be restored when undoing/redoing.
 * @returns An `UndoManager` which allows you to do the manage the undo/redo operations and dispose of the middleware.
 */
export declare function undoMiddleware<S>(subtreeRoot: object, store?: UndoStore, options?: UndoMiddlewareOptions<S>): UndoManager;
/**
 * Returns if the undo recording mechanism is currently disabled.
 *
 * @returns `true` if it is currently disabled, `false` otherwise.
 */
export declare function isGlobalUndoRecordingDisabled(): boolean;
/**
 * Globally skips the undo recording mechanism for the code block that gets run synchronously inside.
 * Consider using the `withoutUndo` method of a particular `UndoManager` instead.
 *
 * @typeparam T Code block return type.
 * @param fn Code block to run.
 * @returns The value returned by the code block.
 */
export declare function withoutUndo<T>(fn: () => T): T;
export {};
