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;
};
import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';
import { ComponentStatesMixin } from '../../util/ComponentStatesMixin.js';
import { EventEmitterMixin } from '../../util/EventEmitterMixin.js';
import { ReadyMixin } from '../../util/ReadyMixin.js';
import { RovingTabindexMixin } from '../../util/RovingTabindexMixin.js';
import onFind from '../../util/onFind.js';
const COMPONENT_TAGS = new Set(['BTU-ICON-BUTTON', 'BTU-DROPDOWN']);
const SELECTABLE_TAGS = new Set(['BTU-ICON-BUTTON']);
/**
 * A semantic container for grouping related buttons together.
 *
 * Supports connected (joined) and spaced layouts, horizontal and vertical
 * orientation, group-level size and disabled propagation, and optional
 * toggle/selection modes (single-select or multi-select).
 *
 * @element btu-button-group
 *
 * @fires {CustomEvent} btu-button-group-ready - Fired after first render and initialization
 * @fires {CustomEvent<{value: string}>} btu-button-group-change - Fired when selection changes (single/multiple modes only)
 * @fires {CustomEvent<{name: string | undefined}>} btu-icon-button-click - Bubbles from child btu-icon-button elements when clicked
 *
 * @slot - One or more `<button class="btu-button …">` or `<btu-icon-button>` elements to display
 *         in the group. The `connected` variant rounds the outer corners on the real `<button>`,
 *         so anchors styled as `.btu-button` slotted directly will not get rounded corners.
 *         Use `<button>` for grouped controls.
 * @slot end - Pushes the child to the end of the group via auto-margin (vertical: bottom, horizontal: right)
 *
 * @cssprop --button-group-gap - Space between buttons when variant="spaced" (default: spacing.sm)
 * @cssprop --button-group-border-radius - Corner radius of outer edges when variant="connected" (default: 0.5rem)
 * @cssprop --button-group-border-color - Internal divider color between connected buttons (default: gray-300)
 * @cssprop --button-group-selection-bg - Background of a toggled/selected child (default: child's --button-tint-subtle)
 * @cssprop --button-group-selection-color - Text/icon color of a toggled/selected child (default: child's --button-tint-strong)
 * @cssprop --button-group-shimmer-highlight - Highlight color of the selection shimmer effect (default: child's --button-tint-highlight)
 *
 * Reads the following CSS custom properties from each child button (set by the
 * button plugin per color variant — see tailwind-plugin-button.ts):
 *
 * @cssprop --button-tint-subtle - Subtle tint of the child button's color family (read-only here)
 * @cssprop --button-tint-strong - Strong tint of the child button's color family (read-only here)
 * @cssprop --button-tint-highlight - Highlight tint of the child button's color family (read-only here)
 *
 * @cssstate btu-connected - Applied when variant="connected", targetable via :state(btu-connected)
 * @cssstate btu-spaced - Applied when variant="spaced", targetable via :state(btu-spaced)
 * @cssstate btu-horizontal - Applied when orientation="horizontal", targetable via :state(btu-horizontal)
 * @cssstate btu-vertical - Applied when orientation="vertical", targetable via :state(btu-vertical)
 * @cssstate btu-disabled - Applied when the group is disabled, targetable via :state(btu-disabled)
 */
export default class ButtonGroup extends RovingTabindexMixin(ComponentStatesMixin(EventEmitterMixin(ReadyMixin(LitElement)))) {
    constructor() {
        super(...arguments);
        /**
         * Accessible name for the group, announced by assistive devices via aria-label.
         * @attr
         */
        this.label = '';
        /**
         * Layout direction of the buttons.
         * @attr
         */
        this.orientation = 'horizontal';
        /**
         * `connected` collapses shared borders for a joined appearance.
         * `spaced` renders buttons with a gap.
         * @attr
         */
        this.variant = 'connected';
        /**
         * Propagates a uniform size to all child buttons.
         * @attr
         */
        this.size = 'md';
        /**
         * When true, disables all child buttons as a group.
         * @attr
         */
        this.disabled = false;
        /**
         * Enables toggle/selection behavior.
         * `single` allows one active button; `multiple` allows many.
         * @attr
         */
        this.selection = 'none';
        /**
         * Reflects the currently selected button value(s).
         * For `single`, the value of the active button.
         * For `multiple`, a comma-delimited list of active values.
         * @attr
         */
        this.value = '';
        /**
         * When set, creates hidden input(s) for native form participation.
         * @attr
         */
        this.name = '';
        /** @internal */
        this.initialClasses = [];
        /** @internal */
        this.boundHandleClick = this.handleClick.bind(this);
        /** @internal */
        this.boundHandleKeyDown = this.handleKeyDown.bind(this);
    }
    static get tagName() {
        return 'BTU-BUTTON-GROUP';
    }
    /** @internal */
    _getRovingTargets() {
        if (this.selection === 'none')
            return [];
        const targets = [];
        for (const child of Array.from(this.children)) {
            if (!(child instanceof HTMLElement))
                continue;
            if (child.hasAttribute('hidden') || child.getAttribute('type') === 'hidden')
                continue;
            if (SELECTABLE_TAGS.has(child.tagName)) {
                const inner = child.querySelector('button');
                if (inner)
                    targets.push(inner);
            }
            else if (child.matches('.btu-button') || child.matches('button') || child.tabIndex >= 0) {
                targets.push(child);
            }
        }
        return targets;
    }
    connectedCallback() {
        super.connectedCallback();
        if (this.className) {
            this.initialClasses = this.className.split(' ').filter(c => c.trim());
        }
        this.setAttribute('role', 'group');
        this.addEventListener('click', this.boundHandleClick);
        this.addEventListener('keydown', this.boundHandleKeyDown);
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.removeEventListener('click', this.boundHandleClick);
        this.removeEventListener('keydown', this.boundHandleKeyDown);
    }
    createRenderRoot() {
        return this;
    }
    willUpdate() {
        this.className = [...this.initialClasses, 'btu-button-group'].filter(Boolean).join(' ');
        this.syncStates();
        if (this.label)
            this.setAttribute('aria-label', this.label);
        else
            this.removeAttribute('aria-label');
        if (this.orientation === 'vertical') {
            this.setAttribute('aria-orientation', 'vertical');
        }
        else {
            this.removeAttribute('aria-orientation');
        }
    }
    firstUpdated() {
        onFind(this, '.btu-button', (button) => {
            const el = button;
            if (!this.contains(el))
                return;
            const wrapper = el.closest('btu-icon-button, btu-dropdown');
            if (wrapper && this.contains(wrapper)) {
                this.syncChild(wrapper);
            }
            else {
                this.syncChild(el);
            }
            this.syncRovingTabindex();
        });
        this.emit('btu-button-group-ready');
    }
    updated(changedProperties) {
        if (changedProperties.has('size') ||
            changedProperties.has('disabled') ||
            changedProperties.has('selection') ||
            changedProperties.has('value')) {
            this.syncAllChildren();
        }
        if (changedProperties.has('name') || changedProperties.has('value') || changedProperties.has('selection')) {
            this.syncHiddenInputs();
        }
        if (changedProperties.has('selection')) {
            this.syncRovingTabindex();
        }
    }
    // ─── Child sync ───────────────────────────────────────────────────
    /** @internal Sync size, disabled, and selection on a direct child */
    syncChild(child) {
        if (COMPONENT_TAGS.has(child.tagName)) {
            child.setAttribute('size', this.size);
            if (this.disabled)
                child.setAttribute('disabled', '');
            else
                child.removeAttribute('disabled');
            if (SELECTABLE_TAGS.has(child.tagName))
                this.syncSelection(child);
        }
        else if (child.classList.contains('btu-button')) {
            child.setAttribute('type', 'button');
            // Size is handled by CSS: btu-button-group[size="..."] .btu-button
            if (this.disabled) {
                child.setAttribute('disabled', '');
                child.setAttribute('aria-disabled', 'true');
            }
            else {
                child.removeAttribute('disabled');
                child.removeAttribute('aria-disabled');
            }
            this.syncSelection(child);
        }
    }
    /** @internal Set aria-pressed on the interactive button element */
    syncSelection(item) {
        const button = SELECTABLE_TAGS.has(item.tagName) ? item.querySelector('button') : item;
        if (!button)
            return;
        if (this.selection === 'none') {
            button.removeAttribute('aria-pressed');
            return;
        }
        const val = this.resolveButtonValue(item);
        const selected = val !== '' && this.selectedValues.includes(val);
        button.setAttribute('aria-pressed', String(selected));
    }
    /** @internal Re-sync all children */
    syncAllChildren() {
        for (const child of Array.from(this.children)) {
            if (child instanceof HTMLElement)
                this.syncChild(child);
        }
        this.syncAllSelected();
    }
    /** @internal Set data-all-selected when every selectable button is pressed */
    syncAllSelected() {
        if (this.selection === 'none' || !this.value) {
            this.removeAttribute('data-all-selected');
            return;
        }
        const buttons = Array.from(this.querySelectorAll('.btu-button[aria-pressed]'));
        if (buttons.length === 0) {
            this.removeAttribute('data-all-selected');
            return;
        }
        const allSelected = buttons.every(b => b.getAttribute('aria-pressed') === 'true');
        if (allSelected) {
            this.setAttribute('data-all-selected', '');
        }
        else {
            this.removeAttribute('data-all-selected');
        }
    }
    /** @internal Initialize roving tabindex: selected button gets tabindex=0, others -1 */
    syncRovingTabindex() {
        const targets = this._getRovingTargets();
        if (targets.length === 0)
            return;
        let focusIndex = 0;
        if (this.selection === 'single' && this.value) {
            const idx = targets.findIndex(t => {
                const item = (t.closest('btu-icon-button') ?? t);
                return this.resolveButtonValue(item) === this.value;
            });
            if (idx >= 0)
                focusIndex = idx;
        }
        this._rovingFocus(focusIndex, false);
    }
    /** @internal Parsed list of currently selected values, filtering empty segments */
    get selectedValues() {
        return this.value ? this.value.split(',').filter(Boolean) : [];
    }
    // ─── Value resolution ─────────────────────────────────────────────
    /** @internal Resolve value: value attr → textContent fallback */
    resolveButtonValue(el) {
        if (el.hasAttribute('value'))
            return el.getAttribute('value') ?? '';
        const text = el.textContent?.trim() ?? '';
        if (!text && this.selection !== 'none') {
            console.warn('[btu-button-group] Button has no resolvable value. Add a value attribute.', el);
        }
        return text;
    }
    /** @internal Resolve the value-holding element from a click target */
    resolveGroupItem(target) {
        const iconButton = target.closest('btu-icon-button');
        if (iconButton && this.contains(iconButton))
            return iconButton;
        const button = target.closest('.btu-button');
        if (button && this.contains(button))
            return button;
        return null;
    }
    // ─── Form participation ───────────────────────────────────────────
    /** @internal Create/update/remove hidden inputs */
    syncHiddenInputs() {
        for (const input of Array.from(this.querySelectorAll('input[type="hidden"][data-btu-form]'))) {
            input.remove();
        }
        if (!this.name || this.selection === 'none' || !this.value)
            return;
        for (const val of this.selectedValues) {
            const input = document.createElement('input');
            input.type = 'hidden';
            input.name = this.name;
            input.value = val;
            input.setAttribute('data-btu-form', '');
            this.appendChild(input);
        }
    }
    // ─── Selection ────────────────────────────────────────────────────
    /** @internal Update value and fire change event */
    setSelection(newValue) {
        this.value = newValue;
        this.emit('btu-button-group-change', { value: this.value });
    }
    /** @internal Handle click events for selection */
    handleClick(event) {
        if (this.selection === 'none' || this.disabled)
            return;
        const target = event.target;
        if (!(target instanceof Element))
            return;
        const item = this.resolveGroupItem(target);
        if (!item || item.hasAttribute('disabled'))
            return;
        const buttonValue = this.resolveButtonValue(item);
        if (!buttonValue)
            return;
        if (this.selection === 'single') {
            this.setSelection(this.value === buttonValue ? '' : buttonValue);
        }
        else {
            const values = this.selectedValues;
            const index = values.indexOf(buttonValue);
            if (index >= 0)
                values.splice(index, 1);
            else
                values.push(buttonValue);
            this.setSelection(values.join(','));
        }
    }
    // ─── Keyboard ─────────────────────────────────────────────────────
    /** @internal */
    handleKeyDown(event) {
        if (this.selection === 'none')
            return;
        const nav = (fn) => {
            event.preventDefault();
            fn();
            if (this.selection === 'single')
                this.activateFocusedButton();
        };
        switch (event.key) {
            case 'ArrowRight':
            case 'ArrowDown':
                nav(() => this._rovingNext());
                break;
            case 'ArrowLeft':
            case 'ArrowUp':
                nav(() => this._rovingPrev());
                break;
            case 'Home':
                nav(() => this._rovingFirst());
                break;
            case 'End':
                nav(() => this._rovingLast());
                break;
            case ' ':
            case 'Enter':
                if (this.selection === 'multiple') {
                    event.preventDefault();
                    this._getRovingTargets()[this._rovingCurrentIndex()]?.click();
                }
                break;
        }
    }
    /** @internal Activate the currently focused button (single-select arrow nav) */
    activateFocusedButton() {
        const focused = this._getRovingTargets()[this._rovingCurrentIndex()];
        if (!focused)
            return;
        const item = (focused.closest('btu-icon-button') ?? focused);
        if (item.hasAttribute('disabled'))
            return;
        const val = this.resolveButtonValue(item);
        if (!val)
            return;
        this.setSelection(val);
    }
    // ─── Custom states ────────────────────────────────────────────────
    /** @internal */
    syncStates() {
        const stateMap = {
            'btu-connected': this.variant === 'connected',
            'btu-spaced': this.variant === 'spaced',
            'btu-horizontal': this.orientation === 'horizontal',
            'btu-vertical': this.orientation === 'vertical',
            'btu-disabled': this.disabled,
        };
        for (const [state, active] of Object.entries(stateMap)) {
            if (active)
                this.states.add(state);
            else
                this.states.delete(state);
        }
    }
    render() {
        return html ``;
    }
}
__decorate([
    property({ type: String })
], ButtonGroup.prototype, "label", void 0);
__decorate([
    property({ type: String, reflect: true })
], ButtonGroup.prototype, "orientation", void 0);
__decorate([
    property({ type: String, reflect: true })
], ButtonGroup.prototype, "variant", void 0);
__decorate([
    property({ type: String, reflect: true })
], ButtonGroup.prototype, "size", void 0);
__decorate([
    property({ type: Boolean })
], ButtonGroup.prototype, "disabled", void 0);
__decorate([
    property({ type: String, reflect: true })
], ButtonGroup.prototype, "selection", void 0);
__decorate([
    property({ type: String, reflect: true })
], ButtonGroup.prototype, "value", void 0);
__decorate([
    property({ type: String })
], ButtonGroup.prototype, "name", void 0);
if (!customElements.get('btu-button-group')) {
    customElements.define('btu-button-group', ButtonGroup);
}
//# sourceMappingURL=ButtonGroup.js.map