import { __esDecorate, __runInitializers } from "tslib";
import { LitElement } from 'lit';
import { property } from 'lit/decorators.js';
let UiFocusRing = (() => {
    let _classSuper = LitElement;
    let _control_decorators;
    let _control_initializers = [];
    let _control_extraInitializers = [];
    let _attach_decorators;
    let _attach_initializers = [];
    let _attach_extraInitializers = [];
    let _for_decorators;
    let _for_initializers = [];
    let _for_extraInitializers = [];
    let _inward_decorators;
    let _inward_initializers = [];
    let _inward_extraInitializers = [];
    let _visible_decorators;
    let _visible_initializers = [];
    let _visible_extraInitializers = [];
    return class UiFocusRing extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _control_decorators = [property({ type: Object })];
            _attach_decorators = [property({ type: Object })];
            _for_decorators = [property({ type: String })];
            _inward_decorators = [property({ type: Boolean, reflect: true })];
            _visible_decorators = [property({ type: Boolean, reflect: true })];
            __esDecorate(this, null, _control_decorators, { kind: "accessor", name: "control", static: false, private: false, access: { has: obj => "control" in obj, get: obj => obj.control, set: (obj, value) => { obj.control = value; } }, metadata: _metadata }, _control_initializers, _control_extraInitializers);
            __esDecorate(this, null, _attach_decorators, { kind: "accessor", name: "attach", static: false, private: false, access: { has: obj => "attach" in obj, get: obj => obj.attach, set: (obj, value) => { obj.attach = value; } }, metadata: _metadata }, _attach_initializers, _attach_extraInitializers);
            __esDecorate(this, null, _for_decorators, { kind: "accessor", name: "for", static: false, private: false, access: { has: obj => "for" in obj, get: obj => obj.for, set: (obj, value) => { obj.for = value; } }, metadata: _metadata }, _for_initializers, _for_extraInitializers);
            __esDecorate(this, null, _inward_decorators, { kind: "accessor", name: "inward", static: false, private: false, access: { has: obj => "inward" in obj, get: obj => obj.inward, set: (obj, value) => { obj.inward = value; } }, metadata: _metadata }, _inward_initializers, _inward_extraInitializers);
            __esDecorate(this, null, _visible_decorators, { kind: "accessor", name: "visible", static: false, private: false, access: { has: obj => "visible" in obj, get: obj => obj.visible, set: (obj, value) => { obj.visible = value; } }, metadata: _metadata }, _visible_initializers, _visible_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #control_accessor_storage = __runInitializers(this, _control_initializers, void 0);
        /**
         * The control element that this focus ring is associated with.
         * When the control gains or loses focus, the focus ring will show or hide.
         */
        get control() { return this.#control_accessor_storage; }
        set control(value) { this.#control_accessor_storage = value; }
        #attach_accessor_storage = (__runInitializers(this, _control_extraInitializers), __runInitializers(this, _attach_initializers, void 0));
        /**
         * An element to attach the focus ring to. Defaults to the parent element.
         * This is typically used when the focus ring should be positioned relative
         * to a different element than the control.
         */
        get attach() { return this.#attach_accessor_storage; }
        set attach(value) { this.#attach_accessor_storage = value; }
        #for_accessor_storage = (__runInitializers(this, _attach_extraInitializers), __runInitializers(this, _for_initializers, void 0));
        /**
         * An ID of an element that this focus ring is for.
         * Alternative to setting the `control` property directly.
         * @attribute
         */
        get for() { return this.#for_accessor_storage; }
        set for(value) { this.#for_accessor_storage = value; }
        #inward_accessor_storage = (__runInitializers(this, _for_extraInitializers), __runInitializers(this, _inward_initializers, false
        /**
         * The internal visibility state of the focus ring.
         */
        ));
        /**
         * Whether the focus ring should render inward instead of outward.
         * When true, the focus ring will be positioned inside the control bounds.
         * @attribute
         */
        get inward() { return this.#inward_accessor_storage; }
        set inward(value) { this.#inward_accessor_storage = value; }
        #visible_accessor_storage = (__runInitializers(this, _inward_extraInitializers), __runInitializers(this, _visible_initializers, false));
        /**
         * The internal visibility state of the focus ring.
         */
        get visible() { return this.#visible_accessor_storage; }
        set visible(value) { this.#visible_accessor_storage = value; }
        abortController = __runInitializers(this, _visible_extraInitializers);
        constructor() {
            super();
            this.addEventListener('visibility-changed', this.onVisibilityChanged);
        }
        connectedCallback() {
            super.connectedCallback();
            this.setupControl();
        }
        disconnectedCallback() {
            super.disconnectedCallback();
            this.cleanupListeners();
        }
        willUpdate(changedProperties) {
            if (changedProperties.has('for') || changedProperties.has('control')) {
                this.setupControl();
            }
        }
        /**
         * Sets up the control element and event listeners.
         */
        setupControl() {
            this.cleanupListeners();
            const control = this.getControl();
            if (!control)
                return;
            this.abortController = new AbortController();
            const { signal } = this.abortController;
            // Listen for focus and blur events
            control.addEventListener('focus', this.handleFocus, { signal });
            control.addEventListener('blur', this.handleBlur, { signal });
            control.addEventListener('pointerdown', this.handlePointerDown, { signal });
            // Set initial state
            this.visible = control.matches(':focus-visible');
        }
        /**
         * Cleans up event listeners.
         */
        cleanupListeners() {
            this.abortController?.abort();
            this.abortController = undefined;
        }
        /**
         * Gets the control element from either the `control` property,
         * the `for` attribute, or defaults to the parent element.
         */
        getControl() {
            if (this.control) {
                return this.control;
            }
            if (this.for) {
                const root = this.getRootNode();
                return root.getElementById(this.for);
            }
            return this.parentElement;
        }
        /**
         * Handles focus events from the control element.
         */
        handleFocus = (event) => {
            // Only show focus ring for keyboard navigation
            if (this.shouldShowFocusRing(event)) {
                this.show();
            }
        };
        /**
         * Handles blur events from the control element.
         */
        handleBlur = () => {
            this.hide();
        };
        /**
         * Handles pointer down events to hide focus ring during mouse interaction.
         */
        handlePointerDown = () => {
            this.hide();
        };
        /**
         * Determines if the focus ring should be shown based on the focus event.
         * The focus ring should only show for keyboard navigation, not mouse clicks.
         */
        shouldShowFocusRing(event) {
            const control = event.target;
            return control?.matches(':focus-visible') ?? false;
        }
        /**
         * Shows the focus ring.
         */
        show() {
            if (this.visible)
                return;
            this.visible = true;
        }
        /**
         * Hides the focus ring.
         */
        hide() {
            if (!this.visible)
                return;
            this.visible = false;
        }
        /**
         * Handles the visibility changed event.
         */
        onVisibilityChanged = (event) => {
            // Stop propagation to prevent multiple focus rings from interfering
            event.stopPropagation();
        };
        updated(changedProperties) {
            super.updated(changedProperties);
            if (changedProperties.has('visible')) {
                this.dispatchEvent(new CustomEvent('visibility-changed', {
                    detail: { visible: this.visible },
                    bubbles: false,
                    composed: true,
                }));
            }
        }
    };
})();
/**
 * A focus ring component that provides a visible focus indicator.
 * This component automatically manages the visibility of the focus ring
 * based on the focus state of its control element.
 *
 * @fires visibility-changed - Dispatched when the focus ring visibility changes.
 *                           - `detail`: An object with a `visible` property (boolean).
 */
export default UiFocusRing;
//# sourceMappingURL=focus-ring.js.map