"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hideSelectionMenu = exports.SelectionContext = void 0;
const prosemirror_keymap_1 = require("prosemirror-keymap");
const prosemirror_state_1 = require("prosemirror-state");
// @ts-ignore // TODO: fix cjs build
const prosemirror_utils_1 = require("prosemirror-utils");
const nodes_1 = require("../../../utils/nodes.js");
const tooltip_1 = require("./tooltip.js");
const SelectionContext = (builder, opts) => {
    const { config } = opts;
    if (Array.isArray(config) && config.length > 0) {
        builder.addPlugin(({ actions }) => new prosemirror_state_1.Plugin(new SelectionTooltip(actions, config, builder.logger, opts)));
    }
};
exports.SelectionContext = SelectionContext;
const HideMetaKey = 'hide-selection-menu';
const hideSelectionMenu = (tr) => {
    return tr.setMeta(HideMetaKey, true);
};
exports.hideSelectionMenu = hideSelectionMenu;
const pluginKey = new prosemirror_state_1.PluginKey('selection-context');
class SelectionTooltip {
    destroyed = false;
    tooltip;
    editorView = null;
    hideTimeoutRef = null;
    _isMousePressed = false;
    constructor(actions, menuConfig, logger, options) {
        this.tooltip = new tooltip_1.TooltipView(actions, menuConfig, logger, {
            ...options,
            onPopupOpenChange: (_open, _event, reason) => {
                if (reason !== 'escape-key' && this.editorView)
                    this.scheduleTooltipHiding(this.editorView);
            },
        });
    }
    get key() {
        return pluginKey;
    }
    get props() {
        return {
            // same as keymap({})
            handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
                // hide context menu when Esc was pressed
                Escape: (_state, _dispatch, view) => {
                    if (this.tooltip.isTooltipOpen) {
                        this.tooltip.hide(view);
                        return true;
                    }
                    return false;
                },
            }),
            handleDOMEvents: {
                mousedown: (view) => {
                    const startState = {
                        doc: view.state.doc,
                        selection: view.state.selection,
                    };
                    this._isMousePressed = true;
                    this.cancelTooltipHiding();
                    this.tooltip.hide(view);
                    const onMouseUp = () => {
                        if (this.destroyed)
                            return;
                        this._isMousePressed = false;
                        this.update(view, startState);
                    };
                    document.addEventListener('mouseup', onMouseUp, { once: true });
                },
            },
        };
    }
    get state() {
        return {
            init: () => ({ disabled: false }),
            apply(tr) {
                return { disabled: Boolean(tr.getMeta(HideMetaKey)) };
            },
        };
    }
    view(view) {
        this.update(view);
        return {
            update: this.update.bind(this),
            destroy: () => {
                this.destroyed = true;
                this.cancelTooltipHiding();
                this.tooltip.destroy();
            },
        };
    }
    update(view, prevState) {
        this.editorView = view;
        if (this._isMousePressed)
            return;
        this.cancelTooltipHiding();
        const hideFromTr = pluginKey.getState(view.state)?.disabled;
        // Don't show tooltip if editor not mounted to the DOM
        if (hideFromTr || !view.dom.parentNode) {
            this.tooltip.hide(view);
            return;
        }
        const { state } = view;
        // Don't do anything if the document/selection didn't change
        if (prevState && prevState.doc.eq(state.doc) && prevState.selection.eq(state.selection)) {
            return;
        }
        // Don't show tooltip if editor out of focus
        if (!view.hasFocus()) {
            this.tooltip.hide(view);
            return;
        }
        const { selection } = state;
        // Hide the tooltip if the selection is empty
        if (selection.empty ||
            !(selection instanceof prosemirror_state_1.TextSelection || selection instanceof prosemirror_state_1.AllSelection)) {
            this.tooltip.hide(view);
            return;
        }
        if (
        // Hide tooltip when one side of selection is inside a codeblock
        (0, nodes_1.isCodeBlock)(selection.$from.parent) ||
            (0, nodes_1.isCodeBlock)(selection.$to.parent) ||
            // or when selection is inside node where context menu is disabled
            (0, prosemirror_utils_1.hasParentNode)((node) => node.type.spec.selectionContext === false)(selection)) {
            this.tooltip.hide(view);
            return;
        }
        this.tooltip.show(view);
    }
    scheduleTooltipHiding(view) {
        this.hideTimeoutRef = setTimeout(() => {
            // hide tooltip if view is out of focus after 30 ms
            if (!view.hasFocus()) {
                this.tooltip.hide(view);
            }
        }, 30);
    }
    cancelTooltipHiding() {
        if (this.hideTimeoutRef !== null) {
            clearTimeout(this.hideTimeoutRef);
            this.hideTimeoutRef = null;
        }
    }
}
//# sourceMappingURL=index.js.map
