// #region Imports
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;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Listen } from '../../../../events/Decorators/ListenDecorator';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Disableable } from '../../../Behaviors/Disableable';
import { Slottable } from '../../../Behaviors/Slottable';
import { Themeable } from '../../../Behaviors/Themeable';
import { Variantable } from '../../../Behaviors/Variantable';
import { addInheritanceProviderController } from '../../../Controllers/InheritanceProviderController';
import { KeyboardController } from '../../../Controllers/KeyboardController';
import { ResizeController } from '../../../Controllers/ResizeController';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { FlowDirection } from '../../../Types/FlowDirection';
import { Key } from '../../../Types/Key';
import { CustomElement } from '../../Abstracts/CustomElement';
import { InkBarElement } from '../../Primitives/InkBar/InkBarElement';
import { segmentElementTemplate } from './SegmentElementTemplate';
import { SEGMENT_INHERITANCE_CONTEXT } from './SegmentInheritanceContext';
import { SegmentItemElement } from './SegmentItemElement';
import { segmentElementCosmopolitanStyle } from './Themes/SegmentElement.Cosmopolitan';
import { segmentElementJoyStyle } from './Themes/SegmentElement.Joy';
import { segmentElementMemphisStyle } from './Themes/SegmentElement.Memphis';
// #endregion
/**
 * Segment - A mutually exclusive button group for toggling between different views or options.
 *
 * @description
 * The Segment component (also known as a segmented control) displays a group of related buttons
 * arranged in a horizontal row where only one option can be selected at a time. It provides a
 * visual indicator that highlights the selected segment and supports keyboard navigation for
 * accessibility. Segments are ideal for switching between different views, filters, or modes
 * within the same context without navigating to a new page. The component automatically manages
 * selection state and includes an animated ink bar indicator to show the active segment.
 *
 * @name Segment
 * @element mosaik-segment
 * @category Selectors
 *
 * @slot - The default slot for segment items (mosaik-segment-item elements)
 *
 * @csspart indicator - The animated ink bar indicator element
 *
 * @cssprop {String} --segment-background-color - The background fill color of the segment container
 * @cssprop {String} --segment-border-color - The border color
 * @cssprop {String} --segment-border-radius - The corner rounding radius
 * @cssprop {String} --segment-border-style - The border line style
 * @cssprop {String} --segment-border-width - The border thickness
 * @cssprop {String} --segment-font-family - The font family CSS custom property.
 * @cssprop {String} --segment-font-letter-spacing - The font letter spacing CSS custom property.
 * @cssprop {String} --segment-font-line-height - The font line height CSS custom property.
 * @cssprop {String} --segment-font-size - The font size CSS custom property.
 * @cssprop {String} --segment-font-text-decoration - The font text decoration CSS custom property.
 * @cssprop {String} --segment-font-text-transform - The font text transform CSS custom property.
 * @cssprop {String} --segment-font-weight - The font weight CSS custom property.
 * @cssprop {String} --segment-foreground-color - The text and icon color
 * @cssprop {String} --segment-gap - The spacing between segment items
 * @cssprop {String} --segment-indicator-height - The height of the selection indicator
 * @cssprop {String} --segment-padding-bottom - The bottom padding inside the segment container
 * @cssprop {String} --segment-padding-left - The left padding inside the segment container
 * @cssprop {String} --segment-padding-right - The right padding inside the segment container
 * @cssprop {String} --segment-padding-top - The top padding inside the segment container
 * @cssprop {String} --segment-shadow - The shadow CSS custom property.
 * @cssprop {String} --segment-shadow-blur - The shadow blur CSS custom property.
 * @cssprop {String} --segment-shadow-color - The shadow color CSS custom property.
 * @cssprop {String} --segment-shadow-offset-x - The shadow offset x CSS custom property.
 * @cssprop {String} --segment-shadow-offset-y - The shadow offset y CSS custom property.
 * @cssprop {String} --segment-shadow-spread - The shadow spread CSS custom property.
 * @cssprop {String} --segment-transition-duration - The transition duration CSS custom property.
 * @cssprop {String} --segment-transition-mode - The transition mode CSS custom property.
 * @cssprop {String} --segment-transition-property - The transition property CSS custom property.
 * @cssprop {String} --segment-translate - The translate CSS custom property.
 *
 * @fires connected {ConnectedEvent} - Fired when connected to the DOM
 * @fires changed {PropertyChangedEvent} - Fired when properties change
 *
 * @dependency mosaik-ink-bar - The Ink Bar element.
 *
 * @example
 * Basic segment with three options:
 * ```html
 * <mosaik-segment>
 *   <mosaik-segment-item><span slot="label">Day</span></mosaik-segment-item>
 *   <mosaik-segment-item is-checked><span slot="label">Week</span></mosaik-segment-item>
 *   <mosaik-segment-item><span slot="label">Month</span></mosaik-segment-item>
 * </mosaik-segment>
 * ```
 *
 * @example
 * Primary variant segment:
 * ```html
 * <mosaik-segment variant="primary">
 *   <mosaik-segment-item><span slot="label">List</span></mosaik-segment-item>
 *   <mosaik-segment-item is-checked><span slot="label">Grid</span></mosaik-segment-item>
 *   <mosaik-segment-item><span slot="label">Table</span></mosaik-segment-item>
 * </mosaik-segment>
 * ```
 *
 * @example
 * Disabled segment:
 * ```html
 * <mosaik-segment disabled>
 *   <mosaik-segment-item><span slot="label">Option 1</span></mosaik-segment-item>
 *   <mosaik-segment-item><span slot="label">Option 2</span></mosaik-segment-item>
 * </mosaik-segment>
 * ```
 *
 * @public
 */
let SegmentElement = class SegmentElement extends Themeable(Slottable(Disableable(Variantable(Appearanceable(CustomElement))))) {
    // #region Fields
    _provider = addInheritanceProviderController(this, {
        context: SEGMENT_INHERITANCE_CONTEXT,
        values: () => ({
            disabled: this.disabled,
            variant: this.variant,
            dir: this.dir
        })
    });
    _indicatorElement;
    _resizeController;
    _keyboardController;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._indicatorElement = null;
        this._keyboardController = new KeyboardController(this, { capture: true });
        this._resizeController = new ResizeController(this, {
            callback: () => {
                const current = this.getCurrent();
                if (current) {
                    this.alignIndicatorTo(current);
                }
            }
        });
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     * The `is` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-segment';
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this._keyboardController
            .add(Key.RightArrow, () => {
            const current = this.dir === FlowDirection.RightToLeft
                ? this.getItem('previous')
                : this.getItem('next');
            current?.check();
        }, (e) => this.getEnabledItems().includes(e?.target), { preventDefault: true })
            .add(Key.LeftArrow, () => {
            const current = this.dir === FlowDirection.RightToLeft
                ? this.getItem('next')
                : this.getItem('previous');
            current?.check();
        }, (e) => this.getEnabledItems().includes(e?.target), { preventDefault: true })
            .add(Key.Home, () => {
            const current = this.getItem('first');
            current?.check();
        }, (e) => this.getEnabledItems().includes(e?.target), { preventDefault: true })
            .add(Key.End, () => {
            const current = this.getItem('last');
            current?.check();
        }, (e) => this.getEnabledItems().includes(e?.target), { preventDefault: true })
            .add(Key.Enter, () => {
            const current = document.activeElement;
            current.check();
        }, (e) => this.getEnabledItems().includes(e?.target), { preventDefault: true });
    }
    /**
     * @public
     * @override
     */
    onSlotChanges(slotName) {
        super.onSlotChanges(slotName);
        const elements = this.getItems();
        for (const [i, e] of elements.entries()) {
            e.classList.toggle('first', i === 0);
            e.classList.toggle('inner', i > 0 && i < elements.length - 1);
            e.classList.toggle('last', i === elements.length - 1);
            if (e.isChecked) {
                this.alignIndicatorTo(e);
            }
        }
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        this._indicatorElement = this.getTemplatePart('indicator');
    }
    /**
     * @protected
     */
    onClick(event) {
        const clicked = event.composedPath().find((el) => el instanceof SegmentItemElement);
        if (!clicked) {
            return;
        }
        // Checkable.handleClick() already toggled the clicked item before
        // this handler runs (events bubble child → parent). Force mutual
        // exclusivity: uncheck every other item, ensure the clicked one
        // is checked, and align the indicator.
        const items = this.getItems();
        for (const item of items) {
            if (item !== clicked && item.isChecked) {
                item.isChecked = false;
            }
        }
        if (!clicked.isChecked) {
            clicked.isChecked = true;
        }
        this.alignIndicatorTo(clicked);
    }
    /**
     * Stretches the ink bar toward the pressed segment item (anticipation
     * effect). On pointer release, the bar either slides to the new
     * selection (if click fires) or snaps back to the current segment.
     *
     * @protected
     */
    onPointerDown(event) {
        const target = event.composedPath().find((el) => el instanceof SegmentItemElement);
        if (!target) {
            return;
        }
        const current = this.getCurrent();
        if (!current || current === target || target.disabled) {
            return;
        }
        if (this._indicatorElement) {
            this._indicatorElement.stretchToward(target);
        }
        const cleanup = () => {
            requestAnimationFrame(() => {
                const selected = this.getCurrent();
                if (selected) {
                    this.alignIndicatorTo(selected);
                }
            });
            document.removeEventListener('pointerup', cleanup);
            document.removeEventListener('pointercancel', cleanup);
        };
        document.addEventListener('pointerup', cleanup);
        document.addEventListener('pointercancel', cleanup);
    }
    /**
     * @protected
     */
    onChecked(event) {
        const current = event.target;
        // const others = this.getSlotAssigmments('')
        //     .filter((x): x is SegmentItemElement => x instanceof SegmentItemElement)
        //     .filter(x => x !== current)
        //     .find((x) => !x.isChecked);
        this.alignIndicatorTo(current);
    }
    onResize(event) {
        const current = this.getCurrent();
        if (current) {
            this.alignIndicatorTo(current);
        }
    }
    /**
     * @protected
     */
    onDisabledPropertyChange() {
        // Trigger context update for child elements
        this.requestUpdate();
    }
    /**
     * @protected
     */
    onVariantPropertyChange() {
        // Trigger context update for child elements
        this.requestUpdate();
    }
    /**
     * @protected
     */
    onDirPropertyChange() {
        // Trigger context update for child elements
        this.requestUpdate();
    }
    /**
     * @private
     */
    alignIndicatorTo(element) {
        if (this._indicatorElement) {
            this._indicatorElement.target = element;
            this._indicatorElement.align();
        }
    }
    /**
     * @private
     */
    getItems() {
        return this.getSlotAssignmentsOf('', SegmentItemElement);
    }
    /**
     * @private
     */
    getEnabledItems() {
        return this.getItems().filter((x) => !x.disabled);
    }
    /**
     * @private
     */
    getCurrent() {
        return this.getItems().find((x) => x.isChecked) ?? null;
    }
    /**
     * @private
     */
    getItem(selector) {
        const items = this.getItems().filter((item) => !item.disabled);
        const currIndex = items.findIndex((item) => item === document.activeElement);
        switch (selector) {
            case 'first':
                return items[0];
            case 'last':
                return items[items.length - 1];
            case 'next':
                return items[currIndex + 1] ?? items[0];
            case 'previous':
                return items[currIndex - 1] ?? items[items.length - 1];
            default:
                return null;
        }
    }
};
__decorate([
    Listen('click'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Event]),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onClick", null);
__decorate([
    Listen('pointerdown'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [PointerEvent]),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onPointerDown", null);
__decorate([
    Listen('checked'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [CustomEvent]),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onChecked", null);
__decorate([
    Listen('resize', 'window'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [CustomEvent]),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onResize", null);
__decorate([
    Watch('disabled'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onDisabledPropertyChange", null);
__decorate([
    Watch('variant'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onVariantPropertyChange", null);
__decorate([
    Watch('dir'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], SegmentElement.prototype, "onDirPropertyChange", null);
SegmentElement = __decorate([
    Component({
        selector: 'mosaik-segment',
        template: segmentElementTemplate,
        themes: {
            joy: segmentElementJoyStyle,
            memphis: segmentElementMemphisStyle,
            cosmopolitan: segmentElementCosmopolitanStyle
        },
        imports: [
            InkBarElement
        ]
    }),
    __metadata("design:paramtypes", [])
], SegmentElement);
export { SegmentElement };
//# sourceMappingURL=SegmentElement.js.map