var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import React, { forwardRef, memo, useCallback, useEffect, useRef, useState, } from "react";
import { useDataGridContext } from "../../../data-grid/root/DataGridRoot.context.js";
import { Skeleton } from "../../../skeleton/index.js";
import { useId } from "../../../utils-external/index.js";
import { Slot } from "../../../utils/components/slot/Slot.js";
import { cl } from "../../../utils/helpers/index.js";
import { useMergeRefs } from "../../../utils/hooks/index.js";
import { DataTableBaseCell } from "../base-cell/DataTableBaseCell.js";
import { DataTableColumnHeader } from "../column-header/DataTableColumnHeader.js";
import { DataTableDetailsPanelRow } from "../details-panel-row/DataTableDetailsPanelRow.js";
import { DataTableEmptyState } from "../empty-state/DataTableEmptyState.js";
import { useColumnOptions } from "../hooks/useColumnOptions.js";
import { DataTableDetailsPanelProvider, } from "../hooks/useTableDetailsPanel.js";
import { useTableItems } from "../hooks/useTableItems.js";
import { useTableKeyboardNav } from "../hooks/useTableKeyboardNav.js";
import { useTableSelection } from "../hooks/useTableSelection.js";
import { useTableSort } from "../hooks/useTableSort.js";
import { DataTableLoadingState } from "../loading-state/DataTableLoadingState.js";
import { DataTableSubRowToggle } from "../sub-row-toggle/DataTableSubRowToggle.js";
import { DataTableTbody } from "../tbody/DataTableTbody.js";
import { DataTableThead } from "../thead/DataTableThead.js";
import { DataTableTr } from "../tr/DataTableTr.js";
import { DataTableContextProvider, useDataTableContext, } from "./DataTableRoot.context.js";
const DataGridTableInternal = forwardRef((_a, forwardedRef) => {
    var _b, _c, _d;
    var { className, id, layout = "fixed", stickyHeader = true, onRowAction, emptyContent, loadingContent = {
        variant: "skeleton",
        rows: 5,
        label: "Laster innhold",
    }, // TODO translate label
    detailsPanel, subRows, sorting, selectionTrigger = "row" } = _a, rest = __rest(_a, ["className", "id", "layout", "stickyHeader", "onRowAction", "emptyContent", "loadingContent", "detailsPanel", "subRows", "sorting", "selectionTrigger"]);
    const { columnDefinitions, data, getRowId, selection, isLoading, tableSettings, } = useDataGridContext();
    const sortingState = useTableSort(sorting);
    const tableItems = useTableItems({
        items: data,
        getRowId,
        subRows,
    });
    const tableSelectionState = useTableSelection({
        selection,
        selectionTrigger,
        tableItems,
    });
    const { columns, stickyStart, totalColSpan } = useColumnOptions(columnDefinitions, {
        stickyColumns: tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.stickyColumns,
        hasSelection: tableSelectionState.selection.mode !== "none",
        hasDetailsPanel: !!(detailsPanel === null || detailsPanel === void 0 ? void 0 : detailsPanel.getContent),
        layout,
        columnDisplay: tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.columnDisplay,
    });
    const tableId = useId(id);
    /* TODO: Need to figure out how to handle this since settings is provided from root, not table itself */
    const truncateContent = (_b = tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.truncateContent) !== null && _b !== void 0 ? _b : layout !== "auto";
    return (React.createElement(DataTableContextProvider, { layout: layout, withKeyboardNav: true, selectionState: tableSelectionState, stickyStart: stickyStart, stickyHeader: stickyHeader, tableId: tableId, loading: loadingContent, onRowAction: onRowAction, columns: columns, totalColSpan: totalColSpan, tableItems: tableItems, sortingState: sortingState },
        React.createElement(TableElementWrapper, { enabled: true, hasStickyColumns: !!(((_c = tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.stickyColumns) === null || _c === void 0 ? void 0 : _c.start) ||
                ((_d = tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.stickyColumns) === null || _d === void 0 ? void 0 : _d.end)) },
            React.createElement("table", Object.assign({}, rest, { ref: forwardedRef, className: cl("aksel-data-table", className), "data-zebra-stripes": tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.zebraStripes, "data-column-dividers": tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.columnDividers, "data-truncate-content": truncateContent, "data-density": tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.rowDensity, "data-text-size": tableSettings === null || tableSettings === void 0 ? void 0 : tableSettings.textSize, "data-layout": layout, "data-loading": isLoading || undefined, "aria-busy": isLoading || undefined }),
                React.createElement(DataTableDetailsPanelProvider, { detailsPanel: detailsPanel },
                    React.createElement(DataTableThead, { "data-sticky": stickyHeader || undefined },
                        React.createElement(DataTableTr, null, columns.map(({ isSticky, isStickyLast, stickyLeftOffset, colDef }) => {
                            var _a, _b;
                            return (React.createElement(DataTableColumnHeader, { id: colDef.id, width: colDef.width, align: (_a = colDef.align) !== null && _a !== void 0 ? _a : "left", key: colDef.id, isSticky: isSticky, sortable: colDef.isSortable, label: colDef.header, style: stickyLeftOffset
                                    ? { left: stickyLeftOffset }
                                    : undefined, "data-sticky-last": isStickyLast || undefined }, (_b = colDef.headerCell) !== null && _b !== void 0 ? _b : colDef.header));
                        }))),
                    React.createElement(DataTableTbody, null,
                        React.createElement(DataTableTBodyContent, { emptyContent: emptyContent })))))));
});
/**
 * Temp optimization to avoid re-renders on every keyboard-move, selection change etc
 */
function TableElementWrapper({ children, enabled, hasStickyColumns, }) {
    const [applyStickyStyles, setApplyStickyStyles] = useState(false);
    const tableWrapperRef = useRef(null);
    const tableRef = useRef(null);
    const rafRef = useRef(null);
    const { tabIndex, setTableRef } = useTableKeyboardNav({
        enabled,
    });
    const mergedTableRefs = useMergeRefs(tableRef, setTableRef);
    const updateStickyStyles = useCallback(() => {
        if (!tableWrapperRef.current) {
            return;
        }
        const doesWrapperHasScroll = tableWrapperRef.current.scrollWidth > tableWrapperRef.current.clientWidth;
        setApplyStickyStyles(doesWrapperHasScroll);
    }, []);
    const scheduleStickyStylesUpdate = useCallback(() => {
        if (rafRef.current !== null) {
            return;
        }
        rafRef.current = requestAnimationFrame(() => {
            rafRef.current = null;
            updateStickyStyles();
        });
    }, [updateStickyStyles]);
    useEffect(function observeAndUpdateStickyStyles() {
        if (!hasStickyColumns) {
            return;
        }
        const tableWrapperElement = tableWrapperRef.current;
        if (!tableWrapperElement) {
            return;
        }
        const handleResize = () => scheduleStickyStylesUpdate();
        window.addEventListener("resize", handleResize);
        let resizeObserver;
        if (typeof ResizeObserver !== "undefined") {
            resizeObserver = new ResizeObserver(handleResize);
            resizeObserver.observe(tableWrapperElement);
            if (tableRef.current) {
                resizeObserver.observe(tableRef.current);
            }
        }
        scheduleStickyStylesUpdate();
        return () => {
            window.removeEventListener("resize", handleResize);
            resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
            if (rafRef.current !== null) {
                cancelAnimationFrame(rafRef.current);
                rafRef.current = null;
            }
        };
    }, [scheduleStickyStylesUpdate, hasStickyColumns]);
    return (React.createElement("div", { className: "aksel-data-table__border-wrapper" },
        React.createElement("div", { ref: tableWrapperRef, className: "aksel-data-table__scroll-wrapper" },
            React.createElement(Slot, { tabIndex: tabIndex, 
                /* @ts-expect-error Ref is not typed correctly to handle this case */
                ref: mergedTableRefs, "data-scroll": applyStickyStyles ? "true" : undefined }, children))));
}
function DataTableTBodyContent({ emptyContent }) {
    var _a, _b, _c;
    const { columns, loading, totalColSpan, tableItems } = useDataTableContext();
    const { isLoading } = useDataGridContext();
    if (isLoading && (loading === null || loading === void 0 ? void 0 : loading.variant) === "content") {
        return (React.createElement(DataTableLoadingState, { colSpan: totalColSpan }, loading.content));
    }
    if (isLoading && (loading === null || loading === void 0 ? void 0 : loading.variant) === "skeleton") {
        const rows = (_a = loading.rows) !== null && _a !== void 0 ? _a : 5;
        const label = (_b = loading.label) !== null && _b !== void 0 ? _b : "Laster innhold"; // TODO translate
        return (React.createElement(React.Fragment, null,
            React.createElement("tr", null,
                React.createElement("td", { colSpan: totalColSpan, className: "aksel-sr-only" }, label)),
            Array.from({ length: rows }, (_, rowIndex) => (React.createElement(DataTableTr, { key: `skeleton-row-${rowIndex}`, "aria-hidden": true }, columns.map(({ isSticky, isStickyLast, stickyLeftOffset, colDef }, colDefIndex) => {
                var _a;
                return (React.createElement(DataTableBaseCell, { align: (_a = colDef.align) !== null && _a !== void 0 ? _a : "left", key: colDef.id || colDefIndex, as: colDef.isRowHeader ? "th" : "td", isSticky: isSticky, style: stickyLeftOffset ? { left: stickyLeftOffset } : undefined, "data-sticky-last": isStickyLast || undefined },
                    React.createElement(Skeleton, { variant: "text" })));
            }))))));
    }
    if (tableItems.items.length === 0 && emptyContent !== undefined) {
        return (React.createElement(DataTableEmptyState, { colSpan: totalColSpan }, emptyContent));
    }
    const renderLoadingAnnouncement = isLoading && (loading === null || loading === void 0 ? void 0 : loading.variant) === "overlay";
    const overlayLabel = (loading === null || loading === void 0 ? void 0 : loading.variant) === "overlay"
        ? ((_c = loading.label) !== null && _c !== void 0 ? _c : "Laster innhold") // TODO translate
        : "Laster innhold";
    return (React.createElement(React.Fragment, null,
        renderLoadingAnnouncement && (React.createElement("tr", null,
            React.createElement("td", { colSpan: totalColSpan, className: "aksel-sr-only" }, overlayLabel))),
        tableItems.items.map((rowData, rowIndex) => {
            const rowId = tableItems.visibleRowIds[rowIndex];
            const details = rowId != null ? tableItems.itemDetails.get(rowId) : undefined;
            /* Should in theory be impossible. Look about typing this? */
            if (!details) {
                return null;
            }
            return (React.createElement(DataTableDataRow, { key: details.id, rowData: rowData, details: details, columns: columns }));
        })));
}
const DataTableDataRow = memo(function DataTableDataRow({ rowData, details, columns, }) {
    const hasSubRows = details.children.length > 0;
    return (React.createElement(React.Fragment, null,
        React.createElement(DataTableTr, { rowId: details.id }, columns.map(({ isSticky, isStickyLast, stickyLeftOffset, colDef }, colDefIndex) => {
            var _a;
            const renderNestedToggle = colDefIndex === 0 && hasSubRows;
            const renderNestedIndent = colDefIndex === 0 && (details.level > 0 || hasSubRows);
            const style = Object.assign({ "--__axc-data-table-nested-depth": details.level }, (stickyLeftOffset ? { left: stickyLeftOffset } : {}));
            return (React.createElement(DataTableBaseCell, { align: (_a = colDef.align) !== null && _a !== void 0 ? _a : "left", key: colDef.id || colDefIndex, as: colDef.isRowHeader ? "th" : "td", isSticky: isSticky, "data-nested": renderNestedIndent || undefined, "data-sticky-last": isStickyLast || undefined, style: style, beforeContent: renderNestedToggle ? (React.createElement(DataTableSubRowToggle, { details: details })) : undefined }, colDef.bodyCell(rowData)));
        })),
        React.createElement(DataTableDetailsPanelRow, { rowId: details.id, rowData: rowData })));
}, 
/* TODO: Might be some better metrics we could use to optimize this */
(prev, next) => prev.rowData === next.rowData &&
    prev.columns === next.columns &&
    prev.details.id === next.details.id &&
    prev.details.level === next.details.level &&
    prev.details.children.length === next.details.children.length);
const DataGridTable = DataGridTableInternal;
// docgen doesn't work well with type params, so we let it use DataGridTableInternal instead
// eslint-disable-next-line import/export
export { DataGridTable, DataGridTableInternal };
export default DataGridTable;
//# sourceMappingURL=DataGridTableRoot.js.map