// #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 { CssLength } from '@breadstone/mosaik-themes';
import { Alignable } from '../../../Behaviors/Alignable';
import { Themeable } from '../../../Behaviors/Themeable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { LayoutElement } from '../Abstracts/LayoutElement';
import { ColumnDefinitions } from './ColumnDefinitions';
import { gridElementTemplate } from './GridElementTemplate';
import { parseGridLayoutGap } from './IGridLayoutGap';
import { RowDefinitions } from './RowDefinitions';
import { gridElementCosmopolitanStyle } from './Themes/GridElement.Cosmopolitan';
import { gridElementJoyStyle } from './Themes/GridElement.Joy';
import { gridElementMemphisStyle } from './Themes/GridElement.Memphis';
// #endregion
/**
 * Grid - A layout system that arranges elements in a structured grid pattern.
 *
 * @description
 * The Grid component provides a flexible grid layout system for arranging child elements in rows and columns.
 * It supports responsive design patterns and allows for precise control over element positioning and spacing.
 * This component is ideal for creating complex layouts, dashboards, and organized content structures.
 *
 * @name Grid
 * @element mosaik-grid
 * @category Layout
 *
 * @slot - The default slot for grid items.
 *
 * @example
 * Dashboard with a fixed sidebar and a flexible main content area:
 * ```html
 * <mosaik-grid column-definitions="240 *" row-definitions="auto *" gap="16">
 *   <mosaik-grid-item column="1" row="1" row-span="2">Sidebar</mosaik-grid-item>
 *   <mosaik-grid-item column="2" row="1">Header</mosaik-grid-item>
 *   <mosaik-grid-item column="2" row="2">Main Content</mosaik-grid-item>
 * </mosaik-grid>
 * ```
 *
 * @example
 * Equal-width card layout with consistent spacing:
 * ```html
 * <mosaik-grid column-definitions="* * *" row-definitions="auto" gap="24">
 *   <mosaik-grid-item column="1" row="1">Card 1</mosaik-grid-item>
 *   <mosaik-grid-item column="2" row="1">Card 2</mosaik-grid-item>
 *   <mosaik-grid-item column="3" row="1">Card 3</mosaik-grid-item>
 * </mosaik-grid>
 * ```
 *
 * @public
 */
let GridElement = class GridElement extends Alignable(Themeable(LayoutElement)) {
    // #region Fields
    _rowDefinitions;
    _columnDefinitions;
    _gap;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `GridElement` class.
     *
     * @public
     */
    constructor() {
        super();
        this._rowDefinitions = [];
        this._columnDefinitions = [];
        this._gap = 0;
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     *
     * @public
     * @static
     * @override
     * @readonly
    */
    static get is() {
        return 'mosaik-grid';
    }
    /**
     * Gets or sets the `rowDefinitions` property.
     *
     * Specifies the number of rows and their heights using `GridLength` sizing.
     * The array length defines the number of rows; each element defines the sizing of one row track.
     *
     * **Accepted forms**
     * - Array of `RowDefinitionInput` entries (JavaScript property binding).
     * - Space-separated string of grid-length tokens (HTML attribute), e.g. `"auto * 2* 100"`.
     *
     * **Accepted element / token forms**
     * - `number` - fixed height in pixels/DIPs (e.g. `100`).
     * - `string` - `"auto"`, `"*"`, `"n*"`, or a numeric string (e.g. `"2*"`).
     * - `IRowDefinition` - `{ height, minHeight?, maxHeight? }` (array form only).
     *
     * CSS units (`px`, `em`, `%`, `fr`, …) are **not** supported and will
     * throw. Negative values are rejected.
     *
     * @public
     * @attr row-definitions
     */
    get rowDefinitions() {
        return this._rowDefinitions;
    }
    set rowDefinitions(value) {
        if (this._rowDefinitions !== value) {
            this._rowDefinitions = value;
            this.style.gridTemplateRows = this.generateRowStyle(this._rowDefinitions);
            this.requestUpdate('rowDefinitions');
        }
    }
    /**
     * Gets or sets the `columnDefinitions` property.
     *
     * Specifies the number of columns and their widths using `GridLength` sizing.
     * The array length defines the number of columns; each element defines the sizing of one column track.
     *
     * **Accepted forms**
     * - Array of `ColumnDefinitionInput` entries (JavaScript property binding).
     * - Space-separated string of grid-length tokens (HTML attribute), e.g. `"* 2* auto 120"`.
     *
     * **Accepted element / token forms**
     * - `number` - fixed width in pixels/DIPs (e.g. `120`).
     * - `string` - `"auto"`, `"*"`, `"n*"`, or a numeric string (e.g. `"2*"`).
     * - `IColumnDefinition` - `{ width, minWidth?, maxWidth? }` (array form only).
     *
     * CSS units (`px`, `em`, `%`, `fr`, …) are **not** supported and will
     * throw. Negative values are rejected.
     *
     * @public
     * @attr column-definitions
     */
    get columnDefinitions() {
        return this._columnDefinitions;
    }
    set columnDefinitions(value) {
        if (this._columnDefinitions !== value) {
            this._columnDefinitions = value;
            this.style.gridTemplateColumns = this.generateColumnStyle(this._columnDefinitions);
            this.requestUpdate('columnDefinitions');
        }
    }
    /**
     * Gets or sets the `gap` property.
     *
     * Specifies the spacing between grid tracks (rows and columns).
     *
     * **Accepted forms**
     * - `number` - uniform gap in pixels on both axes (e.g. `16`).
     * - `CssLength` string - uniform gap with a CSS unit (e.g. `'1rem'`, `'8px'`).
     * - `IGridLayoutGap` object - separate gap per axis (`{ rows, columns }`) (JS only).
     *
     * When set via HTML attribute, the value is parsed as a CSS length
     * string (e.g. `gap="16"`, `gap="1rem"`).
     *
     * Negative values are rejected.
     *
     * @defaultValue `0`
     * @public
     * @attr gap
     */
    get gap() {
        return this._gap;
    }
    set gap(value) {
        if (this._gap !== value) {
            this._gap = value;
            this.style.gap = this.generateGapStyle(this._gap);
            this.requestUpdate('gap');
        }
    }
    // #endregion
    // #region Methods
    /**
     * Called when the `rowDefinitions` property changes.
     * Re-evaluates child item positions against the updated row track count.
     *
     * @protected
     */
    onRowDefinitionsChanged() {
        this.invalidateItemPositions();
    }
    /**
     * Called when the `columnDefinitions` property changes.
     * Re-evaluates child item positions against the updated column track count.
     *
     * @protected
     */
    onColumnDefinitionsChanged() {
        this.invalidateItemPositions();
    }
    /**
     * @protected
     * @override
     */
    onItemsChanged() {
        super.onItemsChanged();
        this.invalidateItemPositions();
    }
    /**
     * Resolves the `gap` property into a CSS `gap` shorthand value.
     *
     * Delegates to `parseGridLayoutGap` for validation and
     * normalisation, then produces the shortest valid CSS `gap` string.
     *
     * @private
     * @param gap - A `GridLayoutGap` input.
     * @returns A CSS `gap` value string.
     */
    generateGapStyle(gap) {
        const parsed = parseGridLayoutGap(gap);
        return parsed.rows === parsed.columns
            ? parsed.rows
            : `${parsed.rows} ${parsed.columns}`;
    }
    /**
     * Generates a CSS `grid-template-columns` value from the parsed `ColumnDefinitions`.
     *
     * @private
     * @param definition The raw column definitions array.
     * @returns A space-separated CSS track-list string.
     */
    generateColumnStyle(definition) {
        return ColumnDefinitions.parse(definition)
            .map((column) => this.generateTrack(column.width, column.minWidth, column.maxWidth))
            .join(' ');
    }
    /**
     * Generates a CSS `grid-template-rows` value from the parsed `RowDefinitions`.
     *
     * @private
     * @param definition The raw row definitions array.
     * @returns A space-separated CSS track-list string.
     */
    generateRowStyle(definition) {
        return RowDefinitions.parse(definition)
            .map((row) => this.generateTrack(row.height, row.minHeight, row.maxHeight))
            .join(' ');
    }
    /**
     * Converts a `GridLength` with optional min/max constraints into
     * an equivalent CSS `grid-template-*` track size string.
     *
     * **Mapping rules**
     *
     * | GridLength type | No constraints  | With min/max                   |
     * |-----------------|-----------------|--------------------------------|
     * | `pixel`         | `{value}px`     | `{clamp(min, value, max)}px`   |
     * | `auto`          | `auto`          | `minmax({min}px, {max/auto})`  |
     * | `star`          | `{factor}fr`    | `minmax({min}px, {max/Nfr})`   |
     *
     * @private
     * @param length The grid length specification.
     * @param minBound Minimum track size in pixels (0 = unconstrained).
     * @param maxBound Maximum track size in pixels (MAX_SAFE_INTEGER = unbounded).
     * @returns A CSS track-size value string.
     */
    generateTrack(length, minBound, maxBound) {
        const hasMin = minBound > 0;
        const hasMax = maxBound < Number.MAX_SAFE_INTEGER;
        // Absolute (pixel) - clamp the fixed value directly
        if (length.isAbsolute) {
            const clamped = Math.max(minBound, Math.min(maxBound, length.value));
            return `${clamped}px`;
        }
        // Auto sizing
        if (length.isAuto) {
            if (hasMin && hasMax) {
                return `minmax(${minBound}px, ${maxBound}px)`;
            }
            if (hasMin) {
                return `minmax(${minBound}px, auto)`;
            }
            if (hasMax) {
                return `minmax(auto, ${maxBound}px)`;
            }
            return 'auto';
        }
        // Star (proportional) sizing
        if (hasMin && hasMax) {
            return `minmax(${minBound}px, ${maxBound}px)`;
        }
        if (hasMin) {
            return `minmax(${minBound}px, ${length.value}fr)`;
        }
        if (hasMax) {
            return `minmax(0px, ${maxBound}px)`;
        }
        return `${length.value}fr`;
    }
    /**
     * Iterates all slotted child items and requests each `GridItemElement`
     * to re-evaluate its CSS `grid-area` placement against the current
     * column/row definitions.
     *
     * @private
     */
    invalidateItemPositions() {
        const items = this.items;
        if (!items) {
            return;
        }
        for (const item of items) {
            if ('invalidatePosition' in item
                && typeof item['invalidatePosition'] === 'function') {
                item.invalidatePosition();
            }
        }
    }
};
__decorate([
    Attribute({
        type: String,
        converter: {
            fromAttribute: (value) => {
                if (value === null || value.trim().length === 0) {
                    return [];
                }
                return RowDefinitions.fromString(value);
            },
            toAttribute: (value) => {
                return RowDefinitions.toString(value);
            }
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], GridElement.prototype, "rowDefinitions", null);
__decorate([
    Attribute({
        type: String,
        converter: {
            fromAttribute: (value) => {
                if (value === null || value.trim().length === 0) {
                    return [];
                }
                return ColumnDefinitions.fromString(value);
            },
            toAttribute: (value) => {
                return ColumnDefinitions.toString(value);
            }
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], GridElement.prototype, "columnDefinitions", null);
__decorate([
    Attribute({
        type: String,
        converter: {
            fromAttribute: (value) => {
                if (value === null || value.trim().length === 0) {
                    return 0;
                }
                return CssLength.tryParse(value) ?? 0;
            }
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], GridElement.prototype, "gap", null);
__decorate([
    Watch('rowDefinitions'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], GridElement.prototype, "onRowDefinitionsChanged", null);
__decorate([
    Watch('columnDefinitions'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], GridElement.prototype, "onColumnDefinitionsChanged", null);
GridElement = __decorate([
    Component({
        selector: 'mosaik-grid',
        themes: {
            joy: gridElementJoyStyle,
            memphis: gridElementMemphisStyle,
            cosmopolitan: gridElementCosmopolitanStyle
        },
        template: gridElementTemplate
    }),
    __metadata("design:paramtypes", [])
], GridElement);
export { GridElement };
//# sourceMappingURL=GridElement.js.map