"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.linkTooltipPlugin = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
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 prosemirror_view_1 = require("prosemirror-view");
const ErrorBoundary_1 = require("../../../../../react-utils/ErrorBoundary.js");
const marks_1 = require("../../../../../utils/marks.js");
const ReactRenderer_1 = require("../../../../behavior/ReactRenderer/index.js");
const LinkSpecs_1 = require("../../LinkSpecs/index.js");
const utils_1 = require("../../utils.js");
const TooltipView_1 = require("./TooltipView.js");
const className = 'pm-link-focus-deco';
const placement = ['bottom-start', 'bottom-end', 'top-start', 'top-end'];
function getTextNode(state) {
    if (!(state.selection instanceof prosemirror_state_1.TextSelection) ||
        !state.selection.empty ||
        !(0, marks_1.isMarkActive)(state, (0, LinkSpecs_1.linkType)(state.schema)))
        return null;
    const parent = (0, prosemirror_utils_1.findParentNode)(Boolean)(state.selection);
    if (!parent) {
        return null;
    }
    const textNodes = (0, prosemirror_utils_1.findChildrenByMark)(parent?.node, (0, LinkSpecs_1.linkType)(state.schema));
    const textNode = textNodes.find((n) => {
        const start = n.pos + parent.pos;
        const end = start + n.node.nodeSize;
        return start <= state.selection.from && end >= state.selection.from;
    });
    if (!textNode)
        return null;
    const absolutePos = textNode.pos + parent.pos + 1;
    return {
        ...textNode,
        absolutePos,
        parent,
        from: absolutePos,
        to: absolutePos + textNode.node.nodeSize,
    };
}
const linkTooltipPlugin = (deps) => {
    let viewTooltip = null;
    return new prosemirror_state_1.Plugin({
        view(view) {
            viewTooltip = new SelectionTooltip(view, deps);
            return viewTooltip;
        },
        props: {
            handleKeyDown: (0, prosemirror_keymap_1.keydownHandler)({
                Escape: () => viewTooltip?.onEscapeDown() ?? false,
            }),
            decorations(state) {
                const textNode = getTextNode(state);
                if (!textNode)
                    return prosemirror_view_1.DecorationSet.empty;
                const { from, to } = textNode;
                return prosemirror_view_1.DecorationSet.create(state.doc, [
                    prosemirror_view_1.Decoration.inline(from, to, {
                        class: `pm-node-selected ${className}`,
                    }),
                ]);
            },
        },
    });
};
exports.linkTooltipPlugin = linkTooltipPlugin;
class SelectionTooltip {
    normalizeUrl;
    view;
    show;
    textNode;
    textNodeRef;
    manualHidden = false;
    currentUrl = '';
    renderItem;
    constructor(view, deps) {
        this.normalizeUrl = (0, utils_1.normalizeUrlFactory)(deps);
        this.view = view;
        this.show = false;
        this.update(view);
    }
    update(view) {
        if (!view.dom.parentNode) {
            this.hideTooltip();
            return;
        }
        const { state } = view;
        this.textNode = getTextNode(state);
        const prevRef = this.textNodeRef;
        this.textNodeRef = this.view.dom.getElementsByClassName(className)[0];
        if (prevRef !== this.textNodeRef) {
            this.manualHidden = false;
        }
        if (this.manualHidden || !this.textNode || !this.textNodeRef) {
            this.hideTooltip();
            return;
        }
        this.showTooltip();
    }
    destroy() {
        this.show = false;
        this.renderItem?.remove();
        this.renderItem = undefined;
    }
    onEscapeDown() {
        if (this.show) {
            this.removePlaceholderLink(this.textNode);
            this.manualHidden = true;
            this.hideTooltip();
            return true;
        }
        return false;
    }
    getMarkAttrs() {
        const { textNode } = this;
        const linkMark = textNode && (0, marks_1.findMark)(textNode.node, (0, LinkSpecs_1.linkType)(this.view.state.schema));
        return linkMark?.attrs;
    }
    renderTooltip() {
        this.renderItem = this.renderItem ?? this.createRenderItem();
        this.renderItem.rerender();
    }
    hideTooltip() {
        this.show = false;
        this.renderTooltip();
    }
    showTooltip() {
        this.show = true;
        this.renderTooltip();
    }
    onOpenChange = (open, event, reason) => {
        if (open)
            return;
        if (reason === 'escape-key') {
            this.cancelPopup();
            return;
        }
        const target = event?.target;
        const isUndoRedoClick = Boolean(target?.closest('[data-toolbar-item="undo"], [data-toolbar-item="redo"]'));
        if (isUndoRedoClick) {
            this.manualHidden = true;
            this.hideTooltip();
            return;
        }
        this.onOutsideClick();
    };
    onOutsideClick = () => {
        const url = this.currentUrl.trim();
        if (!url) {
            this.removeLink();
            return;
        }
        this.changeAttrs({ href: url });
        this.hideTooltip();
        this.manualHidden = true;
    };
    cancelPopup() {
        this.removePlaceholderLink(this.textNode, { returnSelection: true });
        this.manualHidden = true;
        this.hideTooltip();
        this.view.focus();
    }
    removePlaceholderLink(textNode, opts) {
        if (textNode) {
            const { view } = this;
            const { state } = view;
            const attrs = (0, marks_1.findMark)(textNode.node, (0, LinkSpecs_1.linkType)(state.schema))?.attrs;
            if (attrs?.[LinkSpecs_1.LinkAttr.IsPlaceholder]) {
                const { from, to } = textNode;
                let tr = state.tr.removeMark(from, to, (0, LinkSpecs_1.linkType)(state.schema));
                if (opts?.returnSelection) {
                    tr = tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, from, to));
                }
                view.dispatch(tr);
            }
        }
    }
    changeAttrs({ href }) {
        const { view, textNode } = this;
        if (!textNode)
            return;
        const normalizeResult = this.normalizeUrl(href);
        if (normalizeResult) {
            const { url } = normalizeResult;
            const { from, to } = textNode;
            const tr = view.state.tr;
            tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, tr.mapping.map(to)));
            tr.addMark(from, to, (0, LinkSpecs_1.linkType)(view.state.schema).create({ href: url }));
            view.dispatch(tr);
        }
    }
    removeLink() {
        const { view, textNode } = this;
        if (!textNode)
            return;
        const { from, to } = textNode;
        const tr = view.state.tr.removeMark(from, to, (0, LinkSpecs_1.linkType)(view.state.schema));
        view.dispatch(tr);
        this.manualHidden = true;
        this.hideTooltip();
        view.focus();
    }
    onUrlChange(url) {
        this.currentUrl = url;
    }
    onOpenInNewTab() {
        this.view.focus();
    }
    createRenderItem() {
        return (0, ReactRenderer_1.getReactRendererFromState)(this.view.state).createItem('link-tooltip', () => ((0, jsx_runtime_1.jsx)(ErrorBoundary_1.ErrorLoggerBoundary, { children: (0, jsx_runtime_1.jsx)(SelectionTooltipView, { show: this.show, domElem: this.textNodeRef, onCancel: this.cancelPopup.bind(this), attrs: this.getMarkAttrs(), onChange: this.changeAttrs.bind(this), onRemove: this.removeLink.bind(this), onOpenChange: this.onOpenChange, onUrlChange: this.onUrlChange.bind(this), onOpenInNewTab: this.onOpenInNewTab.bind(this) }) })));
    }
}
const SelectionTooltipView = (props) => {
    const { show } = props;
    if (!show)
        return null;
    const { domElem, onChange, onCancel, onRemove, onOpenChange, onUrlChange, onOpenInNewTab, attrs = {}, } = props;
    const href = attrs[LinkSpecs_1.LinkAttr.Href];
    const autoFocus = Boolean(attrs[LinkSpecs_1.LinkAttr.IsPlaceholder]);
    return ((0, jsx_runtime_1.jsx)(TooltipView_1.Link, { href: href ?? '', anchorElement: domElem, placement: placement, onOpenChange: onOpenChange, onChange: onChange, onCancel: onCancel, onRemove: onRemove, onUrlChange: onUrlChange, autoFocus: autoFocus, onOpenInNewTab: onOpenInNewTab }, href));
};
//# sourceMappingURL=index.js.map
