// #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 { Disableable } from '../../../Behaviors/Disableable';
import { Orientable } from '../../../Behaviors/Orientable';
import { Valueable } from '../../../Behaviors/Valueable';
import { ColorController } from '../../../Controllers/ColorController';
import { ResizeController } from '../../../Controllers/ResizeController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { QueryChild } from '../../../Decorators/QueryChildDecorator';
import { FlowDirection } from '../../../Types/FlowDirection';
import { Orientation } from '../../../Types/Orientation';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ColorThumbElement } from '../ColorThumb/ColorThumbElement';
import { colorSliderElementJoyStyle } from './Themes/ColorSliderElement.Joy';
import { colorSliderElementRetroStyle } from './Themes/ColorSliderElement.Retro';
import { colorSliderElementCosmopolitanStyle } from './Themes/ColorSliderElement.Cosmopolitan';
import { Themeable } from '../../../Behaviors/Themeable';
// #endregion
/**
 * The `{@link ColorSliderElement}` element.
 *
 * @public
 */
let ColorSliderElement = class ColorSliderElement extends Themeable(Disableable(Orientable(Valueable(CustomElement)))) {
    // #region Fields
    _resizeController;
    _colorController;
    _thumb;
    _input;
    _color;
    _step;
    _altered;
    _boundingClientRect;
    _pointerDown;
    _focused;
    _sliderHandlePosition;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._color = '';
        this._step = 0.01;
        this._pointerDown = false;
        this._altered = 0;
        this._focused = false;
        this._sliderHandlePosition = 0;
        this._resizeController = new ResizeController(this, {
            callback: (entries) => {
                for (const entry of entries) {
                    this._boundingClientRect = entry.contentRect;
                }
            }
        });
        this._colorController = new ColorController(this, {
            applyColorToState: () => {
                this._sliderHandlePosition = 100 * (this._colorController.hue / 360);
            },
            extractColorFromState: (controller) => ({
                ...controller.getColor('hsl'),
                h: this.value
            }),
            maintains: 'saturation'
        });
    }
    // #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-slider';
    }
    /**
     * Gets or sets the `color` property.
     *
     * @public
     * @attr
     */
    get color() {
        return this._color;
    }
    set color(value) {
        if (this._color !== value) {
            this._color = value;
            this.requestUpdate('color');
        }
    }
    /**
     * Gets or sets the `step` property.
     *
     * @private
     * @template
     */
    get step() {
        return this._step;
    }
    set step(value) {
        if (this._step !== value) {
            this._step = value;
            this.requestUpdate('step');
        }
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this.on('focus', (e) => this.handleFocus());
        this.on('blur', (e) => this.handleBlur());
    }
    onApplyTemplate() {
        super.onApplyTemplate();
        const thumb = this.getTemplatePart('thumb');
        thumb.on('pointerdown', (e) => this.handlePointerdown(e));
        thumb.on('pointermove', (e) => this.handlePointermove(e));
        thumb.on('pointerup', (e) => this.handlePointerup(e));
        thumb.on('pointercancel', (e) => this.handlePointerup(e));
        thumb.on('pointerleave', (e) => this.handlePointerup(e));
        this._boundingClientRect = this.getBoundingClientRect();
    }
    handleKeydown(event) {
        this._focused = true;
        this._altered = [event.shiftKey, event.ctrlKey, event.altKey].filter((key) => !!key).length;
        let delta = 0;
        switch (event.key) {
            case 'ArrowUp':
                delta = this.step;
                break;
            case 'ArrowDown':
                delta = -this.step;
                break;
            case 'ArrowLeft':
                delta = this.step * (this.dir === FlowDirection.LeftToRight ? -1 : 1);
                break;
            case 'ArrowRight':
                delta = this.step * (this.dir === FlowDirection.LeftToRight ? 1 : -1);
                break;
            default:
                return;
        }
        event.preventDefault();
        const range = 360;
        const mult = 100 / range;
        this._sliderHandlePosition = Math.min(100, Math.max(0, this._sliderHandlePosition + delta * mult));
        this.value = Math.min(100, Math.max(0, this.value + delta));
        this._colorController.applyColorFromState();
        if (delta !== 0) {
            this.emit('input', {
                bubbles: true,
                composed: true
            });
            this.emit('change', {
                bubbles: true,
                composed: true
            });
        }
    }
    handleInput(event) {
        this.value = event.target.valueAsNumber;
        this._sliderHandlePosition = 100 * (this.value / 360);
        this._colorController.applyColorFromState();
    }
    handleChange(event) {
        this.handleInput(event);
        this.emit('change', {
            bubbles: true,
            composed: true
        });
    }
    focus(focusOptions = {}) {
        super.focus(focusOptions);
        this.forwardFocus();
    }
    forwardFocus() {
        this._focused = true;
        this._input.focus();
    }
    handleFocus() {
        this._focused = true;
    }
    handleBlur() {
        if (this._pointerDown) {
            return;
        }
        this._altered = 0;
        this._focused = false;
    }
    handlePointerdown(event) {
        if (event.button !== 0) {
            event.preventDefault();
            return;
        }
        this._pointerDown = true;
        this._colorController.savePreviousColor();
        this._boundingClientRect = this.getBoundingClientRect();
        event.target.setPointerCapture(event.pointerId);
        if (event.pointerType === 'mouse') {
            this._focused = true;
        }
    }
    handlePointermove(event) {
        this._sliderHandlePosition = this.calculateHandlePosition(event);
        this.value = 360 * (this._sliderHandlePosition / 100);
        this._colorController.applyColorFromState();
        this.dispatchEvent(new Event('input', {
            bubbles: true,
            composed: true,
            cancelable: true
        }));
    }
    handlePointerup(event) {
        this._pointerDown = false;
        event.target.releasePointerCapture(event.pointerId);
        const shouldApplyDefault = this.dispatchEvent(new Event('change', {
            bubbles: true,
            composed: true,
            cancelable: true
        }));
        if (!shouldApplyDefault) {
            this._colorController.restorePreviousColor();
        }
        // Retain focus on input element after mouse up to enable keyboard interactions
        this.focus();
        if (event.pointerType === 'mouse') {
            this._focused = false;
        }
    }
    /**
     * Returns the value under the cursor
     * @param: PointerEvent on slider
     * @return: Slider value that correlates to the position under the pointer
     */
    calculateHandlePosition(event) {
        if (!this._boundingClientRect) {
            return this._sliderHandlePosition;
        }
        const rect = this._boundingClientRect;
        const minOffset = this.orientation === Orientation.Horizontal ? rect.top : rect.left;
        const offset = this.orientation === Orientation.Horizontal ? event.clientY : event.clientX;
        const size = this.orientation === Orientation.Horizontal ? rect.height : rect.width;
        const percent = Math.max(0, Math.min(1, (offset - minOffset) / size));
        const sliderHandlePosition = this.orientation === Orientation.Horizontal || this.dir !== FlowDirection.LeftToRight ? 100 - 100 * percent : 100 * percent;
        return sliderHandlePosition;
    }
    handleGradientPointerdown(event) {
        if (event.button !== 0) {
            return;
        }
        event.stopPropagation();
        event.preventDefault();
        this._thumb.dispatchEvent(new PointerEvent('pointerdown', event));
        this.handlePointermove(event);
    }
    get handlePositionStyles() {
        return `${this.orientation === Orientation.Vertical ? 'inset-block-end' : 'inset-inline-start'}: ${this._sliderHandlePosition}%`;
    }
};
__decorate([
    QueryChild('[part="thumb"]'),
    __metadata("design:type", ColorThumbElement)
], ColorSliderElement.prototype, "_thumb", void 0);
__decorate([
    QueryChild('[part="slider x"]'),
    __metadata("design:type", HTMLInputElement)
], ColorSliderElement.prototype, "_input", void 0);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], ColorSliderElement.prototype, "color", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], ColorSliderElement.prototype, "step", null);
ColorSliderElement = __decorate([
    Component({
        selector: 'mosaik-color-slider',
        // template: colorSliderElementTemplate,
        themes: {
            joy: colorSliderElementJoyStyle,
            retro: colorSliderElementRetroStyle,
            cosmopolitan: colorSliderElementCosmopolitanStyle
        },
        imports: [
            ColorThumbElement
        ]
    }),
    __metadata("design:paramtypes", [])
], ColorSliderElement);
export { ColorSliderElement };
//# sourceMappingURL=ColorSliderElement.js.map