// #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 { Emit } from '../../../../Events/Decorators/EmitDecorator';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Variantable } from '../../../Behaviors/Variantable';
import { KeyboardController } from '../../../Controllers/KeyboardController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { ExpandDirection } from '../../../Types/ExpandDirection';
import { ExpansionMode } from '../../../Types/ExpansionMode';
import { Key } from '../../../Types/Key';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ExpanderElement } from './ExpanderElement';
import { expanderGroupElementTemplate } from './ExpanderGroupElementTemplate';
import { expanderGroupElementJoyStyle } from './Themes/ExpanderGroupElement.Joy';
import { expanderGroupElementRetroStyle } from './Themes/ExpanderGroupElement.Retro';
import { expanderGroupElementCosmopolitanStyle } from './Themes/ExpanderGroupElement.Cosmopolitan';
import { Themeable } from '../../../Behaviors/Themeable';
import { HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Slottable } from '../../../Behaviors/Slottable';
// #endregion
/**
 * ExpanderGroup - A component that represents a group of expandable items.
 *
 * @description
 * The ExpanderGroup component is designed to manage a collection of expander items, allowing users to show or hide
 * related content in a structured manner. It helps in organizing information hierarchically and improves user
 * experience by minimizing clutter.
 *
 * @name ExpanderGroup
 * @element mosaik-expander-group
 * @category UI Components
 *
 * @example
 * ```html
 * <mosaik-expander-group>
 *   <mosaik-expander>
 *     <div slot="header">Expander 1</div>
 *     <div slot="default">Content for expander 1</div>
 *   </mosaik-expander>
 *   <mosaik-expander>
 *     <div slot="header">Expander 2</div>
 *     <div slot="default">Content for expander 2</div>
 *   </mosaik-expander>
 * </mosaik-expander-group>
 * ```
 *
 * @slot - The default slot for placing expander items.
 *
 * @fires expanderChanged - Fired when an expander item is changed.
 *
 * @cssprop {unknown} --expander-group-font-family - The font-family property for the expander group text.
 * @cssprop {unknown} --expander-group-font-size - The font-size property for the expander group text.
 * @cssprop {unknown} --expander-group-font-line-height - The line-height property for the expander group text.
 * @cssprop {unknown} --expander-group-font-weight - The font-weight property for the expander group text.
 * @cssprop {unknown} --expander-group-font-letter-spacing - The letter-spacing property for the expander group text.
 * @cssprop {unknown} --expander-group-font-text-decoration - The text-decoration property for the expander group text.
 * @cssprop {unknown} --expander-group-font-text-transform - The text-transform property for the expander group text.
 * @cssprop {unknown} --expander-group-background-color - The background-color property for the expander group.
 * @cssprop {unknown} --expander-group-foreground-color - The foreground-color property for the expander group.
 * @cssprop {unknown} --expander-group-border-color - The border-color property for the expander group.
 * @cssprop {unknown} --expander-group-border-width - The border-width property for the expander group.
 * @cssprop {unknown} --expander-group-border-radius - The border-radius property for the expander group.
 * @cssprop {unknown} --expander-group-border-style - The border-style property for the expander group.
 * @cssprop {unknown} --expander-group-transition-duration - The transition duration for animations.
 * @cssprop {unknown} --expander-group-transition-mode - The transition mode for animations.
 * @cssprop {unknown} --expander-group-transition-property - The transition property for animations.
 * @cssprop {unknown} --expander-group-padding-top - The padding-top property for the expander group.
 * @cssprop {unknown} --expander-group-padding-left - The padding-left property for the expander group.
 * @cssprop {unknown} --expander-group-padding-bottom - The padding-bottom property for the expander group.
 * @cssprop {unknown} --expander-group-padding-right - The padding-right property for the expander group.
 * @cssprop {unknown} --expander-group-gap - The gap between items in the expander group.
 *
 * @dependency {ExpanderElement} - The Expander element used within the group.
 *
 * @public
 */
let ExpanderGroupElement = class ExpanderGroupElement extends Themeable(Variantable(Appearanceable(Slottable(CustomElement)))) {
    // #region Fields
    _keyboardController;
    _toggled;
    _itemSubscriptions;
    _lastTriggeredExpander;
    _mode;
    _direction;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._mode = ExpansionMode.Single;
        this._direction = ExpandDirection.Down;
        this._toggled = new HTMLElementEventEmitter(this, 'toggled');
        this._itemSubscriptions = [];
        this._lastTriggeredExpander = null;
        this._keyboardController = new KeyboardController(this, { capture: true });
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `{@link is}` property.
     * The `{@link is}` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-expander-group';
    }
    /**
     * Gets or sets the `mode` property.
     *
     * @public
     * @attr
     */
    get mode() {
        return this._mode;
    }
    set mode(value) {
        if (this._mode !== value) {
            this._mode = value;
            this.requestUpdate('mode');
        }
    }
    /**
     * Gets or sets the `direction` property.
     *
     * @public
     * @attr
     */
    get direction() {
        return this._direction;
    }
    set direction(value) {
        if (this._direction !== value) {
            this._direction = value;
            this.requestUpdate('direction');
        }
    }
    /**
     * Called when <ACTION>.
     * Provides reference to `{@link IEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get toggled() {
        return this._toggled;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     */
    collapse(expander) {
        if (!expander.isExpanded) {
            return;
        }
        expander.collapse();
    }
    /**
     * @public
     */
    expand(expander) {
        if (expander.isExpanded) {
            return;
        }
        expander.expand();
    }
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this._keyboardController
            .add(Key.Home, () => {
            const item = this.getEnabledSlotItems().at(0);
            item?.focus();
        }, (e) => this.getEnabledSlotItems().includes(e?.target))
            .add(Key.End, () => {
            const item = this.getEnabledSlotItems().at(-1);
            item?.focus();
        }, (e) => this.getEnabledSlotItems().includes(e?.target))
            .add(Key.UpArrow, (e) => {
            const focusedPanel = e?.target;
            if (!e?.altKey) {
                const panelIndex = this.getEnabledSlotItems().indexOf(focusedPanel);
                const next = this.getEnabledSlotItems()[panelIndex + -1] || focusedPanel;
                if (next === focusedPanel) {
                    return;
                }
                next.focus();
            }
            if (e?.shiftKey && e.altKey) {
                this.getEnabledSlotItems().forEach((p) => this.collapse(p));
            }
        }, (e) => this.getEnabledSlotItems().includes(e?.target))
            .add(Key.DownArrow, (e) => {
            const focusedPanel = e?.target;
            if (!e?.altKey) {
                const panelIndex = this.getEnabledSlotItems().indexOf(focusedPanel);
                const next = this.getEnabledSlotItems()[panelIndex + 1] || focusedPanel;
                if (next === focusedPanel) {
                    return;
                }
                next.focus();
            }
            if (e?.shiftKey && e.altKey) {
                if (this._mode === ExpansionMode.Single) {
                    this.getEnabledSlotItems().forEach((p) => p !== focusedPanel ? this.collapse(p) : this.expand(p));
                    return;
                }
                this.getEnabledSlotItems().forEach((p) => this.expand(p));
            }
        }, (e) => this.getEnabledSlotItems().includes(e?.target));
    }
    /**
     * @public
     * @override
     */
    onSlotChanges() {
        const elements = this.getSlotItems();
        for (const [i, e] of elements.entries()) {
            e.dir = this.dir;
            e.variant = this.variant;
            e.appearance = this.appearance;
            e.direction = this.direction;
            e.lang = this.lang;
            e.dir = this.dir;
            e.classList.add('expander-group-expander');
            e.classList.toggle('first', i === 0);
            e.classList.toggle('inner', i > 0 && i < elements.length - 1);
            e.classList.toggle('last', i === elements.length - 1);
        }
        // filter all enabled items
        const items = this.getEnabledSlotItems();
        this._itemSubscriptions.forEach((x) => x.dispose());
        // clear subscriptions
        this._itemSubscriptions.splice(0, this._itemSubscriptions.length);
        items.forEach((x) => {
            this._itemSubscriptions.push(x.on('toggled', () => this.onToggled({})));
            this._itemSubscriptions.push(x.on('expanded', (e) => {
                this._lastTriggeredExpander = e.target;
                if (this._mode === ExpansionMode.Multiple || !items.includes(this._lastTriggeredExpander)) {
                    return;
                }
                this.getEnabledSlotItems().forEach((y) => {
                    if (y.isExpanded && y !== this._lastTriggeredExpander) {
                        this.collapse(y);
                    }
                });
            }));
        });
        items.filter((x) => x.isExpanded).slice(Math.max(0, 1))
            .forEach((x) => {
            x.isExpanded = false;
        });
    }
    /**
     * Emits the {@link toggled} event.
     *
     * @protected
     */
    onToggled(args) {
        this._toggled.emit(args);
    }
    /**
     * @protected
     */
    onModePropertyChanged(prev, next) {
        if (prev === next) {
            return;
        }
        if (next === ExpansionMode.Single) {
            this.getEnabledSlotItems()
                .filter((x) => this._lastTriggeredExpander?.disabled ?? x !== this._lastTriggeredExpander)
                .forEach((x) => x.isExpanded = false);
        }
    }
    /**
     * @protected
     */
    onDisabledPropertyChange(_prev, next) {
        const elements = this.getSlotItems();
        if (next !== undefined) {
            elements.forEach((x) => x.disabled = next);
        }
    }
    /**
     * @protected
     */
    onAppearancePropertyChange(_prev, next) {
        if (next) {
            const elements = this.getSlotItems();
            elements.forEach((x) => x.appearance = next);
        }
    }
    /**
     * @protected
     */
    onVariantPropertyChange(_prev, next) {
        if (next) {
            const elements = this.getSlotItems();
            elements.forEach((x) => x.variant = next);
        }
    }
    /**
     * @protected
     */
    onDirPropertyChange(_prev, next) {
        if (next) {
            const elements = this.getSlotItems();
            elements.forEach((x) => x.dir = next);
        }
    }
    /**
     * @protected
     */
    onDirectionPropertyChanged(_prev, next) {
        if (next) {
            const elements = this.getSlotItems();
            elements.forEach((x) => x.direction = next);
        }
    }
    /**
     * @private
     */
    getSlotItems() {
        return this.getSlotAssignments('')
            .filter((x) => x instanceof ExpanderElement);
    }
    /**
     * @private
     */
    getEnabledSlotItems() {
        return this.getSlotItems()
            .filter((x) => !x.disabled);
    }
};
__decorate([
    Attribute({ type: ExpansionMode }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], ExpanderGroupElement.prototype, "mode", null);
__decorate([
    Attribute({ type: ExpandDirection }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], ExpanderGroupElement.prototype, "direction", null);
__decorate([
    Emit({ eventName: 'toggled' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ExpanderGroupElement.prototype, "toggled", null);
__decorate([
    Watch('mode'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], ExpanderGroupElement.prototype, "onModePropertyChanged", null);
__decorate([
    Watch('disabled'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Boolean, Boolean]),
    __metadata("design:returntype", void 0)
], ExpanderGroupElement.prototype, "onDisabledPropertyChange", null);
__decorate([
    Watch('appearance'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], ExpanderGroupElement.prototype, "onAppearancePropertyChange", null);
__decorate([
    Watch('variant'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], ExpanderGroupElement.prototype, "onVariantPropertyChange", null);
__decorate([
    Watch('dir'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], ExpanderGroupElement.prototype, "onDirPropertyChange", null);
__decorate([
    Watch('direction'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], ExpanderGroupElement.prototype, "onDirectionPropertyChanged", null);
ExpanderGroupElement = __decorate([
    Component({
        selector: 'mosaik-expander-group',
        template: expanderGroupElementTemplate,
        themes: {
            joy: expanderGroupElementJoyStyle,
            retro: expanderGroupElementRetroStyle,
            cosmopolitan: expanderGroupElementCosmopolitanStyle
        },
        imports: [
            ExpanderElement
        ]
    }),
    __metadata("design:paramtypes", [])
], ExpanderGroupElement);
export { ExpanderGroupElement };
//# sourceMappingURL=ExpanderGroupElement.js.map