import * as i0 from '@angular/core';
import { InjectionToken, inject, ElementRef, Renderer2, DOCUMENT, input, Component, ChangeDetectorRef, PLATFORM_ID, NgZone, DestroyRef, contentChildren, Directive } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { fromEvent, debounceTime } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { LAYOUT_CONTENT } from '@ngstarter-ui/components/layout';
import { PANEL_CONTENT } from '@ngstarter-ui/components/panel';
import { Icon } from '@ngstarter-ui/components/icon';

const SCROLL_SPY_NAV = new InjectionToken('SPY_NAV');

class ScrollSpyOn {
    _parent = inject(SCROLL_SPY_NAV);
    _elementRef = inject(ElementRef);
    _renderer = inject(Renderer2);
    _document = inject(DOCUMENT);
    targetId = input.required(...(ngDevMode ? [{ debugName: "targetId" }] : /* istanbul ignore next */ []));
    ngOnInit() {
        const fullUrl = this._document.location.origin + this._document.location.pathname;
        this._renderer.setAttribute(this._elementRef.nativeElement, 'href', fullUrl + '#' + this.targetId());
    }
    get isActive() {
        return this.targetId() === this._parent.activeId;
    }
    _handleClick(event) {
        event.preventDefault();
        event.stopPropagation();
        this._parent.scrollTo(this.targetId());
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyOn, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: ScrollSpyOn, isStandalone: true, selector: "ngs-scroll-spy-on,[ngs-scroll-spy-on]", inputs: { targetId: { classPropertyName: "targetId", publicName: "targetId", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "_handleClick($event)" }, properties: { "class.is-active": "isActive" }, classAttribute: "ngs-scroll-spy-on" }, exportAs: ["ngsScrollSpyOn"], ngImport: i0, template: "<ng-content/>\n", styles: [":host{display:block;width:max-content;padding:calc(var(--spacing, .25rem) * 2) calc(var(--spacing, .25rem) * 5);font-size:var(--ngs-font-size-sm);border-left:1px solid var(--ngs-color-subtle)}:host:hover{color:var(--ngs-color-primary)}:host.is-active{color:var(--ngs-color-primary);border-left-color:var(--sys-outline)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyOn, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-scroll-spy-on,[ngs-scroll-spy-on]', exportAs: 'ngsScrollSpyOn', host: {
                        'class': 'ngs-scroll-spy-on',
                        '[class.is-active]': 'isActive',
                        '(click)': '_handleClick($event)'
                    }, template: "<ng-content/>\n", styles: [":host{display:block;width:max-content;padding:calc(var(--spacing, .25rem) * 2) calc(var(--spacing, .25rem) * 5);font-size:var(--ngs-font-size-sm);border-left:1px solid var(--ngs-color-subtle)}:host:hover{color:var(--ngs-color-primary)}:host.is-active{color:var(--ngs-color-primary);border-left-color:var(--sys-outline)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }], propDecorators: { targetId: [{ type: i0.Input, args: [{ isSignal: true, alias: "targetId", required: true }] }] } });

class ScrollSpyNav {
    document = inject(DOCUMENT);
    cdr = inject(ChangeDetectorRef);
    platformId = inject(PLATFORM_ID);
    zone = inject(NgZone);
    destroyRef = inject(DestroyRef);
    panelBody = inject(PANEL_CONTENT, { optional: true });
    layoutBody = inject(LAYOUT_CONTENT, { optional: true });
    _items = contentChildren(ScrollSpyOn, ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
    threshold = 10;
    _activeId;
    scrollContainer;
    ngAfterContentInit() {
        if (isPlatformServer(this.platformId)) {
            return;
        }
        if (this.panelBody) {
            this.scrollContainer = this.panelBody.scrollContainer();
        }
        else if (this.layoutBody) {
            this.scrollContainer = this.layoutBody.scrollContainer();
        }
        else {
            this.scrollContainer = this.document.body;
        }
        if (this.scrollContainer) {
            this.zone.runOutsideAngular(() => {
                fromEvent(this.scrollContainer, 'scroll')
                    .pipe(debounceTime(35), takeUntilDestroyed(this.destroyRef))
                    .subscribe(() => {
                    this._findActiveItem();
                });
            });
            setTimeout(() => {
                this._findActiveItem();
            }, 10);
        }
    }
    get activeId() {
        return this._activeId;
    }
    scrollTo(targetId) {
        if (!this.scrollContainer) {
            return;
        }
        this._activeId = targetId;
        const targetElement = this.document.querySelector('#' + targetId);
        const offsetTopFix = parseInt(getComputedStyle(targetElement).marginTop) +
            parseInt(getComputedStyle(targetElement).height) + this.threshold;
        this.cdr.detectChanges();
        this.scrollContainer.scroll({
            top: targetElement.offsetTop - offsetTopFix,
            left: 0,
            behavior: 'smooth'
        });
    }
    _findActiveItem() {
        for (let item of this._items()) {
            const targetElement = this.document.querySelector('#' + item.targetId());
            if (targetElement) {
                if (this._elementIsVisibleInViewport(this.scrollContainer, targetElement)) {
                    if (this._activeId === item.targetId()) {
                        return;
                    }
                    this.zone.run(() => {
                        this._activeId = item.targetId();
                        this.cdr.detectChanges();
                    });
                    break;
                }
            }
        }
    }
    _elementIsVisibleInViewport(container, targetEl, partiallyVisible = false) {
        const { top, left, bottom, right } = targetEl.getBoundingClientRect();
        const containerRect = container.getBoundingClientRect();
        const innerWidth = containerRect.width;
        const innerHeight = containerRect.height;
        return partiallyVisible
            ? ((top > 0 && top < innerHeight) ||
                (bottom > 0 && bottom < innerHeight)) &&
                ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
            : top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyNav, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: ScrollSpyNav, isStandalone: true, selector: "ngs-scroll-spy-nav,[ngs-scroll-spy-nav]", host: { classAttribute: "ngs-scroll-spy-nav" }, providers: [
            {
                provide: SCROLL_SPY_NAV,
                useExisting: ScrollSpyNav
            }
        ], queries: [{ propertyName: "_items", predicate: ScrollSpyOn, isSignal: true }], exportAs: ["ngsScrollSpyNav"], ngImport: i0, template: "<ng-content select=\"ngs-scroll-spy-title,[ngs-scroll-spy-title]\"/>\n<div>\n  <ng-content/>\n</div>\n<ng-content select=\"ngs-scroll-spy-back-to-top,[ngs-scroll-spy-back-to-top]\"/>\n", styles: [":host{width:240px;display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyNav, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-scroll-spy-nav,[ngs-scroll-spy-nav]', exportAs: 'ngsScrollSpyNav', providers: [
                        {
                            provide: SCROLL_SPY_NAV,
                            useExisting: ScrollSpyNav
                        }
                    ], host: {
                        'class': 'ngs-scroll-spy-nav'
                    }, template: "<ng-content select=\"ngs-scroll-spy-title,[ngs-scroll-spy-title]\"/>\n<div>\n  <ng-content/>\n</div>\n<ng-content select=\"ngs-scroll-spy-back-to-top,[ngs-scroll-spy-back-to-top]\"/>\n", styles: [":host{width:240px;display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }], propDecorators: { _items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => ScrollSpyOn), { isSignal: true }] }] } });

class ScrollSpyTitle {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyTitle, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: ScrollSpyTitle, isStandalone: true, selector: "ngs-scroll-spy-title,[ngs-scroll-spy-title]", host: { classAttribute: "ngs-scroll-spy-title" }, exportAs: ["ngsScrollSpyTitle"], ngImport: i0, template: "<div class=\"truncate\"><ng-content/></div>\n", styles: [":host{display:block;font-weight:500;font-size:var(--ngs-font-size-xl)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyTitle, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-scroll-spy-title,[ngs-scroll-spy-title]', exportAs: 'ngsScrollSpyTitle', host: {
                        'class': 'ngs-scroll-spy-title'
                    }, template: "<div class=\"truncate\"><ng-content/></div>\n", styles: [":host{display:block;font-weight:500;font-size:var(--ngs-font-size-xl)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }] });

class ScrollSpyContainerDirective {
    elementRef = inject(ElementRef);
    getScrollContainer() {
        return this.elementRef.nativeElement;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyContainerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.4", type: ScrollSpyContainerDirective, isStandalone: true, selector: "[ngsScrollSpyContainer]", host: { classAttribute: "ngs-scroll-spy-container" }, exportAs: ["ngsScrollSpyContainer"], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyContainerDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ngsScrollSpyContainer]',
                    exportAs: 'ngsScrollSpyContainer',
                    host: {
                        'class': 'ngs-scroll-spy-container'
                    }
                }]
        }] });

class ScrollSpyBackToTop {
    platformId = inject(PLATFORM_ID);
    document = inject(DOCUMENT);
    panelBody = inject(PANEL_CONTENT, { optional: true });
    layoutBody = inject(LAYOUT_CONTENT, { optional: true });
    scrollContainer;
    scrollToTop() {
        if (isPlatformServer(this.platformId)) {
            return;
        }
        if (this.panelBody) {
            this.scrollContainer = this.panelBody.scrollContainer();
        }
        else if (this.layoutBody) {
            this.scrollContainer = this.layoutBody.scrollContainer();
        }
        else {
            this.scrollContainer = this.document.body;
        }
        if (this.scrollContainer) {
            this.scrollContainer.scrollTo({
                top: 0,
                behavior: 'smooth'
            });
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyBackToTop, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: ScrollSpyBackToTop, isStandalone: true, selector: "ngs-scroll-spy-back-to-top,[ngs-scroll-spy-back-to-top]", host: { listeners: { "click": "scrollToTop()" } }, exportAs: ["ngsScrollSpyBackToTop"], ngImport: i0, template: "<ngs-icon name=\"fluent:arrow-up-24-regular\"/>\n<ng-content/>\n", styles: [":host{display:inline-flex;align-items:center;gap:calc(var(--spacing, .25rem) * 1);font-size:var(--ngs-font-size-sm);font-weight:600;cursor:pointer;--ngs-icon-size: calc(var(--spacing, .25rem) * 4.5)}:host:hover{color:var(--ngs-color-primary)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScrollSpyBackToTop, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-scroll-spy-back-to-top,[ngs-scroll-spy-back-to-top]', exportAs: 'ngsScrollSpyBackToTop', imports: [
                        Icon
                    ], host: {
                        '(click)': 'scrollToTop()'
                    }, template: "<ngs-icon name=\"fluent:arrow-up-24-regular\"/>\n<ng-content/>\n", styles: [":host{display:inline-flex;align-items:center;gap:calc(var(--spacing, .25rem) * 1);font-size:var(--ngs-font-size-sm);font-weight:600;cursor:pointer;--ngs-icon-size: calc(var(--spacing, .25rem) * 4.5)}:host:hover{color:var(--ngs-color-primary)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }] });

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

export { SCROLL_SPY_NAV, ScrollSpyBackToTop, ScrollSpyContainerDirective, ScrollSpyNav, ScrollSpyOn, ScrollSpyTitle };
//# sourceMappingURL=ngstarter-ui-components-scroll-spy.mjs.map
