import { saveSelection } from '../../../../util/dom';
/**
 * A DOM-based undo manager. Integrates with native undo/redo functionality of
 * the browser. Supports user Ctrl+Z and Ctrl+Shift+Z shortcuts and application
 * context menu undo/redo events.
 */
export class WebUndo {
    /** Whether we are in a process of pushing a new undo item. */
    _push = false;
    /** The DOM element, which keeps text content for native undo/redo integration. */
    el;
    /** Undo stack. */
    uStack = [];
    /** Redo stack. */
    rStack = [];
    _undo() {
        const undo = this.uStack.pop();
        if (undo) {
            const redo = undo[1](undo[0]);
            this.rStack.push(redo);
        }
    }
    _redo() {
        const redo = this.rStack.pop();
        if (redo) {
            const undo = redo[1](redo[0]);
            this.uStack.push(undo);
        }
    }
    // /** ------------------------------------------------------ {@link UndoRedo} */
    push(undo) {
        const el = this.el;
        const restoreSelection = saveSelection();
        try {
            this._push = true;
            this.rStack = [];
            el.setAttribute('aria-hidden', 'false');
            el.focus();
            document.execCommand?.('insertText', false, '.');
            const tlen = this.el.innerText.length;
            if (tlen - 1 === this.uStack.length)
                this.uStack.push(undo);
        }
        finally {
            el.blur();
            this._push = false;
            el.setAttribute('aria-hidden', 'true');
            restoreSelection?.();
        }
    }
    undo() {
        document?.execCommand?.('undo');
    }
    redo() {
        document?.execCommand?.('redo');
    }
    /** -------------------------------------------------- {@link UiLifeCycles} */
    start() {
        const el = (this.el = document.createElement('div'));
        el.tabIndex = -1;
        el.contentEditable = 'true';
        el.setAttribute('aria-hidden', 'true');
        const style = el.style;
        style.pointerEvents = 'none';
        style.position = 'fixed';
        style.fontSize = '1px';
        style.top = '-1000px';
        style.opacity = '0';
        const body = document.body;
        body.appendChild(el);
        el.addEventListener('focus', this.onFocus);
        el.addEventListener('input', this.onInput);
        return () => {
            body.removeChild(el);
            el.removeEventListener('focus', this.onFocus);
            el.removeEventListener('input', this.onInput);
        };
    }
    onFocus = () => {
        const el = this.el;
        setTimeout(() => el.blur(), 0);
    };
    onInput = () => {
        const tlen = this.el.innerText.length;
        if (!this._push) {
            const { uStack: undo, rStack: redo } = this;
            while (undo.length && undo.length > tlen)
                this._undo();
            while (redo.length && undo.length < tlen)
                this._redo();
        }
    };
}
//# sourceMappingURL=WebUndo.js.map