var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var AffineLinkedDocWidget_1;
import { assertExists, DisposableGroup, throttle, } from '@blockeditor/global/utils';
import { WidgetElement } from '@blockeditor/lit';
import { customElement } from 'lit/decorators.js';
import { isControlledKeyboardEvent } from '../../../_common/utils/event.js';
import { matchFlavours } from '../../../_common/utils/index.js';
import { getInlineEditorByModel, getViewportElement, } from '../../../_common/utils/query.js';
import { getCurrentNativeRange } from '../../../_common/utils/selection.js';
import { getPopperPosition } from '../../../page-block/utils/position.js';
import { getMenus } from './config.js';
import { LinkedDocPopover } from './linked-doc-popover.js';
export function showLinkedDocPopover({ editorHost, model, range, container = document.body, abortController = new AbortController(), options, triggerKey, }) {
    const disposables = new DisposableGroup();
    abortController.signal.addEventListener('abort', () => disposables.dispose());
    const linkedDoc = new LinkedDocPopover(editorHost, model, abortController);
    linkedDoc.options = options;
    linkedDoc.triggerKey = triggerKey;
    // Mount
    container.appendChild(linkedDoc);
    disposables.add(() => linkedDoc.remove());
    // Handle position
    const updatePosition = throttle(() => {
        const linkedDocElement = linkedDoc.linkedDocElement;
        assertExists(linkedDocElement, 'You should render the linked page node even if no position');
        const position = getPopperPosition(linkedDocElement, range);
        linkedDoc.updatePosition(position);
    }, 10);
    disposables.addFromEvent(window, 'resize', updatePosition);
    const scrollContainer = getViewportElement(editorHost);
    if (scrollContainer) {
        // Note: in edgeless mode, the scroll container is not exist!
        disposables.addFromEvent(scrollContainer, 'scroll', updatePosition, {
            passive: true,
        });
    }
    // Wait for node to be mounted
    setTimeout(updatePosition);
    disposables.addFromEvent(window, 'mousedown', (e) => {
        if (e.target === linkedDoc)
            return;
        abortController.abort();
    });
    return linkedDoc;
}
export const AFFINE_LINKED_DOC_WIDGET = 'affine-linked-doc-widget';
let AffineLinkedDocWidget = AffineLinkedDocWidget_1 = class AffineLinkedDocWidget extends WidgetElement {
    constructor() {
        super(...arguments);
        this.options = AffineLinkedDocWidget_1.DEFAULT_OPTIONS;
        this.showLinkedDoc = (model, triggerKey) => {
            const curRange = getCurrentNativeRange();
            showLinkedDocPopover({
                editorHost: this.host,
                model,
                range: curRange,
                options: this.options,
                triggerKey,
            });
        };
        this._onKeyDown = (ctx) => {
            const eventState = ctx.get('keyboardState');
            const event = eventState.raw;
            if (isControlledKeyboardEvent(event) || event.key.length !== 1)
                return;
            const text = this.host.selection.value.find(selection => selection.is('text'));
            if (!text) {
                return;
            }
            const model = this.host.page.getBlockById(text.blockId);
            if (!model) {
                return;
            }
            if (matchFlavours(model, this.options.ignoreBlockTypes))
                return;
            const inlineEditor = getInlineEditorByModel(this.host, model);
            if (!inlineEditor)
                return;
            const inlineRange = inlineEditor.getInlineRange();
            if (!inlineRange)
                return;
            if (inlineRange.length > 0) {
                // When select text and press `[[` should not trigger transform,
                // since it will break the bracket complete.
                // Expected `[[selected text]]` instead of `@selected text]]`
                return;
            }
            const [leafStart, offsetStart] = inlineEditor.getTextPoint(inlineRange.index);
            const prefixText = leafStart.textContent
                ? leafStart.textContent.slice(0, offsetStart)
                : '';
            const matchedKey = this.options.triggerKeys.find(triggerKey => (prefixText + event.key).endsWith(triggerKey));
            if (!matchedKey)
                return;
            const primaryTriggerKey = this.options.triggerKeys[0];
            inlineEditor.slots.inlineRangeApply.once(() => {
                if (this.options.convertTriggerKey && primaryTriggerKey !== matchedKey) {
                    // Convert to the primary trigger key
                    // e.g. [[ -> @
                    const startIdxBeforeMatchKey = inlineRange.index - (matchedKey.length - 1);
                    inlineEditor.deleteText({
                        index: startIdxBeforeMatchKey,
                        length: matchedKey.length,
                    });
                    inlineEditor.insertText({ index: startIdxBeforeMatchKey, length: 0 }, primaryTriggerKey);
                    inlineEditor.setInlineRange({
                        index: startIdxBeforeMatchKey + primaryTriggerKey.length,
                        length: 0,
                    });
                    inlineEditor.slots.inlineRangeApply.once(() => {
                        this.showLinkedDoc(model, primaryTriggerKey);
                    });
                    return;
                }
                this.showLinkedDoc(model, matchedKey);
            });
        };
    }
    connectedCallback() {
        super.connectedCallback();
        this.handleEvent('keyDown', this._onKeyDown);
    }
};
AffineLinkedDocWidget.DEFAULT_OPTIONS = {
    /**
     * The first item of the trigger keys will be the primary key
     */
    triggerKeys: ['@', '[[', '【【'],
    ignoreBlockTypes: ['affine:code'],
    /**
     * Convert trigger key to primary key (the first item of the trigger keys)
     */
    convertTriggerKey: true,
    getMenus,
};
AffineLinkedDocWidget = AffineLinkedDocWidget_1 = __decorate([
    customElement(AFFINE_LINKED_DOC_WIDGET)
], AffineLinkedDocWidget);
export { AffineLinkedDocWidget };
//# sourceMappingURL=index.js.map