import { __esDecorate, __runInitializers } from "tslib";
import { html, LitElement, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import reactive from '../../../decorators/reactive.js';
import '../../../md/chip/ui-chip.js';
/**
 * A NodeFilter mask that includes text nodes and elements.
 * It is used with the NodeWalker
 */
const ShowMask = NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT;
let MentionTextArea = (() => {
    let _classSuper = LitElement;
    let _instanceExtraInitializers = [];
    let _label_decorators;
    let _label_initializers = [];
    let _label_extraInitializers = [];
    let _supportingText_decorators;
    let _supportingText_initializers = [];
    let _supportingText_extraInitializers = [];
    let _disabled_decorators;
    let _disabled_initializers = [];
    let _disabled_extraInitializers = [];
    let _invalid_decorators;
    let _invalid_initializers = [];
    let _invalid_extraInitializers = [];
    let _name_decorators;
    let _name_initializers = [];
    let _name_extraInitializers = [];
    let _required_decorators;
    let _required_initializers = [];
    let _required_extraInitializers = [];
    let _placeholder_decorators;
    let _placeholder_initializers = [];
    let _placeholder_extraInitializers = [];
    let _set_value_decorators;
    let _suggestions_decorators;
    let _suggestions_initializers = [];
    let _suggestions_extraInitializers = [];
    let _mentionTrigger_decorators;
    let _mentionTrigger_initializers = [];
    let _mentionTrigger_extraInitializers = [];
    let _minQueryLength_decorators;
    let _minQueryLength_initializers = [];
    let _minQueryLength_extraInitializers = [];
    let _editorElement_decorators;
    let _editorElement_initializers = [];
    let _editorElement_extraInitializers = [];
    let _suggestionsPopover_decorators;
    let _suggestionsPopover_initializers = [];
    let _suggestionsPopover_extraInitializers = [];
    let _isShowingSuggestions_decorators;
    let _isShowingSuggestions_initializers = [];
    let _isShowingSuggestions_extraInitializers = [];
    let _filteredSuggestions_decorators;
    let _filteredSuggestions_initializers = [];
    let _filteredSuggestions_extraInitializers = [];
    let _selectedSuggestionIndex_decorators;
    let _selectedSuggestionIndex_initializers = [];
    let _selectedSuggestionIndex_extraInitializers = [];
    let _hasContent_decorators;
    let _hasContent_initializers = [];
    let _hasContent_extraInitializers = [];
    let _isLabelFloating_decorators;
    let _isLabelFloating_initializers = [];
    let _isLabelFloating_extraInitializers = [];
    let _isEditorFocus_decorators;
    let _isEditorFocus_initializers = [];
    let _isEditorFocus_extraInitializers = [];
    return class MentionTextArea extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _label_decorators = [property({ type: String })];
            _supportingText_decorators = [property({ type: String, attribute: 'supporting-text' })];
            _disabled_decorators = [property({ type: Boolean, reflect: true })];
            _invalid_decorators = [property({ type: Boolean, reflect: true })];
            _name_decorators = [property({ type: String })];
            _required_decorators = [property({ type: Boolean })];
            _placeholder_decorators = [property({ type: String })];
            _set_value_decorators = [property({ type: String })];
            _suggestions_decorators = [property({ type: Array, attribute: false })];
            _mentionTrigger_decorators = [property({ type: String, attribute: 'mention-trigger' })];
            _minQueryLength_decorators = [property({ type: Number, attribute: 'min-query-length' })];
            _editorElement_decorators = [query('.editor')];
            _suggestionsPopover_decorators = [query('.suggestions-popover')];
            _isShowingSuggestions_decorators = [state(), reactive()];
            _filteredSuggestions_decorators = [reactive()];
            _selectedSuggestionIndex_decorators = [state()];
            _hasContent_decorators = [state()];
            _isLabelFloating_decorators = [state()];
            _isEditorFocus_decorators = [state()];
            __esDecorate(this, null, _label_decorators, { kind: "accessor", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
            __esDecorate(this, null, _supportingText_decorators, { kind: "accessor", name: "supportingText", static: false, private: false, access: { has: obj => "supportingText" in obj, get: obj => obj.supportingText, set: (obj, value) => { obj.supportingText = value; } }, metadata: _metadata }, _supportingText_initializers, _supportingText_extraInitializers);
            __esDecorate(this, null, _disabled_decorators, { kind: "accessor", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, get: obj => obj.disabled, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, _disabled_initializers, _disabled_extraInitializers);
            __esDecorate(this, null, _invalid_decorators, { kind: "accessor", name: "invalid", static: false, private: false, access: { has: obj => "invalid" in obj, get: obj => obj.invalid, set: (obj, value) => { obj.invalid = value; } }, metadata: _metadata }, _invalid_initializers, _invalid_extraInitializers);
            __esDecorate(this, null, _name_decorators, { kind: "accessor", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
            __esDecorate(this, null, _required_decorators, { kind: "accessor", name: "required", static: false, private: false, access: { has: obj => "required" in obj, get: obj => obj.required, set: (obj, value) => { obj.required = value; } }, metadata: _metadata }, _required_initializers, _required_extraInitializers);
            __esDecorate(this, null, _placeholder_decorators, { kind: "accessor", name: "placeholder", static: false, private: false, access: { has: obj => "placeholder" in obj, get: obj => obj.placeholder, set: (obj, value) => { obj.placeholder = value; } }, metadata: _metadata }, _placeholder_initializers, _placeholder_extraInitializers);
            __esDecorate(this, null, _set_value_decorators, { kind: "setter", name: "value", static: false, private: false, access: { has: obj => "value" in obj, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _suggestions_decorators, { kind: "accessor", name: "suggestions", static: false, private: false, access: { has: obj => "suggestions" in obj, get: obj => obj.suggestions, set: (obj, value) => { obj.suggestions = value; } }, metadata: _metadata }, _suggestions_initializers, _suggestions_extraInitializers);
            __esDecorate(this, null, _mentionTrigger_decorators, { kind: "accessor", name: "mentionTrigger", static: false, private: false, access: { has: obj => "mentionTrigger" in obj, get: obj => obj.mentionTrigger, set: (obj, value) => { obj.mentionTrigger = value; } }, metadata: _metadata }, _mentionTrigger_initializers, _mentionTrigger_extraInitializers);
            __esDecorate(this, null, _minQueryLength_decorators, { kind: "accessor", name: "minQueryLength", static: false, private: false, access: { has: obj => "minQueryLength" in obj, get: obj => obj.minQueryLength, set: (obj, value) => { obj.minQueryLength = value; } }, metadata: _metadata }, _minQueryLength_initializers, _minQueryLength_extraInitializers);
            __esDecorate(this, null, _editorElement_decorators, { kind: "accessor", name: "editorElement", static: false, private: false, access: { has: obj => "editorElement" in obj, get: obj => obj.editorElement, set: (obj, value) => { obj.editorElement = value; } }, metadata: _metadata }, _editorElement_initializers, _editorElement_extraInitializers);
            __esDecorate(this, null, _suggestionsPopover_decorators, { kind: "accessor", name: "suggestionsPopover", static: false, private: false, access: { has: obj => "suggestionsPopover" in obj, get: obj => obj.suggestionsPopover, set: (obj, value) => { obj.suggestionsPopover = value; } }, metadata: _metadata }, _suggestionsPopover_initializers, _suggestionsPopover_extraInitializers);
            __esDecorate(this, null, _isShowingSuggestions_decorators, { kind: "accessor", name: "isShowingSuggestions", static: false, private: false, access: { has: obj => "isShowingSuggestions" in obj, get: obj => obj.isShowingSuggestions, set: (obj, value) => { obj.isShowingSuggestions = value; } }, metadata: _metadata }, _isShowingSuggestions_initializers, _isShowingSuggestions_extraInitializers);
            __esDecorate(this, null, _filteredSuggestions_decorators, { kind: "accessor", name: "filteredSuggestions", static: false, private: false, access: { has: obj => "filteredSuggestions" in obj, get: obj => obj.filteredSuggestions, set: (obj, value) => { obj.filteredSuggestions = value; } }, metadata: _metadata }, _filteredSuggestions_initializers, _filteredSuggestions_extraInitializers);
            __esDecorate(this, null, _selectedSuggestionIndex_decorators, { kind: "accessor", name: "selectedSuggestionIndex", static: false, private: false, access: { has: obj => "selectedSuggestionIndex" in obj, get: obj => obj.selectedSuggestionIndex, set: (obj, value) => { obj.selectedSuggestionIndex = value; } }, metadata: _metadata }, _selectedSuggestionIndex_initializers, _selectedSuggestionIndex_extraInitializers);
            __esDecorate(this, null, _hasContent_decorators, { kind: "accessor", name: "hasContent", static: false, private: false, access: { has: obj => "hasContent" in obj, get: obj => obj.hasContent, set: (obj, value) => { obj.hasContent = value; } }, metadata: _metadata }, _hasContent_initializers, _hasContent_extraInitializers);
            __esDecorate(this, null, _isLabelFloating_decorators, { kind: "accessor", name: "isLabelFloating", static: false, private: false, access: { has: obj => "isLabelFloating" in obj, get: obj => obj.isLabelFloating, set: (obj, value) => { obj.isLabelFloating = value; } }, metadata: _metadata }, _isLabelFloating_initializers, _isLabelFloating_extraInitializers);
            __esDecorate(this, null, _isEditorFocus_decorators, { kind: "accessor", name: "isEditorFocus", static: false, private: false, access: { has: obj => "isEditorFocus" in obj, get: obj => obj.isEditorFocus, set: (obj, value) => { obj.isEditorFocus = value; } }, metadata: _metadata }, _isEditorFocus_initializers, _isEditorFocus_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        /**
         * Shadow root configuration for the component.
         * Uses 'open' mode for accessibility and delegates focus to enable proper focus management.
         */
        static shadowRootOptions = {
            mode: 'open',
            delegatesFocus: true,
        };
        #label_accessor_storage = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _label_initializers, ''
        /**
         * Supporting text displayed below the input
         */
        ));
        /**
         * The label text displayed as placeholder/floating label
         */
        get label() { return this.#label_accessor_storage; }
        set label(value) { this.#label_accessor_storage = value; }
        #supportingText_accessor_storage = (__runInitializers(this, _label_extraInitializers), __runInitializers(this, _supportingText_initializers, ''
        /**
         * Whether the component is disabled
         */
        ));
        /**
         * Supporting text displayed below the input
         */
        get supportingText() { return this.#supportingText_accessor_storage; }
        set supportingText(value) { this.#supportingText_accessor_storage = value; }
        #disabled_accessor_storage = (__runInitializers(this, _supportingText_extraInitializers), __runInitializers(this, _disabled_initializers, false
        /**
         * Whether the component is in an invalid state
         */
        ));
        /**
         * Whether the component is disabled
         */
        get disabled() { return this.#disabled_accessor_storage; }
        set disabled(value) { this.#disabled_accessor_storage = value; }
        #invalid_accessor_storage = (__runInitializers(this, _disabled_extraInitializers), __runInitializers(this, _invalid_initializers, false
        /**
         * The name attribute for form integration
         */
        ));
        /**
         * Whether the component is in an invalid state
         */
        get invalid() { return this.#invalid_accessor_storage; }
        set invalid(value) { this.#invalid_accessor_storage = value; }
        #name_accessor_storage = (__runInitializers(this, _invalid_extraInitializers), __runInitializers(this, _name_initializers, ''
        /**
         * Whether the input is required
         */
        ));
        /**
         * The name attribute for form integration
         */
        get name() { return this.#name_accessor_storage; }
        set name(value) { this.#name_accessor_storage = value; }
        #required_accessor_storage = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _required_initializers, false
        /**
         * Placeholder text shown when input is empty
         */
        ));
        /**
         * Whether the input is required
         */
        get required() { return this.#required_accessor_storage; }
        set required(value) { this.#required_accessor_storage = value; }
        #placeholder_accessor_storage = (__runInitializers(this, _required_extraInitializers), __runInitializers(this, _placeholder_initializers, ''));
        /**
         * Placeholder text shown when input is empty
         */
        get placeholder() { return this.#placeholder_accessor_storage; }
        set placeholder(value) { this.#placeholder_accessor_storage = value; }
        get value() {
            return this._value;
        }
        set value(newValue) {
            const oldValue = this._value;
            if (newValue === this._value)
                return; // No change, skip update
            this._value = newValue;
            this.requestUpdate('value', oldValue);
            // Only sync editor from value when set externally and element is ready
            if (this.editorElement) {
                this.syncEditorFromValue();
            }
        }
        #suggestions_accessor_storage = (__runInitializers(this, _placeholder_extraInitializers), __runInitializers(this, _suggestions_initializers, []
        /**
         * Character that triggers mention suggestions (default: '@')
         */
        ));
        /**
         * Available suggestions for mentions
         */
        get suggestions() { return this.#suggestions_accessor_storage; }
        set suggestions(value) { this.#suggestions_accessor_storage = value; }
        #mentionTrigger_accessor_storage = (__runInitializers(this, _suggestions_extraInitializers), __runInitializers(this, _mentionTrigger_initializers, '@'
        /**
         * Minimum characters after trigger to show suggestions
         */
        ));
        /**
         * Character that triggers mention suggestions (default: '@')
         */
        get mentionTrigger() { return this.#mentionTrigger_accessor_storage; }
        set mentionTrigger(value) { this.#mentionTrigger_accessor_storage = value; }
        #minQueryLength_accessor_storage = (__runInitializers(this, _mentionTrigger_extraInitializers), __runInitializers(this, _minQueryLength_initializers, 0));
        /**
         * Minimum characters after trigger to show suggestions
         */
        get minQueryLength() { return this.#minQueryLength_accessor_storage; }
        set minQueryLength(value) { this.#minQueryLength_accessor_storage = value; }
        #editorElement_accessor_storage = (__runInitializers(this, _minQueryLength_extraInitializers), __runInitializers(this, _editorElement_initializers, void 0));
        get editorElement() { return this.#editorElement_accessor_storage; }
        set editorElement(value) { this.#editorElement_accessor_storage = value; }
        #suggestionsPopover_accessor_storage = (__runInitializers(this, _editorElement_extraInitializers), __runInitializers(this, _suggestionsPopover_initializers, void 0));
        get suggestionsPopover() { return this.#suggestionsPopover_accessor_storage; }
        set suggestionsPopover(value) { this.#suggestionsPopover_accessor_storage = value; }
        #isShowingSuggestions_accessor_storage = (__runInitializers(this, _suggestionsPopover_extraInitializers), __runInitializers(this, _isShowingSuggestions_initializers, false));
        get isShowingSuggestions() { return this.#isShowingSuggestions_accessor_storage; }
        set isShowingSuggestions(value) { this.#isShowingSuggestions_accessor_storage = value; }
        #filteredSuggestions_accessor_storage = (__runInitializers(this, _isShowingSuggestions_extraInitializers), __runInitializers(this, _filteredSuggestions_initializers, []));
        get filteredSuggestions() { return this.#filteredSuggestions_accessor_storage; }
        set filteredSuggestions(value) { this.#filteredSuggestions_accessor_storage = value; }
        #selectedSuggestionIndex_accessor_storage = (__runInitializers(this, _filteredSuggestions_extraInitializers), __runInitializers(this, _selectedSuggestionIndex_initializers, 0));
        get selectedSuggestionIndex() { return this.#selectedSuggestionIndex_accessor_storage; }
        set selectedSuggestionIndex(value) { this.#selectedSuggestionIndex_accessor_storage = value; }
        #hasContent_accessor_storage = (__runInitializers(this, _selectedSuggestionIndex_extraInitializers), __runInitializers(this, _hasContent_initializers, false));
        get hasContent() { return this.#hasContent_accessor_storage; }
        set hasContent(value) { this.#hasContent_accessor_storage = value; }
        #isLabelFloating_accessor_storage = (__runInitializers(this, _hasContent_extraInitializers), __runInitializers(this, _isLabelFloating_initializers, false));
        get isLabelFloating() { return this.#isLabelFloating_accessor_storage; }
        set isLabelFloating(value) { this.#isLabelFloating_accessor_storage = value; }
        #isEditorFocus_accessor_storage = (__runInitializers(this, _isLabelFloating_extraInitializers), __runInitializers(this, _isEditorFocus_initializers, false));
        get isEditorFocus() { return this.#isEditorFocus_accessor_storage; }
        set isEditorFocus(value) { this.#isEditorFocus_accessor_storage = value; }
        currentMentionQuery = (__runInitializers(this, _isEditorFocus_extraInitializers), '');
        currentMentionStart = -1;
        mentionMap = new Map();
        mutationObserver;
        _value = ''; // Internal value storage
        /**
         * A read-only list of the names of the fields currently mentioned in the textarea.
         */
        get mentions() {
            const dependencies = new Set();
            if (!this.value) {
                return [];
            }
            const regex = /@\{([^}]+)\}/g;
            let match;
            while ((match = regex.exec(this.value)) !== null) {
                dependencies.add(match[1]);
            }
            return Array.from(dependencies);
        }
        connectedCallback() {
            super.connectedCallback();
            // Setup mutation observer to watch for changes in the editor
            this.mutationObserver = new MutationObserver(() => {
                this.syncValueFromEditor();
            });
        }
        disconnectedCallback() {
            super.disconnectedCallback();
            this.mutationObserver?.disconnect();
        }
        firstUpdated() {
            // Start observing mutations in the editor
            if (this.editorElement && this.mutationObserver) {
                this.mutationObserver.observe(this.editorElement, {
                    childList: true,
                    subtree: true,
                    characterData: true,
                });
            }
            // Setup initial content
            this.updateComplete.then(() => {
                this.syncEditorFromValue();
            });
        }
        willUpdate(changedProperties) {
            super.willUpdate(changedProperties);
            // No need to sync editor from value here since setter handles it
            if (changedProperties.has('suggestions')) {
                this.updateFilteredSuggestions();
            }
            if (changedProperties.has('selectedSuggestionIndex')) {
                const index = this.selectedSuggestionIndex;
                if (index >= 0) {
                    this.suggestionsPopover?.querySelector(`.suggestion-item:nth-child(${index + 1})`)?.scrollIntoView({
                        behavior: 'smooth',
                        block: 'nearest',
                    });
                }
            }
        }
        /**
         * Get the plain text content without field references
         * @returns The plain text content with field names instead of references
         */
        getPlainText() {
            let text = this.value;
            // Replace field references with their display names
            text = text.replace(/@\{([^}]+)\}/g, (match, fieldId) => {
                const field = this.suggestions.find((f) => f.id === fieldId);
                return field ? field.label : fieldId;
            });
            return text;
        }
        /**
         * Sets the caret position at the beginning of a specific text node
         */
        setCaretPositionAtTextNode(textNode, offset = 0) {
            const selection = window.getSelection();
            if (!selection)
                return;
            const range = document.createRange();
            range.setStart(textNode, offset);
            range.setEnd(textNode, offset);
            selection.removeAllRanges();
            selection.addRange(range);
        }
        /**
         * Synchronizes the value property from the editor content
         */
        syncValueFromEditor() {
            const newValue = this.getValueFromEditor();
            if (newValue !== this._value) {
                // Update internal value directly to avoid triggering setter
                this._value = newValue;
                this.requestUpdate('value');
                this.dispatchEvent(new Event('input', { bubbles: true }));
            }
            this.updateContentState();
        }
        /**
         * Gets the value from editor content, converting chips to @{mention} format
         */
        getValueFromEditor() {
            const childNodes = Array.from(this.editorElement.childNodes);
            let result = '';
            for (const node of childNodes) {
                if (node.nodeType === Node.TEXT_NODE) {
                    result += node.textContent || '';
                }
                else if (node.nodeType === Node.ELEMENT_NODE) {
                    const element = node;
                    if (element.classList.contains('mention-chip')) {
                        const mentionId = element.getAttribute('data-mention-id');
                        if (mentionId) {
                            result += `@{${mentionId}}`;
                        }
                    }
                    else {
                        result += element.textContent || '';
                    }
                }
            }
            return result;
        }
        /**
         * Synchronizes the editor content from the value property
         */
        syncEditorFromValue() {
            if (!this.editorElement)
                return;
            const fragments = this.parseValueToFragments(this._value);
            this.editorElement.innerHTML = '';
            for (const fragment of fragments) {
                if (fragment.type === 'text') {
                    this.editorElement.appendChild(document.createTextNode(fragment.content));
                }
                else if (fragment.type === 'mention') {
                    if (fragment.mentionId) {
                        let mention = this.mentionMap.get(fragment.mentionId);
                        // If mention not in map, try to find it in suggestions
                        if (!mention) {
                            mention = this.suggestions.find((s) => s.id === fragment.mentionId);
                            if (mention) {
                                // Add to map for future use
                                this.mentionMap.set(mention.id, mention);
                            }
                        }
                        if (mention) {
                            const chipElement = this.createMentionChip(mention);
                            this.editorElement.appendChild(chipElement);
                        }
                        else {
                            // Fallback to text if mention not found anywhere
                            this.editorElement.appendChild(document.createTextNode(`@{${fragment.mentionId}}`));
                        }
                    }
                }
            }
            this.updateContentState();
        }
        /**
         * Parses value string into text and mention fragments
         */
        parseValueToFragments(value) {
            const fragments = [];
            const mentionRegex = /@\{([^}]+)\}/g;
            let lastIndex = 0;
            let match;
            while ((match = mentionRegex.exec(value)) !== null) {
                // Add text before mention
                if (match.index > lastIndex) {
                    fragments.push({
                        type: 'text',
                        content: value.substring(lastIndex, match.index),
                    });
                }
                // Add mention
                fragments.push({
                    type: 'mention',
                    content: match[0],
                    mentionId: match[1],
                });
                lastIndex = mentionRegex.lastIndex;
            }
            // Add remaining text
            if (lastIndex < value.length) {
                fragments.push({
                    type: 'text',
                    content: value.substring(lastIndex),
                });
            }
            return fragments;
        }
        /**
         * Creates a mention chip element
         */
        createMentionChip(mention) {
            const wrapper = document.createElement('span');
            wrapper.className = 'mention-chip';
            wrapper.setAttribute('data-mention-id', mention.id);
            wrapper.setAttribute('contenteditable', 'false');
            const chip = document.createElement('ui-chip');
            chip.setAttribute('type', 'input');
            chip.setAttribute('removable', 'true');
            chip.textContent = mention.label;
            chip.addEventListener('remove', () => {
                this.removeMention(wrapper, mention);
            });
            wrapper.appendChild(chip);
            return wrapper;
        }
        /**
         * Updates content state flags
         */
        updateContentState() {
            const hasAnyContent = this.editorElement.childNodes.length > 0 && (this.editorElement.textContent?.trim().length || 0) > 0;
            this.hasContent = hasAnyContent;
            this.isLabelFloating = hasAnyContent || this.isShowingSuggestions || this.isEditorFocus;
        }
        /**
         * Handles input events in the editor
         */
        handleEditorInput(event) {
            event.stopPropagation();
            // Check for mention trigger
            this.checkForMentionTrigger();
            // Sync value
            this.syncValueFromEditor();
        }
        /**
         * Handles keydown events in the editor
         */
        handleEditorKeyDown(event) {
            if (this.isShowingSuggestions) {
                this.handleSuggestionKeyDown(event);
            }
        }
        /**
         * Handles keydown events when suggestions are visible
         */
        handleSuggestionKeyDown(event) {
            switch (event.key) {
                case 'ArrowUp':
                    event.preventDefault();
                    this.selectedSuggestionIndex = Math.max(0, this.selectedSuggestionIndex - 1);
                    break;
                case 'ArrowDown':
                    event.preventDefault();
                    this.selectedSuggestionIndex = Math.min(this.filteredSuggestions.length - 1, this.selectedSuggestionIndex + 1);
                    break;
                case 'Enter':
                case 'Tab':
                    event.preventDefault();
                    this.selectSuggestion(this.filteredSuggestions[this.selectedSuggestionIndex]);
                    break;
                case 'Escape':
                    event.preventDefault();
                    this.hideSuggestions();
                    break;
            }
        }
        /**
         * Handles focus events
         */
        handleEditorFocus() {
            this.isEditorFocus = true;
            this.updateContentState();
        }
        /**
         * Handles blur events
         */
        handleEditorBlur(event) {
            // Don't hide suggestions if focus moved to suggestions popover
            if (event.relatedTarget && this.suggestionsPopover?.contains(event.relatedTarget)) {
                return;
            }
            this.isEditorFocus = false;
            this.hideSuggestions();
            this.updateContentState();
            this.dispatchEvent(new Event('change', { bubbles: true }));
        }
        handleEditorPaste(event) {
            // Prevent default paste behavior to handle mentions properly
            event.preventDefault();
            const pastedContent = event.clipboardData?.getData('text/plain');
            if (!pastedContent)
                return;
            const selection = window.getSelection();
            if (!selection || selection.rangeCount === 0)
                return;
            // Get the current range
            let range;
            if ('getComposedRanges' in selection && typeof selection.getComposedRanges === 'function' && this.shadowRoot) {
                const composedRanges = selection.getComposedRanges({ shadowRoots: [this.shadowRoot] });
                if (composedRanges.length === 0)
                    return;
                range = composedRanges[0];
            }
            else {
                range = selection.getRangeAt(0);
            }
            // Convert StaticRange to Range if needed for deleteContents
            let workingRange;
            if (range instanceof StaticRange) {
                workingRange = document.createRange();
                workingRange.setStart(range.startContainer, range.startOffset);
                workingRange.setEnd(range.endContainer, range.endOffset);
            }
            else {
                workingRange = range;
            }
            // Delete the current selection (if any)
            workingRange.deleteContents();
            // Insert the pasted text at the current position
            const textNode = document.createTextNode(pastedContent);
            workingRange.insertNode(textNode);
            // Position cursor at the end of the inserted text
            workingRange.setStartAfter(textNode);
            workingRange.setEndAfter(textNode);
            selection.removeAllRanges();
            selection.addRange(workingRange);
            // Hide suggestions if showing
            this.hideSuggestions();
            // Sync value and trigger events
            this.syncValueFromEditor();
        }
        /**
         * Checks if the current caret position indicates a mention trigger
         */
        checkForMentionTrigger() {
            const selection = window.getSelection();
            if (!selection || selection.rangeCount === 0) {
                this.hideSuggestions();
                return;
            }
            // Use getComposedRanges() for shadow DOM support, fallback to getRangeAt()
            let range;
            if ('getComposedRanges' in selection && typeof selection.getComposedRanges === 'function' && this.shadowRoot) {
                const composedRanges = selection.getComposedRanges({ shadowRoots: [this.shadowRoot] });
                if (composedRanges.length === 0) {
                    this.hideSuggestions();
                    return;
                }
                range = composedRanges[0];
            }
            else {
                range = selection.getRangeAt(0);
            }
            const caretContainer = range.startContainer;
            const caretOffset = range.startOffset;
            // Ensure the caret is within our editor element
            if (!this.editorElement.contains(caretContainer)) {
                this.hideSuggestions();
                return;
            }
            // Only look for triggers in text nodes
            if (caretContainer.nodeType !== Node.TEXT_NODE) {
                this.hideSuggestions();
                return;
            }
            const textContent = caretContainer.textContent || '';
            // Look backwards from caret to find mention trigger
            let mentionStart = -1;
            for (let i = caretOffset - 1; i >= 0; i--) {
                const char = textContent[i];
                if (char === this.mentionTrigger) {
                    mentionStart = i;
                    break;
                }
                if (char === ' ' || char === '\n') {
                    break;
                }
            }
            if (mentionStart >= 0) {
                const query = textContent.substring(mentionStart + 1, caretOffset);
                if (query.length >= this.minQueryLength) {
                    this.currentMentionQuery = query;
                    this.currentMentionStart = this.getGlobalTextPosition(caretContainer, mentionStart);
                    this.showSuggestions();
                    this.updateFilteredSuggestions();
                }
                else {
                    this.hideSuggestions();
                }
            }
            else {
                this.hideSuggestions();
            }
        }
        walkerNodeFilter(node) {
            if (node.nodeType === Node.TEXT_NODE) {
                return NodeFilter.FILTER_ACCEPT;
            }
            else if (node.nodeType === Node.ELEMENT_NODE) {
                const element = node;
                if (element.classList.contains('mention-chip')) {
                    // Accept mention chips as single characters
                    return NodeFilter.FILTER_ACCEPT;
                }
                else if (element.parentElement?.classList.contains('mention-chip')) {
                    // It's a chip, ignore the entire tree
                    return NodeFilter.FILTER_REJECT;
                }
            }
            return NodeFilter.FILTER_SKIP;
        }
        /**
         * Gets the global text position within the editor for a position within a text node
         */
        getGlobalTextPosition(textNode, offsetInNode) {
            let position = 0;
            const walker = document.createTreeWalker(this.editorElement, ShowMask, this.walkerNodeFilter);
            let node = walker.nextNode();
            while (node && node !== textNode) {
                if (node.nodeType === Node.TEXT_NODE) {
                    position += node.textContent?.length || 0;
                }
                else if (node.nodeType === Node.ELEMENT_NODE) {
                    const element = node;
                    if (element.classList?.contains('mention-chip')) {
                        position += 1; // Count chip as 1 character
                    }
                }
                node = walker.nextNode();
            }
            return position + offsetInNode;
        }
        /**
         * Finds the DOM node and offset that corresponds to a global text position
         */
        findNodeAtGlobalPosition(globalPosition) {
            let currentPosition = 0;
            const walker = document.createTreeWalker(this.editorElement, ShowMask, this.walkerNodeFilter);
            let node = walker.nextNode();
            while (node) {
                if (node.nodeType === Node.TEXT_NODE) {
                    const textLength = node.textContent?.length || 0;
                    if (currentPosition + textLength >= globalPosition) {
                        return {
                            node,
                            offset: globalPosition - currentPosition,
                        };
                    }
                    currentPosition += textLength;
                }
                else if (node.nodeType === Node.ELEMENT_NODE) {
                    const element = node;
                    if (element.classList?.contains('mention-chip')) {
                        if (currentPosition === globalPosition) {
                            // Position is right before the chip
                            const parentNode = element.parentNode;
                            if (parentNode) {
                                return {
                                    node: parentNode,
                                    offset: Array.from(parentNode.childNodes).indexOf(element),
                                };
                            }
                        }
                        currentPosition += 1; // Count chip as 1 character
                    }
                }
                node = walker.nextNode();
            }
            // Position is beyond the end, return the last position
            const lastChild = this.editorElement.lastChild;
            if (lastChild) {
                if (lastChild.nodeType === Node.TEXT_NODE) {
                    return {
                        node: lastChild,
                        offset: lastChild.textContent?.length || 0,
                    };
                }
                else {
                    return {
                        node: this.editorElement,
                        offset: this.editorElement.childNodes.length,
                    };
                }
            }
            return null;
        }
        /**
         * Shows the suggestions popover
         */
        showSuggestions() {
            if (!this.isShowingSuggestions) {
                this.isShowingSuggestions = true;
                this.selectedSuggestionIndex = 0;
                this.updateContentState();
                // Use Popover API to show the popover
                this.updateComplete.then(() => {
                    if (this.suggestionsPopover) {
                        this.suggestionsPopover.showPopover();
                        this.positionSuggestions();
                    }
                });
            }
        }
        /**
         * Hides the suggestions popover
         */
        hideSuggestions() {
            if (this.isShowingSuggestions) {
                this.isShowingSuggestions = false;
                this.currentMentionQuery = '';
                this.currentMentionStart = -1;
                this.updateContentState();
                // Use Popover API to hide the popover
                if (this.suggestionsPopover) {
                    this.suggestionsPopover.hidePopover();
                }
            }
        }
        /**
         * Updates filtered suggestions based on current query
         */
        updateFilteredSuggestions() {
            if (!this.currentMentionQuery) {
                this.filteredSuggestions = this.suggestions.slice(0, 10); // Limit to 10
                return;
            }
            const query = this.currentMentionQuery.toLowerCase();
            this.filteredSuggestions = this.suggestions
                .filter((suggestion) => suggestion.label.toLowerCase().includes(query) ||
                suggestion.description?.toLowerCase().includes(query) ||
                suggestion.suffix?.toLowerCase().includes(query))
                .slice(0, 10); // Limit to 10
            // Reset selection if needed
            if (this.selectedSuggestionIndex >= this.filteredSuggestions.length) {
                this.selectedSuggestionIndex = 0;
            }
        }
        /**
         * Positions the suggestions popover using the Popover API anchor positioning
         */
        positionSuggestions() {
            if (!this.suggestionsPopover)
                return;
            const selection = window.getSelection();
            if (!selection || selection.rangeCount === 0)
                return;
            // Use getComposedRanges() for shadow DOM support, fallback to getRangeAt()
            let range;
            if ('getComposedRanges' in selection && typeof selection.getComposedRanges === 'function' && this.shadowRoot) {
                const composedRanges = selection.getComposedRanges({ shadowRoots: [this.shadowRoot] });
                if (composedRanges.length === 0)
                    return;
                range = composedRanges[0];
            }
            else {
                range = selection.getRangeAt(0);
            }
            // Convert StaticRange to Range if needed for getBoundingClientRect
            let workingRange;
            if (range instanceof StaticRange) {
                workingRange = document.createRange();
                workingRange.setStart(range.startContainer, range.startOffset);
                workingRange.setEnd(range.endContainer, range.endOffset);
            }
            else {
                workingRange = range;
            }
            const rect = workingRange.getBoundingClientRect();
            // Position suggestions below the caret using manual positioning as fallback
            // The Popover API will handle proper layering and overflow handling
            this.suggestionsPopover.style.left = `${rect.left}px`;
            this.suggestionsPopover.style.top = `${rect.bottom + 4}px`;
        }
        /**
         * Selects a suggestion and inserts it as a mention
         */
        selectSuggestion(suggestion) {
            if (!suggestion)
                return;
            // Add to mention map
            this.mentionMap.set(suggestion.id, suggestion);
            // Find the position where the mention trigger starts
            const mentionStart = this.currentMentionStart;
            // Find the DOM node and offset for the mention start position
            const mentionStartInfo = this.findNodeAtGlobalPosition(mentionStart);
            if (!mentionStartInfo) {
                // Fallback: insert at the end
                const chip = this.createMentionChip(suggestion);
                const afterTextNode = document.createTextNode('');
                this.editorElement.appendChild(chip);
                this.editorElement.appendChild(afterTextNode);
                this.setCaretPositionAtTextNode(afterTextNode, 0);
                this.hideSuggestions();
                this.syncValueFromEditor();
                this.dispatchEvent(new CustomEvent('mention-insert', {
                    detail: {
                        suggestion,
                        trigger: this.mentionTrigger + this.currentMentionQuery,
                        position: mentionStart,
                    },
                    bubbles: true,
                }));
                return;
            }
            // If the target is not a text node, insert at the container level
            if (mentionStartInfo.node.nodeType !== Node.TEXT_NODE) {
                const chip = this.createMentionChip(suggestion);
                const container = mentionStartInfo.node;
                const beforeNode = container.childNodes[mentionStartInfo.offset];
                // Create an empty text node for caret positioning
                const afterTextNode = document.createTextNode('');
                if (beforeNode) {
                    container.insertBefore(chip, beforeNode);
                    container.insertBefore(afterTextNode, beforeNode);
                }
                else {
                    container.appendChild(chip);
                    container.appendChild(afterTextNode);
                }
                // Position caret at the beginning of the after text node
                this.setCaretPositionAtTextNode(afterTextNode, 0);
                this.hideSuggestions();
                this.syncValueFromEditor();
                this.dispatchEvent(new CustomEvent('mention-insert', {
                    detail: {
                        suggestion,
                        trigger: this.mentionTrigger + this.currentMentionQuery,
                        position: mentionStart,
                    },
                    bubbles: true,
                }));
                return;
            }
            // We have a text node - split it and insert the chip
            const textNode = mentionStartInfo.node;
            const splitOffset = mentionStartInfo.offset;
            // Create the mention chip
            const chip = this.createMentionChip(suggestion);
            // Split the text node at the mention start position
            const beforeText = textNode.textContent?.substring(0, splitOffset) || '';
            const afterText = textNode.textContent?.substring(splitOffset + 1) || ''; // +1 to skip the trigger
            // Replace the original text node with the split content
            const parentNode = textNode.parentNode;
            if (parentNode) {
                // Create new text nodes - always create afterTextNode even if empty
                const beforeTextNode = beforeText ? document.createTextNode(beforeText) : null;
                const afterTextNode = document.createTextNode(afterText); // Always create, even if empty
                // Insert the nodes in order
                if (beforeTextNode) {
                    parentNode.insertBefore(beforeTextNode, textNode);
                }
                parentNode.insertBefore(chip, textNode);
                parentNode.insertBefore(afterTextNode, textNode);
                // Remove the original text node
                parentNode.removeChild(textNode);
                // Position caret at the beginning of the after text node
                this.setCaretPositionAtTextNode(afterTextNode, 0);
            }
            else {
                // Fallback: append to editor and create a text node for caret positioning
                const afterTextNode = document.createTextNode('');
                this.editorElement.appendChild(chip);
                this.editorElement.appendChild(afterTextNode);
                this.setCaretPositionAtTextNode(afterTextNode, 0);
            }
            // Hide suggestions
            this.hideSuggestions();
            // Sync value and dispatch events
            this.syncValueFromEditor();
            this.dispatchEvent(new CustomEvent('mention-insert', {
                detail: {
                    suggestion,
                    trigger: this.mentionTrigger + this.currentMentionQuery,
                    position: mentionStart,
                },
                bubbles: true,
            }));
        }
        /**
         * Removes a mention chip
         */
        removeMention(chipElement, mention) {
            const position = this.getElementPosition(chipElement);
            chipElement.remove();
            this.syncValueFromEditor();
            this.dispatchEvent(new CustomEvent('mention-remove', {
                detail: {
                    suggestion: mention,
                    position,
                },
                bubbles: true,
            }));
        }
        /**
         * Gets the text position of an element
         */
        getElementPosition(element) {
            let position = 0;
            let currentNode = this.editorElement.firstChild;
            while (currentNode && currentNode !== element) {
                if (currentNode.nodeType === Node.TEXT_NODE) {
                    position += currentNode.textContent?.length || 0;
                }
                else if (currentNode.nodeType === Node.ELEMENT_NODE) {
                    const element = currentNode;
                    if (element.classList?.contains('mention-chip')) {
                        position += 1; // Count chip as 1 character
                    }
                }
                currentNode = currentNode.nextSibling;
            }
            return position;
        }
        /**
         * Handles clicking on a suggestion
         */
        handleSuggestionClick(suggestion, event) {
            event.preventDefault();
            this.selectSuggestion(suggestion);
            this.focus();
        }
        /**
         * Renders a suggestion item
         */
        renderSuggestion(suggestion, index) {
            const isSelected = index === this.selectedSuggestionIndex;
            const classes = classMap({
                'suggestion-item': true,
                'selected': isSelected,
            });
            return html `
      <button
        class="${classes}"
        @click="${(e) => this.handleSuggestionClick(suggestion, e)}"
        @mouseenter="${() => (this.selectedSuggestionIndex = index)}"
      >
        <div class="suggestion-content">
          <div class="suggestion-headline">${suggestion.label}</div>
          ${suggestion.description
                ? html ` <div class="suggestion-supporting-text">${suggestion.description}</div> `
                : nothing}
        </div>
        ${suggestion.suffix ? html ` <div class="suggestion-suffix">${suggestion.suffix}</div> ` : nothing}
      </button>
    `;
        }
        /**
         * Renders the suggestions popover
         */
        renderSuggestions() {
            return html `
      <div class="suggestions-popover" popover="manual">
        ${this.isShowingSuggestions && this.filteredSuggestions.length > 0
                ? this.filteredSuggestions.map((suggestion, index) => this.renderSuggestion(suggestion, index))
                : nothing}
      </div>
    `;
        }
        render() {
            const surfaceClasses = classMap({
                'surface': true,
                'has-content': this.hasContent,
            });
            const labelClasses = classMap({
                label: true,
                floating: this.isLabelFloating,
            });
            return html `
      <div class="${surfaceClasses}">
        <div class="container"></div>
        <div class="content">
          <div class="body">
            ${this.label ? html `<div class="${labelClasses}">${this.label}</div>` : nothing}
            <div
              class="editor"
              contenteditable="${!this.disabled}"
              data-placeholder="${ifDefined(this.placeholder)}"
              @input="${this.handleEditorInput}"
              @keydown="${this.handleEditorKeyDown}"
              @focus="${this.handleEditorFocus}"
              @blur="${this.handleEditorBlur}"
              @paste="${this.handleEditorPaste}"
              role="textbox"
              aria-label="${ifDefined(this.label)}"
              aria-multiline="true"
              aria-required="${this.required}"
              aria-invalid="${this.invalid}"
              tabindex="${this.disabled ? -1 : 0}"
            ></div>
          </div>
        </div>
        ${this.renderSuggestions()}
      </div>
      ${this.supportingText ? html ` <div class="supporting-text">${this.supportingText}</div> ` : nothing}
    `;
        }
    };
})();
/**
 * A material design textarea component that supports @mentions with suggestions.
 *
 * Features:
 * - Material Design styling
 * - @mention triggers with customizable suggestions
 * - Inline pill/chip rendering for mentions
 * - Proper caret management
 * - Keyboard navigation for suggestions
 * - Overflow container support
 * - Generic design for extensibility
 * - Accessibility support
 *
 * @fires mention-insert - When a mention is inserted
 * @fires mention-remove - When a mention is removed
 * @fires input - When the input value changes
 * @fires change - When the input loses focus and value has changed
 */
export default MentionTextArea;
//# sourceMappingURL=MentionTextArea.js.map