// #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 { HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Emit } from '../../../../events/Decorators/EmitDecorator';
import { Disableable } from '../../../Behaviors/Disableable';
import { Focusable } from '../../../Behaviors/Focusable';
import { Themeable } from '../../../Behaviors/Themeable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { colorEditorPaletteElementTemplate } from './ColorEditorPaletteElementTemplate';
import { IColorPalette } from './IColorPalette';
import { colorEditorPaletteElementCosmopolitanStyle } from './Themes/ColorEditorPaletteElement.Cosmopolitan';
import { colorEditorPaletteElementJoyStyle } from './Themes/ColorEditorPaletteElement.Joy';
import { colorEditorPaletteElementMemphisStyle } from './Themes/ColorEditorPaletteElement.Memphis';
// #endregion
/**
 * Color Editor Palette - A component for displaying and selecting colors from predefined palettes.
 *
 * @name ColorEditorPalette
 * @element mosaik-color-editor-palette
 *
 * @description
 * The Color Editor Palette component displays a grid of color swatches from one or more
 * predefined palettes. Users can select colors from the palette and optionally add custom
 * colors to a user palette. The component supports switching between multiple palettes
 * via a panel interface.
 *
 * @category Media
 *
 * @fires paletteSelect {PaletteSelectEvent} - Fired when a color is selected from the palette
 * @fires paletteAdd {PaletteAddEvent} - Fired when the add button is clicked (for custom palette)
 * @fires paletteChanged {PaletteChangedEvent} - Fired when the active palette is changed
 * @fires paletteCustomChanged {PaletteChangedEvent} - Fired when colors are added or removed from the custom palette. Detail contains { colors: Array<string> }
 *
 * @csspart header - The header row containing title and switcher
 * @csspart title - The palette name display
 * @csspart switcher - The button to open palette selector panel
 * @csspart colors - The container for color swatches
 * @csspart color-item - Individual color swatch buttons
 * @csspart add-button - The button to add current color to custom palette
 * @csspart panel - The palette selector panel
 * @csspart panel-item-more - The "+N" text showing remaining colors count
 *
 * @public
 */
let ColorEditorPaletteElement = class ColorEditorPaletteElement extends Themeable(Disableable(Focusable(CustomElement))) {
    // #region Fields
    _paletteSelect;
    _paletteAdd;
    _paletteChanged;
    _paletteCustomChanged;
    _palettes;
    _selectedPalette;
    _allowAdd;
    _currentColor;
    _panelOpen;
    _panelAnchor;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the ColorEditorPaletteElement class.
     *
     * @public
     */
    constructor() {
        super();
        this._paletteSelect = new HTMLElementEventEmitter(this, 'paletteSelect');
        this._paletteAdd = new HTMLElementEventEmitter(this, 'paletteAdd');
        this._paletteChanged = new HTMLElementEventEmitter(this, 'paletteChanged');
        this._paletteCustomChanged = new HTMLElementEventEmitter(this, 'paletteCustomChanged');
        this._palettes = IColorPalette.allPalettes();
        this._selectedPalette = IColorPalette.MATERIAL_PALETTE.title;
        this._allowAdd = false;
        this._currentColor = '#ff0000';
        this._panelOpen = false;
        this._panelAnchor = null;
    }
    // #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-color-editor-palette';
    }
    /**
     * Gets or sets the available palettes.
     *
     * @public
     */
    get palettes() {
        return this._palettes;
    }
    set palettes(value) {
        if (this._palettes !== value) {
            this._palettes = value;
            this.requestUpdate('palettes');
        }
    }
    /**
     * Gets or sets the currently selected palette name.
     *
     * @public
     * @attr
     */
    get selectedPalette() {
        return this._selectedPalette;
    }
    set selectedPalette(value) {
        if (this._selectedPalette !== value) {
            this._selectedPalette = value;
            this.requestUpdate('selectedPalette');
        }
    }
    /**
     * Gets or sets whether to show the add button (for custom palettes).
     *
     * @public
     */
    get allowAdd() {
        return this._allowAdd;
    }
    set allowAdd(value) {
        if (this._allowAdd !== value) {
            this._allowAdd = value;
            this.requestUpdate('allowAdd');
        }
    }
    /**
     * Gets or sets the current color (used for adding to custom palette).
     *
     * @public
     * @attr
     */
    get currentColor() {
        return this._currentColor;
    }
    set currentColor(value) {
        if (this._currentColor !== value) {
            this._currentColor = value;
            this.requestUpdate('currentColor');
        }
    }
    /**
     * Called when a color is selected from the palette.
     * Provides reference to `{@link IPaletteSelectEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get paletteSelect() {
        return this._paletteSelect;
    }
    /**
     * Called when the add button is clicked.
     * Provides reference to `{@link IPaletteAddEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get paletteAdd() {
        return this._paletteAdd;
    }
    /**
     * Called when the active palette is changed.
     * Provides reference to `{@link IPaletteChangedEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get paletteChanged() {
        return this._paletteChanged;
    }
    /**
     * Called when colors are added or removed from the custom palette.
     * Provides reference to `{@link IPaletteChangedEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get paletteCustomChanged() {
        return this._paletteCustomChanged;
    }
    // #endregion
    // #region Methods
    // #region Properties
    /**
     * Gets whether the panel is open.
     *
     * @public
     */
    get panelOpen() {
        return this._panelOpen;
    }
    /**
     * Gets or sets the anchor element for the panel.
     * When set, the panel will be positioned and sized relative to this element.
     *
     * @public
     */
    get panelAnchor() {
        return this._panelAnchor;
    }
    set panelAnchor(value) {
        if (this._panelAnchor !== value) {
            this._panelAnchor = value;
            this.requestUpdate('panelAnchor');
        }
    }
    /**
     * Gets the computed panel styles based on the anchor element.
     *
     * @public
     */
    getPanelStyles() {
        if (!this._panelAnchor || !this._panelOpen) {
            return '';
        }
        const anchorRect = this._panelAnchor.getBoundingClientRect();
        const hostRect = this.getBoundingClientRect();
        const top = hostRect.top - anchorRect.top;
        const left = hostRect.left - anchorRect.left;
        const width = anchorRect.width;
        const height = anchorRect.height;
        return `top: ${-top}px; left: ${-left}px; width: ${width}px; height: ${height}px;`;
    }
    // #endregion
    /**
     * Gets the currently active palette.
     *
     * @public
     */
    getActivePalette() {
        return this._palettes.find((p) => p.title === this._selectedPalette);
    }
    /**
     * Handles color item click.
     *
     * @public
     */
    handleColorClick(color) {
        if (!this.disabled) {
            this._paletteSelect.emit({
                color: color
            });
        }
    }
    /**
     * Handles add button click.
     *
     * @public
     */
    handleAddClick() {
        if (!this.disabled) {
            this._paletteAdd.emit({ color: this._currentColor });
        }
    }
    /**
     * Handles switcher button click.
     *
     * @public
     */
    handleSwitcherClick() {
        this._panelOpen = !this._panelOpen;
        this.requestUpdate();
    }
    /**
     * Handles panel close.
     *
     * @public
     */
    handlePanelClose() {
        this._panelOpen = false;
        this.requestUpdate();
    }
    /**
     * Handles palette selection from panel.
     *
     * @public
     */
    handlePaletteSelect(paletteName) {
        this._selectedPalette = paletteName;
        this._panelOpen = false;
        this.requestUpdate();
        this._paletteChanged.emit({ palette: paletteName });
    }
    /**
     * Adds a color to the custom palette.
     *
     * @param color - The color to add
     * @public
     */
    addColorToCustomPalette(color) {
        const customPalette = this._palettes.find((p) => p.mutable === true);
        if (customPalette && !customPalette.colors.includes(color)) {
            customPalette.colors.push(color);
            this.requestUpdate('palettes');
            this._paletteCustomChanged.emit({ colors: [...customPalette.colors] });
        }
    }
    /**
     * Removes a color from the custom palette.
     *
     * @param color - The color to remove
     * @public
     */
    removeColorFromCustomPalette(color) {
        const customPalette = this._palettes.find((p) => p.mutable === true);
        if (customPalette) {
            const index = customPalette.colors.indexOf(color);
            if (index !== -1) {
                customPalette.colors.splice(index, 1);
                this.requestUpdate('palettes');
                this._paletteCustomChanged.emit({ colors: [...customPalette.colors] });
            }
        }
    }
    /**
     * Gets the colors from the custom (mutable) palette.
     *
     * @returns The array of colors in the custom palette
     * @public
     */
    getCustomPaletteColors() {
        const customPalette = this._palettes.find((p) => p.mutable === true);
        return customPalette ? [...customPalette.colors] : [];
    }
    /**
     * Sets the colors for the custom (mutable) palette.
     * This replaces all existing colors in the custom palette.
     *
     * @param colors - The array of colors to set
     * @public
     */
    setCustomPaletteColors(colors) {
        const customPalette = this._palettes.find((p) => p.mutable === true);
        if (customPalette) {
            customPalette.colors = [...colors];
            this.requestUpdate('palettes');
        }
    }
};
__decorate([
    Property({ type: Array }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], ColorEditorPaletteElement.prototype, "palettes", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], ColorEditorPaletteElement.prototype, "selectedPalette", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], ColorEditorPaletteElement.prototype, "allowAdd", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], ColorEditorPaletteElement.prototype, "currentColor", null);
__decorate([
    Emit({ eventName: 'paletteSelect' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ColorEditorPaletteElement.prototype, "paletteSelect", null);
__decorate([
    Emit({ eventName: 'paletteAdd' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ColorEditorPaletteElement.prototype, "paletteAdd", null);
__decorate([
    Emit({ eventName: 'paletteChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ColorEditorPaletteElement.prototype, "paletteChanged", null);
__decorate([
    Emit({ eventName: 'paletteCustomChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ColorEditorPaletteElement.prototype, "paletteCustomChanged", null);
__decorate([
    Property({ type: HTMLElement }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], ColorEditorPaletteElement.prototype, "panelAnchor", null);
ColorEditorPaletteElement = __decorate([
    Component({
        selector: 'mosaik-color-editor-palette',
        template: colorEditorPaletteElementTemplate,
        themes: {
            joy: colorEditorPaletteElementJoyStyle,
            memphis: colorEditorPaletteElementMemphisStyle,
            cosmopolitan: colorEditorPaletteElementCosmopolitanStyle
        }
    }),
    __metadata("design:paramtypes", [])
], ColorEditorPaletteElement);
export { ColorEditorPaletteElement };
//# sourceMappingURL=ColorEditorPaletteElement.js.map