// #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 { ResizeController } from '../../../Controllers/ResizeController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { colorEditorAreaElementTemplate } from './ColorEditorAreaElementTemplate';
import { colorEditorAreaElementCosmopolitanStyle } from './Themes/ColorEditorAreaElement.Cosmopolitan';
import { colorEditorAreaElementJoyStyle } from './Themes/ColorEditorAreaElement.Joy';
import { colorEditorAreaElementMemphisStyle } from './Themes/ColorEditorAreaElement.Memphis';
// #endregion
/**
 * Color Editor Area - A 2D gradient picker for selecting saturation and value in HSV color space.
 *
 * @name ColorEditorArea
 * @element mosaik-color-editor-area
 *
 * @description
 * The Color Editor Area component provides an interactive 2D color picking surface
 * where users can select saturation (x-axis) and value/brightness (y-axis) for a given hue.
 * This component is commonly used within color pickers to provide intuitive color selection.
 *
 * @category Media
 *
 * @fires colorAreaChanged {ColorAreaChangedEvent} - Fired when the saturation or value changes via user interaction
 *
 * @csspart thumb - The draggable indicator showing current position
 * @csspart gradient-saturation - The horizontal saturation gradient overlay
 * @csspart gradient-value - The vertical value/brightness gradient overlay
 *
 * @public
 */
let ColorEditorAreaElement = class ColorEditorAreaElement extends Themeable(Disableable(Focusable(CustomElement))) {
    // #region Fields
    _resizeController;
    _colorAreaChanged;
    _hue;
    _saturation;
    _value;
    _boundingClientRect;
    _pointerDown;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the ColorEditorAreaElement class.
     *
     * @public
     */
    constructor() {
        super();
        this._colorAreaChanged = new HTMLElementEventEmitter(this, 'colorAreaChanged');
        this._hue = 0;
        this._saturation = 1;
        this._value = 1;
        this._pointerDown = false;
        this._resizeController = new ResizeController(this, {
            callback: (entries) => {
                for (const entry of entries) {
                    this._boundingClientRect = entry.contentRect;
                }
            }
        });
    }
    // #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-area';
    }
    /**
     * Gets or sets the hue value (0-360).
     *
     * @public
     * @attr
     */
    get hue() {
        return this._hue;
    }
    set hue(value) {
        if (this._hue !== value) {
            this._hue = Math.max(0, Math.min(360, value));
            this.requestUpdate('hue');
        }
    }
    /**
     * Gets or sets the saturation value (0-1).
     *
     * @public
     */
    get saturation() {
        return this._saturation;
    }
    set saturation(value) {
        if (this._saturation !== value) {
            this._saturation = Math.max(0, Math.min(1, value));
            this.requestUpdate('saturation');
        }
    }
    /**
     * Gets or sets the value/brightness (0-1).
     *
     * @public
     */
    get value() {
        return this._value;
    }
    set value(value) {
        if (this._value !== value) {
            this._value = Math.max(0, Math.min(1, value));
            this.requestUpdate('value');
        }
    }
    /**
     * Called when the saturation or value changes.
     * Provides reference to `{@link IColorAreaChangedEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get colorAreaChanged() {
        return this._colorAreaChanged;
    }
    // #endregion
    // #region Methods
    /**
     * @inheritdoc
     * @public
     */
    connectedCallback() {
        super.connectedCallback();
        this.on('pointerdown', (e) => this.onPointerDown(e));
        this.on('pointermove', (e) => this.onPointerMove(e));
        this.on('pointerup', (e) => this.onPointerUp(e));
        this.on('pointercancel', (e) => this.onPointerUp(e));
        this.on('keydown', (e) => this.onKeyDown(e));
    }
    /**
     * Updates the color from external HSV values.
     *
     * @param hue - The hue value (0-360)
     * @param saturation - The saturation value (0-1)
     * @param value - The value/brightness (0-1)
     * @public
     */
    setColor(hue, saturation, value) {
        this._hue = Math.max(0, Math.min(360, hue));
        this._saturation = Math.max(0, Math.min(1, saturation));
        this._value = Math.max(0, Math.min(1, value));
        this.requestUpdate();
    }
    /**
     * @inheritdoc
     * @protected
     */
    firstUpdated(changedProperties) {
        super.firstUpdated(changedProperties);
        this._boundingClientRect = this.getBoundingClientRect();
    }
    /**
     * Handles pointer down events to start dragging.
     *
     * @private
     */
    onPointerDown(event) {
        if (this.disabled) {
            return;
        }
        this._pointerDown = true;
        this.setPointerCapture(event.pointerId);
        this.updatePositionFromPointer(event);
    }
    /**
     * Handles pointer move events for dragging.
     *
     * @private
     */
    onPointerMove(event) {
        if (!this._pointerDown || this.disabled) {
            return;
        }
        this.updatePositionFromPointer(event);
    }
    /**
     * Handles pointer up events to stop dragging.
     *
     * @private
     */
    onPointerUp(event) {
        if (this._pointerDown) {
            this._pointerDown = false;
            this.releasePointerCapture(event.pointerId);
        }
    }
    /**
     * Handles keyboard navigation.
     *
     * @private
     */
    onKeyDown(event) {
        if (this.disabled) {
            return;
        }
        const step = event.shiftKey ? 0.1 : 0.01;
        let handled = false;
        switch (event.key) {
            case 'ArrowLeft':
                this.saturation = Math.max(0, this._saturation - step);
                handled = true;
                break;
            case 'ArrowRight':
                this.saturation = Math.min(1, this._saturation + step);
                handled = true;
                break;
            case 'ArrowUp':
                this.value = Math.min(1, this._value + step);
                handled = true;
                break;
            case 'ArrowDown':
                this.value = Math.max(0, this._value - step);
                handled = true;
                break;
        }
        if (handled) {
            event.preventDefault();
            this.emitChange();
        }
    }
    /**
     * Updates the saturation and value from pointer coordinates.
     *
     * @private
     */
    updatePositionFromPointer(event) {
        // Always use getBoundingClientRect() for pointer calculations since
        // ResizeObserver's contentRect has left/top = 0 (relative to element, not viewport)
        const rect = this.getBoundingClientRect();
        const x = Math.max(0, Math.min(1, (event.clientX - rect.left) / rect.width));
        const y = Math.max(0, Math.min(1, 1 - ((event.clientY - rect.top) / rect.height)));
        this.saturation = x;
        this.value = y;
        this.emitChange();
    }
    /**
     * Emits the change event with current values.
     *
     * @private
     */
    emitChange() {
        this._colorAreaChanged.emit({
            hue: this._hue,
            saturation: this._saturation,
            value: this._value
        });
    }
};
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], ColorEditorAreaElement.prototype, "hue", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], ColorEditorAreaElement.prototype, "saturation", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], ColorEditorAreaElement.prototype, "value", null);
__decorate([
    Emit({ eventName: 'colorAreaChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ColorEditorAreaElement.prototype, "colorAreaChanged", null);
ColorEditorAreaElement = __decorate([
    Component({
        selector: 'mosaik-color-editor-area',
        template: colorEditorAreaElementTemplate,
        themes: {
            joy: colorEditorAreaElementJoyStyle,
            memphis: colorEditorAreaElementMemphisStyle,
            cosmopolitan: colorEditorAreaElementCosmopolitanStyle
        },
        host: {
            'tabindex': '0',
            'role': 'slider',
            'aria-label': 'Color saturation and brightness'
        }
    }),
    __metadata("design:paramtypes", [])
], ColorEditorAreaElement);
export { ColorEditorAreaElement };
//# sourceMappingURL=ColorEditorAreaElement.js.map