import { keydownHandler } from 'prosemirror-keymap';
import { AllSelection, Plugin, PluginKey, TextSelection, } from 'prosemirror-state';
// @ts-ignore // TODO: fix cjs build
import { hasParentNode } from 'prosemirror-utils';
import { isCodeBlock } from "../../../utils/nodes.js";
import { TooltipView } from "./tooltip.js";
export const SelectionContext = (builder, opts) => {
    const { config } = opts;
    if (Array.isArray(config) && config.length > 0) {
        builder.addPlugin(({ actions }) => new Plugin(new SelectionTooltip(actions, config, builder.logger, opts)));
    }
};
const HideMetaKey = 'hide-selection-menu';
export const hideSelectionMenu = (tr) => {
    return tr.setMeta(HideMetaKey, true);
};
const pluginKey = new PluginKey('selection-context');
class SelectionTooltip {
    destroyed = false;
    tooltip;
    hideTimeoutRef = null;
    _isMousePressed = false;
    constructor(actions, menuConfig, logger, options) {
        this.tooltip = new TooltipView(actions, menuConfig, logger, options);
    }
    get key() {
        return pluginKey;
    }
    get props() {
        return {
            // same as keymap({})
            handleKeyDown: 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) {
        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 TextSelection || selection instanceof AllSelection)) {
            this.tooltip.hide(view);
            return;
        }
        if (
        // Hide tooltip when one side of selection is inside a codeblock
        isCodeBlock(selection.$from.parent) ||
            isCodeBlock(selection.$to.parent) ||
            // or when selection is inside node where context menu is disabled
            hasParentNode((node) => node.type.spec.selectionContext === false)(selection)) {
            this.tooltip.hide(view);
            return;
        }
        this.tooltip.show(view, {
            onOpenChange: (_open, _event, reason) => {
                if (reason !== 'escape-key')
                    this.scheduleTooltipHiding(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
