import * as i0 from '@angular/core';
import { inject, PLATFORM_ID, DOCUMENT, input, numberAttribute, output, signal, ElementRef, Renderer2, afterNextRender, ChangeDetectionStrategy, Component } from '@angular/core';
import { isPlatformServer } from '@angular/common';

class InlineTextEdit {
    platformId = inject(PLATFORM_ID);
    document = inject(DOCUMENT);
    enabled = input(true, ...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
    placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
    delay = input(0, { ...(ngDevMode ? { debugName: "delay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
    contentChanged = output();
    isEditing = signal(false, ...(ngDevMode ? [{ debugName: "isEditing" }] : /* istanbul ignore next */ []));
    isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
    previousValue = '';
    minHeightSet = false;
    elementRef = inject((ElementRef));
    renderer = inject(Renderer2);
    emitTimeoutId = null;
    constructor() {
        afterNextRender(() => {
            this.setInitialMinHeight();
        });
    }
    ngAfterViewInit() {
        this.previousValue = this.elementRef.nativeElement.textContent;
    }
    get isContentEditable() {
        return true;
    }
    ngAfterContentChecked() {
        if (isPlatformServer(this.platformId)) {
            return;
        }
        this.setInitialMinHeight();
    }
    ngOnDestroy() {
        this.clearPendingEmission();
    }
    setInitialMinHeight() {
        if (this.minHeightSet) {
            return;
        }
        const el = this.elementRef.nativeElement;
        let height = el.getBoundingClientRect().height;
        if (!height || height < 1) {
            const cs = getComputedStyle(el);
            let lh = parseFloat(cs.lineHeight);
            if (isNaN(lh) || lh <= 0) {
                const fs = parseFloat(cs.fontSize) || 16;
                lh = fs * 1.5;
            }
            height = lh;
        }
        if (height && height > 0) {
            this.renderer.setStyle(el, 'min-height', `${Math.ceil(height)}px`);
            this.minHeightSet = true;
        }
    }
    onFocus() {
        this.isFocused.set(true);
    }
    onBlur() {
        this.isFocused.set(false);
        this.finishEdit();
    }
    onEnter(event) {
        event.preventDefault();
        this.finishEdit();
    }
    onEscape() {
        this.cancelEdit();
    }
    onPaste(event) {
        event.preventDefault();
        const text = event.clipboardData?.getData('text/plain') ?? '';
        this.document.execCommand('insertText', false, text);
    }
    onInput() {
        this.isEditing.set(true);
        // Track live changes and normalize empty content.
        // Browsers may insert a <br> (or wrappers like <div><br></div>) in empty contenteditable elements.
        const el = this.elementRef.nativeElement;
        const html = (el.innerHTML ?? '').trim().toLowerCase();
        const text = (el.textContent ?? '').trim();
        const isEffectivelyEmpty = text.length === 0 ||
            html === '' ||
            html === '<br>' ||
            html === '<br/>' ||
            html === '<div><br></div>';
        if (isEffectivelyEmpty && el.innerHTML !== '') {
            // Clear to a truly empty state so placeholders and styling work correctly.
            el.innerHTML = '';
        }
    }
    finishEdit() {
        if (!this.isEditing()) {
            return;
        }
        const newValue = this.elementRef.nativeElement.textContent?.trim() ?? '';
        if (newValue !== this.previousValue) {
            this.previousValue = newValue;
            this.emitWithDelay(newValue);
        }
        this.isEditing.set(false);
    }
    cancelEdit() {
        if (!this.isEditing()) {
            return;
        }
        this.elementRef.nativeElement.textContent = this.previousValue;
        // Keep focus and move caret to the end of the restored content for better UX.
        this.placeCaretAtEnd();
        this.isEditing.set(false);
        // Cancel any pending emission since the edit was canceled.
        this.clearPendingEmission();
    }
    placeCaretAtEnd() {
        if (isPlatformServer(this.platformId)) {
            return;
        }
        const el = this.elementRef.nativeElement;
        // Ensure the host is focused so caret positioning is visible.
        el.focus();
        const selection = this.document.getSelection?.();
        if (!selection) {
            return;
        }
        const range = this.document.createRange();
        range.selectNodeContents(el);
        range.collapse(false); // collapse to end
        selection.removeAllRanges();
        selection.addRange(range);
    }
    emitWithDelay(value) {
        const d = this.delay();
        // Always clear a previous scheduled emission to ensure only the latest value is emitted
        this.clearPendingEmission();
        if (d > 0) {
            this.emitTimeoutId = setTimeout(() => {
                this.emitTimeoutId = null;
                this.contentChanged.emit(value);
            }, d);
        }
        else {
            this.contentChanged.emit(value);
        }
    }
    clearPendingEmission() {
        if (this.emitTimeoutId) {
            clearTimeout(this.emitTimeoutId);
            this.emitTimeoutId = null;
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: InlineTextEdit, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: InlineTextEdit, isStandalone: true, selector: "ngs-inline-text-edit,[ngs-inline-text-edit]", inputs: { enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChanged: "contentChanged" }, host: { listeners: { "focus": "onFocus()", "blur": "onBlur()", "keydown.enter": "onEnter($event)", "keydown.escape": "onEscape()", "paste": "onPaste($event)", "input": "onInput()" }, properties: { "attr.contenteditable": "isContentEditable", "attr.data-placeholder": "placeholder()", "class.editing": "isEditing()", "class.focused": "isFocused()" }, classAttribute: "ngs-inline-text-edit" }, ngImport: i0, template: "<ng-content/>\n", styles: [":host{display:block;padding:4px 10px;position:relative;transition:border-color .15s cubic-bezier(.25,.8,.25,1);border:var(--ngs-form-field-outlined-outline-width, 1px) solid transparent;outline:none;border-radius:var(--ngs-field-radius);cursor:text;margin-left:-10px;margin-right:-10px;word-wrap:break-word}:host:hover{border-color:var(--ngs-form-field-outlined-outline-color, var(--ngs-color-outline))}:host.editing{color:var(--ngs-form-field-outlined-input-text-color, var(--ngs-color-on-surface));caret-color:var(--ngs-form-field-outlined-caret-color, var(--ngs-color-primary))}:host.focused{border-color:var(--ngs-color-primary);outline:1px solid var(--ngs-color-primary)}:host:empty:before{position:absolute;content:attr(data-placeholder);inset:0;z-index:0;color:var(--ngs-color-neutral-500);font-size:inherit;padding:inherit;word-wrap:break-word}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: InlineTextEdit, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-inline-text-edit,[ngs-inline-text-edit]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
                        'class': 'ngs-inline-text-edit',
                        '[attr.contenteditable]': 'isContentEditable',
                        '[attr.data-placeholder]': 'placeholder()',
                        '[class.editing]': 'isEditing()',
                        '[class.focused]': 'isFocused()',
                        '(focus)': 'onFocus()',
                        '(blur)': 'onBlur()',
                        '(keydown.enter)': 'onEnter($event)',
                        '(keydown.escape)': 'onEscape()',
                        '(paste)': 'onPaste($event)',
                        '(input)': 'onInput()',
                    }, template: "<ng-content/>\n", styles: [":host{display:block;padding:4px 10px;position:relative;transition:border-color .15s cubic-bezier(.25,.8,.25,1);border:var(--ngs-form-field-outlined-outline-width, 1px) solid transparent;outline:none;border-radius:var(--ngs-field-radius);cursor:text;margin-left:-10px;margin-right:-10px;word-wrap:break-word}:host:hover{border-color:var(--ngs-form-field-outlined-outline-color, var(--ngs-color-outline))}:host.editing{color:var(--ngs-form-field-outlined-input-text-color, var(--ngs-color-on-surface));caret-color:var(--ngs-form-field-outlined-caret-color, var(--ngs-color-primary))}:host.focused{border-color:var(--ngs-color-primary);outline:1px solid var(--ngs-color-primary)}:host:empty:before{position:absolute;content:attr(data-placeholder);inset:0;z-index:0;color:var(--ngs-color-neutral-500);font-size:inherit;padding:inherit;word-wrap:break-word}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }], ctorParameters: () => [], propDecorators: { enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], contentChanged: [{ type: i0.Output, args: ["contentChanged"] }] } });

/**
 * Generated bundle index. Do not edit.
 */

export { InlineTextEdit };
//# sourceMappingURL=ngstarter-ui-components-inline-text-edit.mjs.map
