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;
};
import { UmbLitElement } from '../../lit-element/index.js';
import { css, customElement, html, property, query, state, } from '../../../../external/lit/index.js';
import { clamp } from '../../utils/index.js';
/**
 * Custom element for a split panel with adjustable divider.
 * @element umb-split-panel
 * @slot start - Content for the start panel.
 * @slot end - Content for the end panel.
 * @cssprop --umb-split-panel-initial-position - Initial position of the divider.
 * @cssprop --umb-split-panel-start-min-width - Minimum width of the start panel.
 * @cssprop --umb-split-panel-end-min-width - Minimum width of the end panel.
 * @cssprop --umb-split-panel-divider-touch-area-width - Width of the divider touch area.
 * @cssprop --umb-split-panel-divider-width - Width of the divider.
 * @cssprop --umb-split-panel-divider-color - Color of the divider.
 */
let UmbSplitPanelElement = class UmbSplitPanelElement extends UmbLitElement {
    constructor() {
        super(...arguments);
        /**
         * Locking mode for the split panel.
         * Possible values: "start", "end", "none" (default).
         */
        this.lock = 'none';
        /**
         * Initial position of the divider.
         * Pixel or percent value: e.g., "100px" or "25%".
         * Defaults to a CSS variable if not set: "var(--umb-split-panel-initial-position) which defaults to 50%".
         */
        this.position = 'var(--umb-split-panel-initial-position)';
        //TODO: Add support for negative values (relative to end of container) similar to snap points.
        /** Width of the locked panel when in "start" or "end" lock mode */
        this.#lockedPanelWidth = 0;
        /** Pixel value for the snap threshold. Determines how close the divider needs to be to a snap point to snap to it. */
        this.#SNAP_THRESHOLD = 25;
        this._hasStartPanel = false;
        this._hasEndPanel = false;
        this.#hasInitialized = false;
        this.#onDragStart = (event) => {
            event.preventDefault();
            const move = (event) => {
                const { clientX } = event;
                const { left, width } = this.mainElement.getBoundingClientRect();
                const localPos = clamp(clientX - left, 0, width);
                const mappedPos = mapXAxisToSnap(localPos, width);
                this.#lockedPanelWidth = this.lock === 'start' ? mappedPos : width - mappedPos;
                this.#setPosition(mappedPos);
            };
            const stop = () => {
                document.removeEventListener('pointermove', move);
                document.removeEventListener('pointerup', stop);
                this.dispatchEvent(new CustomEvent('position-changed', { detail: { position: this.position } }));
            };
            const mapXAxisToSnap = (xPos, containerWidth) => {
                const snaps = this.snap?.split(' ');
                if (!snaps)
                    return xPos;
                const snapsInPixels = snaps.map((snap) => {
                    let snapPx = parseFloat(snap);
                    if (snap.endsWith('%')) {
                        snapPx = (snapPx / 100) * containerWidth;
                    }
                    if (snap.startsWith('-')) {
                        snapPx = containerWidth + snapPx;
                    }
                    return snapPx;
                });
                const closestSnap = snapsInPixels.reduce((prev, curr) => {
                    return Math.abs(curr - xPos) < Math.abs(prev - xPos) ? curr : prev;
                });
                if (closestSnap < xPos + this.#SNAP_THRESHOLD && closestSnap > xPos - this.#SNAP_THRESHOLD) {
                    xPos = closestSnap;
                }
                return xPos;
            };
            document.addEventListener('pointermove', move, { passive: true });
            document.addEventListener('pointerup', stop);
        };
    }
    //TODO: Add support for negative values (relative to end of container) similar to snap points.
    /** Width of the locked panel when in "start" or "end" lock mode */
    #lockedPanelWidth;
    /** Pixel value for the snap threshold. Determines how close the divider needs to be to a snap point to snap to it. */
    #SNAP_THRESHOLD;
    get #hasBothPanels() {
        return this._hasStartPanel && this._hasEndPanel;
    }
    #hasInitialized;
    disconnectedCallback() {
        super.disconnectedCallback();
        this.#disconnect();
    }
    updated(_changedProperties) {
        super.updated(_changedProperties);
        if (!this.#hasInitialized)
            return;
        if (_changedProperties.has('position')) {
            if (this.lock !== 'none') {
                const { width } = this.mainElement.getBoundingClientRect();
                let pos = parseFloat(this.position);
                if (this.position.endsWith('%')) {
                    pos = (pos / 100) * width;
                }
                const lockedPanelWidth = this.lock === 'start' ? pos : width - pos;
                this.#lockedPanelWidth = lockedPanelWidth;
            }
            this.#updateSplit();
        }
    }
    #setPosition(pos) {
        const { width } = this.mainElement.getBoundingClientRect();
        const localPos = clamp(pos, 0, width);
        const percentagePos = (localPos / width) * 100;
        this.position = percentagePos + '%';
        // Update ARIA value for divider
        const formatted = percentagePos.toFixed(0);
        const ariaText = this.localize?.term('general_dividerPosition', [formatted]) ?? `Divider at ${formatted}%`;
        this.dividerTouchAreaElement.setAttribute('aria-valuetext', ariaText);
    }
    #updateSplit() {
        // If lock is none
        let maxStartWidth = this.position;
        let maxEndWidth = '1fr';
        if (this.lock === 'start') {
            maxStartWidth = this.#lockedPanelWidth + 'px';
            maxEndWidth = `1fr`;
        }
        if (this.lock === 'end') {
            maxStartWidth = `1fr`;
            maxEndWidth = this.#lockedPanelWidth + 'px';
        }
        this.mainElement.style.gridTemplateColumns = `
      minmax(var(--umb-split-panel-start-min-width), ${maxStartWidth})
      0px
      minmax(var(--umb-split-panel-end-min-width), ${maxEndWidth})
    `;
    }
    #onDragStart;
    #disconnect() {
        this.dividerTouchAreaElement.removeEventListener('pointerdown', this.#onDragStart);
        this.dividerTouchAreaElement.removeEventListener('touchstart', this.#onDragStart);
        this.dividerElement.style.display = 'none';
        this.mainElement.style.display = 'flex';
        this.#hasInitialized = false;
    }
    async #connect() {
        this.#hasInitialized = true;
        this.mainElement.style.display = 'grid';
        this.mainElement.style.gridTemplateColumns = `${this.position} 0px 1fr`;
        this.dividerElement.style.display = 'unset';
        this.dividerTouchAreaElement.addEventListener('pointerdown', this.#onDragStart);
        this.dividerTouchAreaElement.addEventListener('touchstart', this.#onDragStart, { passive: false });
        // Wait for the next frame to get the correct position of the divider.
        await new Promise((resolve) => requestAnimationFrame(resolve));
        const { left: dividerLeft } = this.shadowRoot.querySelector('#divider').getBoundingClientRect();
        const { left: mainLeft, width: mainWidth } = this.mainElement.getBoundingClientRect();
        const percentagePos = ((dividerLeft - mainLeft) / mainWidth) * 100;
        this.position = `${percentagePos}%`;
    }
    #onSlotChanged(event) {
        const slot = event.target;
        const name = slot.name;
        if (name === 'start') {
            this._hasStartPanel = slot.assignedElements().length > 0;
        }
        if (name === 'end') {
            this._hasEndPanel = slot.assignedElements().length > 0;
        }
        if (!this.#hasBothPanels) {
            if (this.#hasInitialized) {
                this.#disconnect();
            }
            return;
        }
        this.#connect();
    }
    #onKeydown(event) {
        if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
            const { width } = this.mainElement.getBoundingClientRect();
            const divider = this.dividerElement.getBoundingClientRect();
            const dividerPos = divider.left - this.mainElement.getBoundingClientRect().left;
            const percentageFromWidth = (dividerPos / width) * 100;
            const multiplier = event.shiftKey ? 10 : 1;
            const step = 1 * multiplier * (event.key === 'ArrowLeft' ? -1 : 1);
            const newPercent = percentageFromWidth + step;
            const toPixels = (newPercent / 100) * this.mainElement.getBoundingClientRect().width;
            this.#setPosition(toPixels);
        }
        if (event.key === 'Home' || event.key === 'End') {
            event.preventDefault();
            const { width } = this.mainElement.getBoundingClientRect();
            const newPos = event.key === 'Home' ? 0 : width;
            this.#setPosition(newPos);
        }
    }
    render() {
        return html `
			<div id="main">
				<slot
					name="start"
					@slotchange=${this.#onSlotChanged}
					style="width: ${this._hasStartPanel ? '100%' : '0'}"></slot>
				<div id="divider">
					<div id="divider-touch-area" tabindex="0" @keydown=${this.#onKeydown}></div>
				</div>
				<slot name="end" @slotchange=${this.#onSlotChanged} style="width: ${this._hasEndPanel ? '100%' : '0'}"></slot>
			</div>
		`;
    }
    static { this.styles = css `
		:host {
			display: contents;
			--umb-split-panel-initial-position: 50%;
			--umb-split-panel-start-min-width: 0;
			--umb-split-panel-end-min-width: 0;
			--umb-split-panel-divider-touch-area-width: 12px;
			--umb-split-panel-divider-width: 1px;
			--umb-split-panel-divider-color: transparent;
			--umb-split-panel-slot-overflow: hidden;
		}
		slot {
			overflow: var(--umb-split-panel-slot-overflow);
			display: block;
			min-height: 0;
		}
		#main {
			width: 100%;
			height: 100%;
			display: flex;
			position: relative;
			z-index: 0;
			overflow: hidden;
		}
		#divider {
			height: 100%;
			position: relative;
			z-index: 999999;
			display: none;
		}
		#divider-touch-area {
			position: absolute;
			top: 0;
			left: -1px;
			height: 100%;
			width: var(--umb-split-panel-divider-touch-area-width);
			cursor: col-resize;
		}
		/* Do we want a line that shows the divider? */
		#divider::after {
			content: '';
			position: absolute;
			top: 0;
			left: 50%;
			width: var(--umb-split-panel-divider-width);
			height: 100%;
			transform: round(translateX(-50%));
			background-color: var(--umb-split-panel-divider-color);
			z-index: -1;
		}
	`; }
};
__decorate([
    query('#main')
], UmbSplitPanelElement.prototype, "mainElement", void 0);
__decorate([
    query('#divider-touch-area')
], UmbSplitPanelElement.prototype, "dividerTouchAreaElement", void 0);
__decorate([
    query('#divider')
], UmbSplitPanelElement.prototype, "dividerElement", void 0);
__decorate([
    property({ type: String })
], UmbSplitPanelElement.prototype, "snap", void 0);
__decorate([
    property({ type: String })
], UmbSplitPanelElement.prototype, "lock", void 0);
__decorate([
    property({ type: String, reflect: true })
], UmbSplitPanelElement.prototype, "position", void 0);
__decorate([
    state()
], UmbSplitPanelElement.prototype, "_hasStartPanel", void 0);
__decorate([
    state()
], UmbSplitPanelElement.prototype, "_hasEndPanel", void 0);
UmbSplitPanelElement = __decorate([
    customElement('umb-split-panel')
], UmbSplitPanelElement);
export { UmbSplitPanelElement };
