/**
 * Copyright Aquera Inc 2023
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */
import { __decorate } from "tslib";
import { styles } from './nile-split-panel.css';
import NileElement from '../internal/nile-element';
import { clamp } from '../internal/math';
import { customElement, property, query } from 'lit/decorators.js';
import { drag } from '../internal/drag';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { watch } from '../internal/watch';
/**
 * @summary Split panels display two adjacent panels, allowing the user to reposition them.
 *
 * @event nile-reposition - Emitted when the divider's position changes.
 *
 * @slot start - Content to place in the start panel.
 * @slot end - Content to place in the end panel.
 * @slot divider - The divider. Useful for slotting in a custom icon that renders as a handle.
 *
 * @csspart start - The start panel.
 * @csspart end - The end panel.
 * @csspart panel - Targets both the start and end panels.
 * @csspart divider - The divider that separates the start and end panels.
 *
 * @cssproperty [--divider-width=4px] - The width of the visible divider.
 * @cssproperty [--divider-hit-area=12px] - The invisible region around the divider where dragging can occur. This is
 *  usually wider than the divider to facilitate easier dragging.
 * @cssproperty [--min=0] - The minimum allowed size of the primary panel.
 * @cssproperty [--max=100%] - The maximum allowed size of the primary panel.
 */
let NileSplitPanel = class NileSplitPanel extends NileElement {
    constructor() {
        super(...arguments);
        /**
         * The current position of the divider from the primary panel's edge as a percentage 0-100. Defaults to 50% of the
         * container's initial size.
         */
        this.position = 50;
        /** Draws the split panel in a vertical orientation with the start and end panels stacked. */
        this.vertical = false;
        /** Disables resizing. Note that the position may still change as a result of resizing the host element. */
        this.disabled = false;
        /** How close the divider must be to a snap point until snapping occurs. */
        this.snapThreshold = 12;
    }
    connectedCallback() {
        super.connectedCallback();
        this.resizeObserver = new ResizeObserver(entries => this.handleResize(entries));
        this.updateComplete.then(() => this.resizeObserver.observe(this));
        this.detectSize();
        this.cachedPositionInPixels = this.percentageToPixels(this.position);
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.resizeObserver.unobserve(this);
    }
    detectSize() {
        const { width, height } = this.getBoundingClientRect();
        this.size = this.vertical ? height : width;
    }
    percentageToPixels(value) {
        return this.size * (value / 100);
    }
    pixelsToPercentage(value) {
        return (value / this.size) * 100;
    }
    handleDrag(event) {
        const isRtl = false;
        if (this.disabled) {
            return;
        }
        // Prevent text selection when dragging
        if (event.cancelable) {
            event.preventDefault();
        }
        drag(this, {
            onMove: (x, y) => {
                let newPositionInPixels = this.vertical ? y : x;
                // Flip for end panels
                if (this.primary === 'end') {
                    newPositionInPixels = this.size - newPositionInPixels;
                }
                // Check snap points
                if (this.snap) {
                    const snaps = this.snap.split(' ');
                    snaps.forEach(value => {
                        let snapPoint;
                        if (value.endsWith('%')) {
                            snapPoint = this.size * (parseFloat(value) / 100);
                        }
                        else {
                            snapPoint = parseFloat(value);
                        }
                        if (isRtl && !this.vertical) {
                            snapPoint = this.size - snapPoint;
                        }
                        if (newPositionInPixels >= snapPoint - this.snapThreshold &&
                            newPositionInPixels <= snapPoint + this.snapThreshold) {
                            newPositionInPixels = snapPoint;
                        }
                    });
                }
                this.position = clamp(this.pixelsToPercentage(newPositionInPixels), 0, 100);
            },
            initialEvent: event
        });
    }
    handleKeyDown(event) {
        if (this.disabled) {
            return;
        }
        if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) {
            let newPosition = this.position;
            const incr = (event.shiftKey ? 10 : 1) * (this.primary === 'end' ? -1 : 1);
            event.preventDefault();
            if ((event.key === 'ArrowLeft' && !this.vertical) || (event.key === 'ArrowUp' && this.vertical)) {
                newPosition -= incr;
            }
            if ((event.key === 'ArrowRight' && !this.vertical) || (event.key === 'ArrowDown' && this.vertical)) {
                newPosition += incr;
            }
            if (event.key === 'Home') {
                newPosition = this.primary === 'end' ? 100 : 0;
            }
            if (event.key === 'End') {
                newPosition = this.primary === 'end' ? 0 : 100;
            }
            this.position = clamp(newPosition, 0, 100);
        }
    }
    handleResize(entries) {
        const { width, height } = entries[0].contentRect;
        this.size = this.vertical ? height : width;
        // Resize when a primary panel is set
        if (this.primary) {
            this.position = this.pixelsToPercentage(this.cachedPositionInPixels);
        }
    }
    handlePositionChange() {
        this.cachedPositionInPixels = this.percentageToPixels(this.position);
        this.positionInPixels = this.percentageToPixels(this.position);
        this.emit('nile-reposition');
    }
    handlePositionInPixelsChange() {
        this.position = this.pixelsToPercentage(this.positionInPixels);
    }
    handleVerticalChange() {
        this.detectSize();
    }
    render() {
        const gridTemplate = this.vertical ? 'gridTemplateRows' : 'gridTemplateColumns';
        const gridTemplateAlt = this.vertical ? 'gridTemplateColumns' : 'gridTemplateRows';
        const isRtl = false;
        const primary = `
      clamp(
        0%,
        clamp(
          var(--min),
          ${this.position}% - var(--divider-width) / 2,
          var(--max)
        ),
        calc(100% - var(--divider-width))
      )
    `;
        const secondary = 'auto';
        if (this.primary === 'end') {
            if (isRtl && !this.vertical) {
                this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`;
            }
            else {
                this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`;
            }
        }
        else {
            if (isRtl && !this.vertical) {
                this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`;
            }
            else {
                this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`;
            }
        }
        // Unset the alt grid template property
        this.style[gridTemplateAlt] = '';
        return html `
      <slot name="start" part="panel start" class="start"></slot>

      <div
        part="divider"
        class="divider"
        tabindex=${ifDefined(this.disabled ? undefined : '0')}
        role="separator"
        aria-valuenow=${this.position}
        aria-valuemin="0"
        aria-valuemax="100"
        aria-label="resize"
        @keydown=${this.handleKeyDown}
        @mousedown=${this.handleDrag}
        @touchstart=${this.handleDrag}
      >
        <slot name="divider"></slot>
      </div>

      <slot name="end" part="panel end" class="end"></slot>
    `;
    }
};
NileSplitPanel.styles = styles;
__decorate([
    query('.divider')
], NileSplitPanel.prototype, "divider", void 0);
__decorate([
    property({ type: Number, reflect: true })
], NileSplitPanel.prototype, "position", void 0);
__decorate([
    property({ attribute: 'position-in-pixels', type: Number })
], NileSplitPanel.prototype, "positionInPixels", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileSplitPanel.prototype, "vertical", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileSplitPanel.prototype, "disabled", void 0);
__decorate([
    property()
], NileSplitPanel.prototype, "primary", void 0);
__decorate([
    property()
], NileSplitPanel.prototype, "snap", void 0);
__decorate([
    property({ type: Number, attribute: 'snap-threshold' })
], NileSplitPanel.prototype, "snapThreshold", void 0);
__decorate([
    watch('position')
], NileSplitPanel.prototype, "handlePositionChange", null);
__decorate([
    watch('positionInPixels')
], NileSplitPanel.prototype, "handlePositionInPixelsChange", null);
__decorate([
    watch('vertical')
], NileSplitPanel.prototype, "handleVerticalChange", null);
NileSplitPanel = __decorate([
    customElement('nile-split-panel')
], NileSplitPanel);
export { NileSplitPanel };
export default NileSplitPanel;
//# sourceMappingURL=nile-split-panel.js.map