// #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, on } from '@breadstone/mosaik-elements';
import { CssLength } from '@breadstone/mosaik-themes';
import { Emit } from '../../../../events/Decorators/EmitDecorator';
import { clamp } from '../../../../Extensions/NumberExtensions';
import { Disableable } from '../../../Behaviors/Disableable';
import { Fitable } from '../../../Behaviors/Fitable';
import { Orientable } from '../../../Behaviors/Orientable';
import { Reversible } from '../../../Behaviors/Reversible';
import { Slottable } from '../../../Behaviors/Slottable';
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 { Watch } from '../../../Decorators/WatchDecorator';
import { FlowDirection } from '../../../Types/FlowDirection';
import { Orientation } from '../../../Types/Orientation';
import { SplitCollapsedPanel } from '../../../Types/SplitCollapsedPanel';
import { SplitLock } from '../../../Types/SplitLock';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ThumbElement } from '../../Primitives/thumb/ThumbElement';
import { splitElementTemplate } from './SplitElementTemplate';
import { splitElementCosmopolitanStyle } from './Themes/SplitElement.Cosmopolitan';
import { splitElementJoyStyle } from './Themes/SplitElement.Joy';
import { splitElementMemphisStyle } from './Themes/SplitElement.Memphis';
// #endregion
/**
 * Split - A layout component that creates a resizable split pane layout with a draggable divider.
 *
 * Enables users to dynamically resize two content areas separated by an interactive divider.
 * Supports both horizontal and vertical orientations, position locking, snapping, and keyboard navigation.
 * When `collapsible` is enabled, panels can be collapsed by dragging beyond 50% of their minimum size.
 *
 * @name SplitElement
 * @element mosaik-split
 * @category Layout
 *
 * @slot ${e.reverse ? 'end' : 'start'} - The ${e.reverse ? 'end' : 'start'} slot.
 * @slot ${e.reverse ? 'start' : 'end'} - The ${e.reverse ? 'start' : 'end'} slot.
 * @slot thumb - Custom grip icon for the draggable divider (defaults to three dots icon)
 *
 * @csspart divider - The interactive draggable divider element
 * @csspart panel end - The panel end part.
 * @csspart panel start - The panel start part.
 * @csspart thumb - The visual grip icon within the divider
 *
 * @cssprop {String} --split-divider-background-color - The divider background color CSS custom property.
 * @cssprop {String} --split-divider-foreground-color - The divider foreground color CSS custom property.
 * @cssprop {String} --split-divider-hit-area - The divider hit area CSS custom property.
 * @cssprop {String} --split-divider-width - Width/height of the divider based on orientation
 * @cssprop {String} --split-font-family - The font family CSS custom property.
 * @cssprop {String} --split-font-letter-spacing - The font letter spacing CSS custom property.
 * @cssprop {String} --split-font-line-height - The font line height CSS custom property.
 * @cssprop {String} --split-font-size - The font size CSS custom property.
 * @cssprop {String} --split-font-text-decoration - The font text decoration CSS custom property.
 * @cssprop {String} --split-font-text-transform - The font text transform CSS custom property.
 * @cssprop {String} --split-font-weight - The font weight CSS custom property.
 * @cssprop {String} --split-gap - The gap CSS custom property.
 * @cssprop {String} --split-padding-bottom - The padding bottom CSS custom property.
 * @cssprop {String} --split-padding-left - The padding left CSS custom property.
 * @cssprop {String} --split-padding-right - The padding right CSS custom property.
 * @cssprop {String} --split-padding-top - The padding top CSS custom property.
 * @cssprop {String} --split-shadow - The shadow CSS custom property.
 * @cssprop {String} --split-shadow-blur - The shadow blur CSS custom property.
 * @cssprop {String} --split-shadow-color - The shadow color CSS custom property.
 * @cssprop {String} --split-shadow-offset-x - The shadow offset x CSS custom property.
 * @cssprop {String} --split-shadow-offset-y - The shadow offset y CSS custom property.
 * @cssprop {String} --split-shadow-spread - The shadow spread CSS custom property.
 * @cssprop {String} --split-thumb-background-color - The thumb background color CSS custom property.
 * @cssprop {String} --split-thumb-border-color - The thumb border color CSS custom property.
 * @cssprop {String} --split-thumb-border-radius - The thumb border radius CSS custom property.
 * @cssprop {String} --split-thumb-foreground-color - The thumb foreground color CSS custom property.
 * @cssprop {String} --split-transition-duration - The transition duration CSS custom property.
 * @cssprop {String} --split-transition-mode - The transition mode CSS custom property.
 * @cssprop {String} --split-transition-property - The transition property CSS custom property.
 * @cssprop {String} --split-translate - The translate CSS custom property.
 *
 * @fires splitReposition {SplitRepositionEvent} - Fired when the split position changes via user interaction
 *
 * @dependency mosaik-thumb - The Thumb element.
 *
 * @example
 * ```html
 * <!-- Basic split layout -->
 * <mosaik-split position="30">
 *   <div slot="start">Left Panel</div>
 *   <div slot="end">Right Panel</div>
 * </mosaik-split>
 *
 * <!-- Vertical split with snapping -->
 * <mosaik-split orientation="vertical" snaps="25% 50% 75%">
 *   <div slot="start">Top Panel</div>
 *   <div slot="end">Bottom Panel</div>
 * </mosaik-split>
 *
 * <!-- Locked split with custom thickness -->
 * <mosaik-split lock="start" thickness="4" position="200px">
 *   <nav slot="start">Navigation</nav>
 *   <main slot="end">Content</main>
 * </mosaik-split>
 *
 * <!-- Collapsible split with minimum constraint -->
 * <mosaik-split collapsible min="200px" position="30%">
 *   <aside slot="start">Collapsible Sidebar</aside>
 *   <main slot="end">Main Content</main>
 * </mosaik-split>
 * ```
 *
 * @public
 */
let SplitElement = class SplitElement extends Themeable(Reversible(Orientable(Disableable(Fitable(Slottable(CustomElement)))))) {
    // #region Fields
    _resizeController;
    _splitReposition;
    _size;
    _position;
    _lock;
    _snaps;
    _snapThreshold;
    _thickness;
    _min;
    _max;
    _collapsible;
    _collapsedPanel;
    _positionBeforeCollapse;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `SplitElement` class.
     *
     * @public
     */
    constructor() {
        super();
        this._position = '50%';
        this._lock = SplitLock.None;
        this._snaps = [];
        this._snapThreshold = 12;
        this._thickness = 2;
        this._min = '0%';
        this._max = '100%';
        this._size = 0;
        this._collapsible = false;
        this._collapsedPanel = SplitCollapsedPanel.None;
        this._positionBeforeCollapse = null;
        this._resizeController = new ResizeController(this, {
            callback: (entries) => this.handleResize(entries)
        });
        this._splitReposition = new HTMLElementEventEmitter(this, 'splitReposition');
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     * The `is` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-split';
    }
    /**
     * Gets or sets the `position` property.
     * The position of the divider. Accepts any valid CSS length value except 'auto'.
     *
     * @example '50%', '200px', '10rem'
     * @public
     * @attr
     */
    get position() {
        return this._position;
    }
    set position(value) {
        if (this._position !== value) {
            this._position = value;
            this.requestUpdate('position');
        }
    }
    /**
     * Gets or sets the `lock` property.
     * Determines which panel is the fixed reference for positioning and resize behavior.
     *
     * - `'none'` (default): The start panel is the primary reference. `position`, `min`, and `max`
     *   control the start panel's size. On container resize, the position **percentage** is preserved,
     *   meaning both panels resize proportionally.
     *
     * - `'start'`: Identical to `'none'` for layout and interaction, but on container resize
     *   the start panel's **absolute pixel size** is preserved instead of the percentage.
     *   The end panel absorbs all resize changes, keeping the start panel at a fixed width/height.
     *
     * - `'end'`: The end panel becomes the primary reference. The grid layout is inverted so
     *   that `position`, `min`, and `max` now control the **end** panel's size. Drag and keyboard
     *   directions are mirrored accordingly. On container resize, the end panel's **absolute pixel
     *   size** is preserved while the start panel absorbs resize changes.
     *
     * @example
     * ```html
     * <!-- Fixed 250px sidebar on the left, main area absorbs resize -->
     * <mosaik-split lock="start" position="250px">
     *   <nav slot="start">Sidebar</nav>
     *   <main slot="end">Content</main>
     * </mosaik-split>
     *
     * <!-- Fixed 300px panel on the right -->
     * <mosaik-split lock="end" position="300px">
     *   <main slot="start">Content</main>
     *   <aside slot="end">Details</aside>
     * </mosaik-split>
     * ```
     *
     * @public
     * @attr
     */
    get lock() {
        return this._lock;
    }
    set lock(value) {
        if (this._lock !== value) {
            this._lock = value;
            this.requestUpdate('lock');
        }
    }
    /**
     * Gets or sets the `snap` property.
     * The `snap` is a space separated list of snap points.
     * When the split is dragged, it will snap to the nearest snap point.
     *
     * @public
     * @attr
     */
    get snaps() {
        return this._snaps;
    }
    set snaps(value) {
        if (this._snaps !== value) {
            this._snaps = value;
            this.requestUpdate('snaps');
        }
    }
    /**
     * Gets or sets the `snapThreshold` property.
     *
     * @public
     * @attr
     */
    get snapThreshold() {
        return this._snapThreshold;
    }
    set snapThreshold(value) {
        if (this._snapThreshold !== value) {
            this._snapThreshold = value;
            this.requestUpdate('snapThreshold');
        }
    }
    /**
     * Gets or sets the `thickness` property.
     *
     * @public
     * @attr
     */
    get thickness() {
        return this._thickness;
    }
    set thickness(value) {
        if (this._thickness !== value) {
            this._thickness = value;
            this.requestUpdate('thickness');
        }
    }
    /**
     * Gets or sets the `min` property.
     * The minimum position constraint for the primary panel.
     * Accepts any valid CSS length value except 'auto' (e.g., '10%', '100px').
     *
     * @public
     * @attr
     */
    get min() {
        return this._min;
    }
    set min(value) {
        if (this._min !== value) {
            this._min = value;
            this.requestUpdate('min');
        }
    }
    /**
     * Gets or sets the `max` property.
     * The maximum position constraint for the primary panel.
     * Accepts any valid CSS length value except 'auto' (e.g., '90%', '500px').
     *
     * @public
     * @attr
     */
    get max() {
        return this._max;
    }
    set max(value) {
        if (this._max !== value) {
            this._max = value;
            this.requestUpdate('max');
        }
    }
    /**
     * Gets or sets the `collapsible` property.
     * When enabled, panels can be collapsed by dragging beyond 50% of their minimum size constraint.
     * A collapsed panel can be expanded by dragging back beyond 50% of the minimum size.
     *
     * **Requires a meaningful `min` value** (e.g., `min="200px"`). The collapse threshold is
     * calculated as 50% of `min`. With the default `min="0%"`, the threshold is 0px and the
     * snap-to-collapse behavior has no effect.
     *
     * **Difference to dragging without `collapsible`:**
     * Without `collapsible`, a panel can still reach zero size if `min="0%"`, but there is no
     * threshold snap behavior, no keyboard collapse (Home/End), and the `collapse()`/`expand()`
     * API methods are disabled.
     *
     * **Note:** The `collapsedPanel` property reflects the visual state regardless of this setting.
     * Even without `collapsible`, if a panel reaches zero size, `collapsedPanel` will indicate
     * which panel is collapsed.
     *
     * @public
     * @attr
     */
    get collapsible() {
        return this._collapsible;
    }
    set collapsible(value) {
        if (this._collapsible !== value) {
            this._collapsible = value;
            this.requestUpdate('collapsible');
        }
    }
    /**
     * Gets or sets the `collapsedPanel` property.
     * Indicates which panel is currently collapsed (has zero size).
     *
     * This property is **automatically derived** from the current `position`:
     * - When position is at or below `0%`, `collapsedPanel` is `'start'`.
     * - When position is at or above `100%`, `collapsedPanel` is `'end'`.
     * - Otherwise, `collapsedPanel` is `'none'`.
     *
     * This auto-detection works regardless of the `collapsible` property, ensuring
     * the value always reflects the visual state the user sees.
     *
     * @public
     * @attr
     * @readonly
     */
    get collapsedPanel() {
        return this._collapsedPanel;
    }
    set collapsedPanel(value) {
        if (this._collapsedPanel !== value) {
            this._collapsedPanel = value;
            this.requestUpdate('collapsedPanel');
        }
    }
    /**
     * Gets the `isCollapsed` property.
     * Returns true if any panel is currently collapsed.
     *
     * @public
     * @readonly
     */
    get isCollapsed() {
        return this._collapsedPanel !== SplitCollapsedPanel.None;
    }
    /**
     * Gets the `isStartCollapsed` property.
     * Returns true if the start panel is collapsed.
     *
     * @public
     * @readonly
     */
    get isStartCollapsed() {
        return this._collapsedPanel === SplitCollapsedPanel.Start;
    }
    /**
     * Gets the `isEndCollapsed` property.
     * Returns true if the end panel is collapsed.
     *
     * @public
     * @readonly
     */
    get isEndCollapsed() {
        return this._collapsedPanel === SplitCollapsedPanel.End;
    }
    /**
     * Gets or sets the `hasPanels` property.
     *
     * @public
     */
    get hasPanels() {
        return this.getSlotAssignments('start').length > 0 && this.getSlotAssignments('end').length > 0;
    }
    /**
     * Gets the position as a percentage value (0-100).
     * This is a computed property used internally for calculations.
     *
     * @public
     * @readonly
     */
    get positionPercentage() {
        return this.cssLengthToPercentage(this._position);
    }
    /**
     * Gets the position in pixels.
     * This is a computed property used internally for calculations.
     *
     * @public
     * @readonly
     */
    get positionInPixels() {
        return this.cssLengthToPixels(this._position);
    }
    /**
     * Called when the split is repositioned.
     * Provides reference to `IEventDetail` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get splitReposition() {
        return this._splitReposition;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        void this.updateComplete.then(() => {
            this._resizeController.observe(this);
            // Detect size after render when the element has actual dimensions
            this.detectSize();
            // Force a re-render to ensure correct orientation is applied
            // This fixes the initial vertical orientation rendering bug
            this.requestUpdate();
        });
    }
    /**
     * @public
     * @override
     */
    disconnectedCallback() {
        this._resizeController.unobserve(this);
        super.disconnectedCallback();
    }
    /**
     * @public
     * @override
     */
    onSlotChanges(_slotName) {
        this.requestUpdate('hasPanels');
    }
    /**
     * @private
     */
    handleDrag(event) {
        if (this.disabled) {
            return;
        }
        // Prevent text selection when dragging
        if (event.cancelable) {
            event.preventDefault();
        }
        this.drag(this, {
            onMove: (x, y) => {
                // Get raw mouse position before any transformations
                let rawPositionInPixels = this.orientation === Orientation.Vertical
                    ? y
                    : x;
                // Flip for end panels
                if (this.lock === 'end') {
                    rawPositionInPixels = this._size - rawPositionInPixels;
                }
                // Get min/max constraints in pixels
                const minPixels = this.cssLengthToPixels(this.min);
                const maxPixels = this.cssLengthToPixels(this.max);
                // Handle collapsible logic FIRST using raw position (before snapping/clamping)
                if (this._collapsible) {
                    const startCollapseThreshold = minPixels * 0.5; // 50% of min size
                    const endCollapseThreshold = maxPixels + ((this._size - maxPixels) * 0.5); // 50% past max
                    // Check START panel collapse/expand
                    if (this._collapsedPanel === SplitCollapsedPanel.Start) {
                        // Start panel is collapsed - check if we should expand
                        if (rawPositionInPixels >= startCollapseThreshold) {
                            // Dragged beyond 50% of min - expand to stored position or min
                            this.collapsedPanel = SplitCollapsedPanel.None;
                            this.position = this._positionBeforeCollapse ?? this.min;
                            this._positionBeforeCollapse = null;
                            return;
                        }
                        // Keep start collapsed
                        this.position = '0%';
                        return;
                    }
                    // Check END panel collapse/expand
                    if (this._collapsedPanel === SplitCollapsedPanel.End) {
                        // End panel is collapsed - check if we should expand
                        if (rawPositionInPixels <= endCollapseThreshold) {
                            // Dragged back - expand to stored position or max
                            this.collapsedPanel = SplitCollapsedPanel.None;
                            this.position = this._positionBeforeCollapse ?? this.max;
                            this._positionBeforeCollapse = null;
                            return;
                        }
                        // Keep end collapsed (position at 100%)
                        this.position = '100%';
                        return;
                    }
                    // No panel is collapsed - check if we should collapse one
                    if (rawPositionInPixels < startCollapseThreshold) {
                        // Dragged past 50% of min - collapse start panel
                        this._positionBeforeCollapse = this._position;
                        this.collapsedPanel = SplitCollapsedPanel.Start;
                        this.position = '0%';
                        return;
                    }
                    if (rawPositionInPixels > endCollapseThreshold) {
                        // Dragged past 50% of remaining space after max - collapse end panel
                        this._positionBeforeCollapse = this._position;
                        this.collapsedPanel = SplitCollapsedPanel.End;
                        this.position = '100%';
                        return;
                    }
                }
                // Apply snapping (only if not handling collapse)
                let newPositionInPixels = rawPositionInPixels;
                this.snaps.forEach((value) => {
                    const snapPoint = this.cssLengthToPixels(value);
                    const adjustedSnapPoint = this.dir === FlowDirection.RightToLeft && this.orientation === Orientation.Horizontal
                        ? this._size - snapPoint
                        : snapPoint;
                    if (newPositionInPixels >= adjustedSnapPoint - this.snapThreshold && newPositionInPixels <= adjustedSnapPoint + this.snapThreshold) {
                        newPositionInPixels = adjustedSnapPoint;
                    }
                });
                // Normal clamping within min/max
                newPositionInPixels = clamp(newPositionInPixels, minPixels, maxPixels);
                // Convert back to percentage for consistent storage
                const percentage = this.pixelsToPercentage(newPositionInPixels);
                this.position = `${percentage}%`;
            },
            initialEvent: event
        });
    }
    /**
     * @private
     */
    handleKeyDown(event) {
        if (this.disabled) {
            return;
        }
        if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) {
            const currentPercentage = this.positionPercentage;
            const minPercentage = this.cssLengthToPercentage(this.min);
            const maxPercentage = this.cssLengthToPercentage(this.max);
            const incr = (event.shiftKey ? 10 : 1) * (this.lock === 'end' ? -1 : 1);
            let newPercentage = currentPercentage;
            event.preventDefault();
            // Handle collapsible keyboard navigation
            if (this._collapsible) {
                // If start collapsed, expand on right/down key
                if (this._collapsedPanel === SplitCollapsedPanel.Start) {
                    const isExpandKey = (event.key === 'ArrowRight' && this.orientation === Orientation.Horizontal) ||
                        (event.key === 'ArrowDown' && this.orientation === Orientation.Vertical) ||
                        event.key === 'End';
                    if (isExpandKey) {
                        this.expand(SplitCollapsedPanel.Start);
                        return;
                    }
                    return;
                }
                // If end collapsed, expand on left/up key
                if (this._collapsedPanel === SplitCollapsedPanel.End) {
                    const isExpandKey = (event.key === 'ArrowLeft' && this.orientation === Orientation.Horizontal) ||
                        (event.key === 'ArrowUp' && this.orientation === Orientation.Vertical) ||
                        event.key === 'Home';
                    if (isExpandKey) {
                        this.expand(SplitCollapsedPanel.End);
                        return;
                    }
                    return;
                }
                // Home key collapses start panel
                if (event.key === 'Home' && this.lock !== 'end') {
                    this.collapse(SplitCollapsedPanel.Start);
                    return;
                }
                // End key collapses end panel
                if (event.key === 'End' && this.lock !== 'start') {
                    this.collapse(SplitCollapsedPanel.End);
                    return;
                }
            }
            if ((event.key === 'ArrowLeft' && this.orientation === Orientation.Horizontal) || (event.key === 'ArrowUp' && this.orientation === Orientation.Vertical)) {
                newPercentage -= incr;
            }
            if ((event.key === 'ArrowRight' && this.orientation === Orientation.Horizontal) || (event.key === 'ArrowDown' && this.orientation === Orientation.Vertical)) {
                newPercentage += incr;
            }
            if (event.key === 'Home') {
                newPercentage = this.lock === 'end' ? maxPercentage : minPercentage;
            }
            if (event.key === 'End') {
                newPercentage = this.lock === 'end' ? minPercentage : maxPercentage;
            }
            newPercentage = clamp(newPercentage, minPercentage, maxPercentage);
            this.position = `${newPercentage}%`;
        }
    }
    /**
     * Handles the double click on the thumb.
     * Toggles the collapse state of a panel based on the current `lock` setting:
     * - `lock="start"`: Toggles the start panel.
     * - `lock="end"`: Toggles the end panel.
     * - `lock="none"`: Determines the target panel by the current position percentage
     *   (≤ 50% → start, > 50% → end).
     *
     * When a panel is already collapsed, it expands that specific panel regardless of lock.
     *
     * @private
     */
    handleDoubleClick() {
        if (this.disabled || !this._collapsible) {
            return;
        }
        // If a panel is already collapsed, expand it
        if (this.isCollapsed) {
            this.expand(this._collapsedPanel);
            return;
        }
        // Determine which panel to collapse based on lock
        let target;
        if (this._lock === SplitLock.Start) {
            target = SplitCollapsedPanel.Start;
        }
        else if (this._lock === SplitLock.End) {
            target = SplitCollapsedPanel.End;
        }
        else {
            // No lock: decide by current position percentage.
            // At exactly 50% no side is dominant, so do nothing.
            const percentage = this.positionPercentage;
            if (percentage === 50) {
                return;
            }
            target = percentage < 50
                ? SplitCollapsedPanel.Start
                : SplitCollapsedPanel.End;
        }
        this.collapse(target);
    }
    /**
     * Collapses the specified panel by dragging it beyond 50% of its minimum size constraint.
     * Only works when `collapsible` is enabled.
     *
     * @public
     * @param panel The panel to collapse
     */
    collapse(panel) {
        if (!this._collapsible || this._collapsedPanel !== SplitCollapsedPanel.None) {
            return;
        }
        this._positionBeforeCollapse = this._position;
        this.collapsedPanel = panel;
        if (panel === SplitCollapsedPanel.Start) {
            this.position = '0%';
        }
        else {
            this.position = '100%';
        }
    }
    /**
     * Expands the specified collapsed panel back to its minimum/maximum position.
     * Only works when `collapsible` is enabled.
     *
     * @public
     * @param panel The panel to expand
     */
    expand(panel) {
        if (!this._collapsible || this._collapsedPanel !== panel) {
            return;
        }
        this.collapsedPanel = SplitCollapsedPanel.None;
        if (panel === SplitCollapsedPanel.Start) {
            this.position = this._positionBeforeCollapse ?? this.min;
        }
        else {
            this.position = this._positionBeforeCollapse ?? this.max;
        }
        this._positionBeforeCollapse = null;
    }
    /**
     * Emits the `splitReposition` event.
     *
     * @protected
     */
    onSplitReposition(args) {
        this._splitReposition.emit(args);
    }
    /**
     * Called when the `position` property changes.
     * Automatically updates `collapsedPanel` to reflect the visual state.
     *
     * @protected
     */
    onPositionPropertyChanged(_prev, _next) {
        const percentage = this.positionPercentage;
        // Auto-detect collapsed state from position.
        // This ensures collapsedPanel always reflects what the user sees,
        // regardless of whether collapsible is enabled.
        if (percentage <= 0) {
            this.collapsedPanel = SplitCollapsedPanel.Start;
        }
        else if (percentage >= 100) {
            this.collapsedPanel = SplitCollapsedPanel.End;
        }
        else if (this._collapsedPanel !== SplitCollapsedPanel.None) {
            this.collapsedPanel = SplitCollapsedPanel.None;
        }
        this.onSplitReposition({
            position: percentage
        });
    }
    /**
     * @protected
     */
    onOrientationPropertyChanged(_prev, _next) {
        this.detectSize();
    }
    /**
     * Converts a CSS length value to pixels.
     *
     * @private
     */
    cssLengthToPixels(value) {
        // Handle raw number (treated as pixels)
        if (typeof value === 'number') {
            return value;
        }
        // Handle percentage
        if (CssLength.isPercentage(value)) {
            return this._size * (CssLength.extractValue(value) / 100);
        }
        // Handle other CSS length units (px, rem, etc.)
        return CssLength.extractValue(value);
    }
    /**
     * Converts a CSS length value to percentage.
     *
     * @private
     */
    cssLengthToPercentage(value) {
        // Handle raw number (treated as pixels, convert to percentage)
        if (typeof value === 'number') {
            return this._size > 0 ? (value / this._size) * 100 : 0;
        }
        // Handle percentage
        if (CssLength.isPercentage(value)) {
            return CssLength.extractValue(value);
        }
        // Convert pixel value to percentage
        const pixels = CssLength.extractValue(value);
        return this._size > 0 ? (pixels / this._size) * 100 : 0;
    }
    /**
     * @private
     */
    detectSize() {
        const rect = this.getBoundingClientRect();
        this._size = this.orientation === Orientation.Vertical
            ? rect.height
            : rect.width;
    }
    /**
     * @private
     */
    pixelsToPercentage(value) {
        return this._size > 0 ? (value / this._size) * 100 : 0;
    }
    /**
     * @private
     */
    handleResize(entries) {
        if (entries.length === 0) {
            return;
        }
        const rect = entries[0].contentRect;
        const previousSize = this._size;
        this._size = this.orientation === Orientation.Vertical ? rect.height : rect.width;
        // When locked, maintain the absolute pixel position during resize
        if (this.lock !== SplitLock.None && previousSize > 0) {
            const positionString = String(this._position);
            // If position is a percentage, convert to maintain absolute size
            if (positionString.endsWith('%')) {
                const absolutePixels = previousSize * (parseFloat(positionString) / 100);
                const newPercentage = this._size > 0 ? (absolutePixels / this._size) * 100 : 0;
                this._position = `${newPercentage}%`;
                this.requestUpdate('position');
            }
        }
    }
    /**
     * @private
     */
    drag(container, options) {
        const pointermove = on(document, 'pointermove', (e) => {
            const dims = container.getBoundingClientRect();
            const defaultView = container.ownerDocument.defaultView;
            const offsetX = dims.left + (defaultView?.scrollX ?? 0);
            const offsetY = dims.top + (defaultView?.scrollY ?? 0);
            const x = e.pageX - offsetX;
            const y = e.pageY - offsetY;
            if (options?.onMove) {
                options.onMove(x, y);
            }
        }, { passive: true });
        const pointerup = on(document, 'pointerup', () => {
            pointermove.dispose();
            pointerup.dispose();
            if (options?.onStop) {
                options.onStop();
            }
        });
        // If an initial event is set, trigger the first drag immediately
        if (options?.initialEvent instanceof PointerEvent) {
            pointermove.invoke(options.initialEvent);
        }
    }
};
__decorate([
    Attribute({
        type: String,
        converter: {
            fromAttribute: (value) => normalizeCssLengthAttribute(value, '50%'),
            toAttribute: (value) => String(value)
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], SplitElement.prototype, "position", null);
__decorate([
    Attribute({ type: SplitLock }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], SplitElement.prototype, "lock", null);
__decorate([
    Attribute({
        type: Array,
        converter: {
            fromAttribute: (value) => {
                if (!value) {
                    return [];
                }
                return value
                    .split(' ')
                    .map((v) => normalizeCssLengthAttribute(v.trim(), '0px'));
            },
            toAttribute: (value) => value.join(' ')
        }
    }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], SplitElement.prototype, "snaps", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], SplitElement.prototype, "snapThreshold", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], SplitElement.prototype, "thickness", null);
__decorate([
    Attribute({
        type: String,
        converter: {
            fromAttribute: (value) => normalizeCssLengthAttribute(value, '0%'),
            toAttribute: (value) => String(value)
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], SplitElement.prototype, "min", null);
__decorate([
    Attribute({
        type: String,
        converter: {
            fromAttribute: (value) => normalizeCssLengthAttribute(value, '100%'),
            toAttribute: (value) => String(value)
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], SplitElement.prototype, "max", null);
__decorate([
    Attribute({ type: Boolean }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], SplitElement.prototype, "collapsible", null);
__decorate([
    Attribute({ type: SplitCollapsedPanel }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], SplitElement.prototype, "collapsedPanel", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], SplitElement.prototype, "hasPanels", null);
__decorate([
    Emit({ eventName: 'splitReposition' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], SplitElement.prototype, "splitReposition", null);
__decorate([
    Watch('position'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], SplitElement.prototype, "onPositionPropertyChanged", null);
__decorate([
    Watch('orientation'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Boolean, Boolean]),
    __metadata("design:returntype", void 0)
], SplitElement.prototype, "onOrientationPropertyChanged", null);
SplitElement = __decorate([
    Component({
        selector: 'mosaik-split',
        template: splitElementTemplate,
        themes: {
            joy: splitElementJoyStyle,
            memphis: splitElementMemphisStyle,
            cosmopolitan: splitElementCosmopolitanStyle
        },
        imports: [
            ThumbElement
        ]
    }),
    __metadata("design:paramtypes", [])
], SplitElement);
export { SplitElement };
/**
 * Normalizes a CSS length attribute value.
 * If the value is a pure number (e.g., "50"), it appends "px".
 * Otherwise, it returns the value as-is (e.g., "50%", "10rem").
 *
 * @param value The attribute value to normalize
 * @param defaultValue The default value to return if value is null/empty
 * @returns A valid CssLength value
 */
function normalizeCssLengthAttribute(value, defaultValue) {
    if (!value) {
        return defaultValue;
    }
    // Check if the value is a pure number (no unit)
    const trimmed = value.trim();
    if ((/^-?\d+(\.\d+)?$/).test(trimmed)) {
        return `${trimmed}px`;
    }
    return trimmed;
}
//# sourceMappingURL=SplitElement.js.map