{"version":3,"file":"DataTable.cjs","names":[],"sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the table does four jobs\n * a caller turns on independently — paging (pageSize), search (searchable,\n * searchKeys), sort (initialSort) and inline edit (onCellChange, editLabels) — over\n * one row model (data, columns, rowKey, emptyMessage). The body is long because\n * those four share the derived-rows pipeline: filter, then sort, then page, then map\n * to cells, in that order and off the same memo.\n *\n * Each of the four also runs in a second mode, where the caller owns the work and\n * the table only reports intent: totalItems/page/onPageChange, onSearchChange,\n * manualSort/onSortChange, loading/loadingRows. That doubles the props without\n * adding a fifth job — every manual prop short-circuits one stage of the same\n * pipeline.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { compareValues } from \"@/utils/compare-values\";\nimport { usePagination } from \"@/hooks\";\nimport { useAnnounce } from \"@/hooks/use-announce\";\nimport { Table, type TableAlign, type TableColumn, type TablePriority } from \"../Table\";\nimport { Pagination } from \"../Pagination\";\nimport { SearchBar } from \"../SearchBar\";\nimport { EditableCell } from \"./EditableCell\";\nimport { LoadingRows } from \"./LoadingRows\";\nimport { useDevWarnings } from \"./use-dev-warnings\";\nimport { DEFAULT_EDIT_LABELS, type CellCommitMove, type DataTableEditLabels } from \"./edit-labels\";\nimport styles from \"./DataTable.module.css\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface DataTableSort<T> {\n    key: keyof T;\n    direction: SortDirection;\n}\n\n/** Input types an editable column can use. */\nexport type DataTableEditorType = \"text\" | \"number\" | \"date\" | \"email\" | \"tel\" | \"url\";\n\n/** One accepted cell edit, handed to `onCellChange`. */\nexport interface DataTableCellChange<T> {\n    /** The row as it was before the edit. */\n    row: T;\n    /** Which column changed. */\n    key: keyof T;\n    /** The parsed new value. */\n    value: unknown;\n    /** The value that was displayed before the edit. */\n    previous: unknown;\n    /** Index of the row in the full `data` array. */\n    rowIndex: number;\n}\n\n/**\n * Column definition for {@link DataTable}. Extends the headless {@link Table}\n * column shape with a typed `key`, opt-in sorting, opt-in inline editing, and the\n * visual options that are forwarded to the underlying Table cell.\n */\nexport interface DataTableColumn<T> {\n    /** Property of the row this column reads from. Doubles as the cell key. */\n    key: keyof T;\n    /** Column heading. */\n    header: ReactNode;\n    /** Custom cell renderer. Defaults to `String(row[key])`. */\n    render?: (row: T) => ReactNode;\n    /** Enable click-to-sort on this column's header. */\n    sortable?: boolean;\n    /** Text alignment forwarded to the Table cell. */\n    align?: TableAlign;\n    /** Responsive visibility priority forwarded to the Table cell. */\n    priority?: TablePriority;\n    /** Fixed column width forwarded to the Table cell. */\n    width?: string | number;\n    /**\n     * Let cells in this column be edited in place. Requires `onCellChange` on the\n     * table; without it the column stays read-only.\n     */\n    editable?: boolean;\n    /** Editor input type. Default `\"text\"`. */\n    editorType?: DataTableEditorType;\n    /** Text the editor opens with. Defaults to `String(value ?? \"\")`. */\n    formatEdit?: (row: T) => string;\n    /**\n     * Turn the typed string into the stored value. Defaults to the trimmed string,\n     * or `Number(raw)` when `editorType` is `\"number\"`.\n     */\n    parse?: (raw: string, row: T) => unknown;\n    /** Return a message to reject the edit, or `null` to accept it. */\n    validate?: (value: unknown, row: T) => string | null;\n}\n\n/** Everything a table needs regardless of who owns paging, sorting and searching. */\nexport interface DataTableBaseProps<T> extends HTMLAttributes<HTMLDivElement> {\n    /**\n     * The rows to work with.\n     *\n     * By default this is the **full** dataset and sorting, searching and paging\n     * all happen in memory. Pass `totalItems` and it becomes the current page as\n     * the server returned it, with those three delegated to the caller.\n     */\n    data: T[];\n    /** Column definitions. */\n    columns: DataTableColumn<T>[];\n    /** Rows per page. Default 10. */\n    pageSize?: number;\n    /** Render a search input above the table. Default false. */\n    searchable?: boolean;\n    /**\n     * Keys to match the search term against. When omitted, every column whose\n     * value is a string or number is searched.\n     */\n    searchKeys?: (keyof T)[];\n    /** Initial sort applied before any header interaction. */\n    initialSort?: DataTableSort<T>;\n    /** Stable key extractor for rows. Defaults to the row index. */\n    rowKey?: (row: T, index: number) => string | number;\n    /** Content shown when no rows match. */\n    emptyMessage?: ReactNode;\n    /**\n     * Persist an accepted cell edit. Return a promise: while it is pending the cell\n     * already shows the new value, and a rejection rolls that back and surfaces the\n     * error in the cell. Without this prop no column is editable.\n     */\n    onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;\n    /** Override the PT-BR copy of the editing affordances. */\n    editLabels?: Partial<DataTableEditLabels>;\n    /**\n     * A fetch is in flight.\n     *\n     * With rows already on screen they stay put, dimmed and `aria-busy`, so the\n     * page does not jump under the cursor between pages. With no rows yet it\n     * renders placeholder lines at full height, which is a different statement\n     * from `emptyMessage`: \"loading\" and \"there is nothing\" are not the same\n     * screen.\n     */\n    loading?: boolean;\n}\n\n/**\n * Paging, as one of the three shapes that actually work.\n *\n * These used to be three optional props, so the compiler accepted\n * `totalItems` with no `page` — a table whose pager moves an internal page while\n * `data` keeps showing page one. Every prop was optional on its own, so the only\n * place left to catch it was a `console.warn` in dev, in the browser, with the\n * component mounted. As a union the same mistake is a build error at the call\n * site, for free, everywhere.\n */\nexport type DataTablePagingProps =\n    | {\n          /** Not server mode. */\n          totalItems?: never;\n          /** The table owns the page. */\n          page?: never;\n          /** Nothing to report to. */\n          onPageChange?: never;\n      }\n    | {\n          /**\n           * Total row count across every page — the `total` of a paginated envelope.\n           *\n           * Passing it switches the table to **server mode**: `data` is read as the\n           * current page, the page count comes from this number instead of\n           * `data.length`, and sorting and searching are delegated to the caller\n           * (see `manualSort` / `manualSearch`, which are implied here). Pair it with\n           * `page` and `onPageChange`.\n           */\n          totalItems?: never;\n          /** Current page, 1-based. Controlled — required in server mode. */\n          page: number;\n          /** Called with the next page. Required whenever `page` is controlled. */\n          onPageChange: (page: number) => void;\n      }\n    | {\n          /**\n           * Total row count across every page — the `total` of a paginated envelope.\n           *\n           * Passing it switches the table to **server mode**: `data` is read as the\n           * current page, the page count comes from this number instead of\n           * `data.length`, and sorting and searching are delegated to the caller\n           * (see `manualSort` / `manualSearch`, which are implied here). `page` and\n           * `onPageChange` come with it — the type says so, because a server-mode\n           * table without them silently shows page one forever.\n           */\n          totalItems: number;\n          /** Current page, 1-based. Controlled, and required in server mode. */\n          page: number;\n          /** Called with the next page. */\n          onPageChange: (page: number) => void;\n      };\n\n/**\n * Sorting: delegated, and therefore reported, or neither.\n *\n * `manualSort` without `onSortChange` renders a header that moves its arrow and\n * changes nothing else — the arrow is a lie the compiler can now catch.\n */\nexport type DataTableSortProps<T> =\n    | {\n          /** The table sorts the rows it has. */\n          manualSort?: false;\n          /** Called with the next sort state — `null` when the header cycles back to unsorted. */\n          onSortChange?: (sort: DataTableSort<T> | null) => void;\n      }\n    | {\n          /**\n           * Sorting is the caller's job: clicking a header reports through\n           * `onSortChange` and the rows are left in the order they arrived.\n           *\n           * Implied by `totalItems`, because sorting the page in memory would sort\n           * *that page only* while the header claims the whole table is ordered.\n           */\n          manualSort: true;\n          /** Where the click goes. Required, since nothing else acts on it. */\n          onSortChange: (sort: DataTableSort<T> | null) => void;\n      };\n\n/**\n * Searching: delegated, and therefore reported, or neither.\n *\n * `manualSearch` without `onSearchChange` renders a search box that filters\n * nothing and tells nobody — the same shape of lie as a header arrow that turns\n * without sorting.\n *\n * Independent of the paging axis on purpose, and that leaves one gap this type\n * does not close: `totalItems` *implies* `manualSearch`, so a server-mode table\n * with `searchable` and no `onSearchChange` falls into the same hole without ever\n * writing `manualSearch`. Closing it means the search axis has to read the paging\n * axis, which crosses two three-member unions into nine and turns every mismatch\n * into a wall of candidate shapes. That case is a dev warning instead — the one\n * spot where runtime really is the cheaper check, and `use-dev-warnings.ts` says\n * so at the call site.\n */\nexport type DataTableSearchProps =\n    | {\n          /** The table filters the rows it has. */\n          manualSearch?: false;\n          /** Called with the current search term (debouncing, if any, is the caller's). */\n          onSearchChange?: (term: string) => void;\n      }\n    | {\n          /**\n           * Searching is the caller's job: typing reports through `onSearchChange`\n           * and the rows are left as they arrived.\n           *\n           * Implied by `totalItems`. Filtering the current page would hide the rows\n           * that do not match *on this page* and show nothing for a term that only\n           * matches on page three — an empty table that looks like \"no results\".\n           */\n          manualSearch: true;\n          /** Where the typing goes. Required, since nothing else acts on it. */\n          onSearchChange: (term: string) => void;\n      };\n\n/**\n * The table's props: the shared half, plus one valid paging shape and one valid\n * sorting shape.\n */\nexport type DataTableProps<T> = DataTableBaseProps<T> &\n    DataTablePagingProps &\n    DataTableSortProps<T> &\n    DataTableSearchProps;\n\n/** Identity of one cell, stable across re-renders and pagination. */\nfunction cellId(rowKeyValue: string | number, columnKey: PropertyKey): string {\n    return `${String(rowKeyValue)}::${String(columnKey)}`;\n}\n\nfunction headerText<T>(column: DataTableColumn<T>): string {\n    return typeof column.header === \"string\" ? column.header : String(column.key);\n}\n\n/**\n * Stateful, headless data table built on top of {@link Table}. Adds\n * client-side searching, click-to-sort columns, pagination and opt-in inline\n * editing while delegating all table markup to the underlying Table component.\n *\n * - Clicking a sortable header cycles asc → desc → unsorted.\n * - Search matches a case-insensitive substring across `searchKeys`\n *   (or every string/number column when not provided).\n * - Pagination is hidden when the result fits on a single page.\n * - A column with `editable` renders a button that opens an inline editor;\n *   `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.\n *\n * Editing is strictly opt-in: with no `editable` column (or no `onCellChange`) the\n * rendered markup is byte-for-byte what it was before the feature existed, which\n * matters because the component is published.\n *\n * ## Optimistic, with a visible rollback\n *\n * An accepted edit is shown immediately and `onCellChange` runs in the background.\n * If it rejects, the cell returns to the old value **and** shows the reason as a\n * `role=\"alert\"` tied to the cell. A silent revert is worse than no optimistic\n * update at all: the user watched their edit appear and has no reason to doubt it.\n *\n * The header memo depends on `columns`, `sort` and the editing state only:\n * `toggleSort` and the commit callbacks are recreated each render but always close\n * over the same setters, so including them would rebuild every header on every\n * render without changing behaviour. That is why `exhaustive-deps` is silenced on\n * that dependency array.\n */\nexport function DataTable<T>({\n    data,\n    columns,\n    pageSize = 10,\n    searchable = false,\n    searchKeys,\n    initialSort,\n    rowKey = (_row, index) => index,\n    emptyMessage,\n    onCellChange,\n    editLabels,\n    totalItems,\n    page: controlledPage,\n    onPageChange,\n    manualSort,\n    onSortChange,\n    manualSearch,\n    onSearchChange,\n    loading = false,\n    className,\n    ...rest\n}: DataTableProps<T>) {\n    const [search, setSearch] = useState<string>(\"\");\n    const [sort, setSort] = useState<DataTableSort<T> | null>(initialSort ?? null);\n    const { page: internalPage, setPage: setInternalPage } = usePagination(1, pageSize);\n    const announce = useAnnounce();\n\n    const serverMode = totalItems !== undefined;\n    const sortIsManual = manualSort ?? serverMode;\n    const searchIsManual = manualSearch ?? serverMode;\n    const page = controlledPage ?? internalPage;\n\n    const setPage = useCallback(\n        (next: number) => {\n            if (controlledPage === undefined) setInternalPage(next);\n            onPageChange?.(next);\n        },\n        [controlledPage, setInternalPage, onPageChange],\n    );\n\n    useDevWarnings({\n        serverMode,\n        controlledPage,\n        onPageChange,\n        sortIsManual,\n        hasSortableColumn: columns.some((column) => column.sortable),\n        onSortChange,\n        searchable,\n        onSearchChange,\n    });\n\n    const [editing, setEditing] = useState<string | null>(null);\n    const [refocus, setRefocus] = useState<string | null>(null);\n    const [overrides, setOverrides] = useState<Record<string, unknown>>({});\n    const [errors, setErrors] = useState<Record<string, string>>({});\n    const [saving, setSaving] = useState<Record<string, boolean>>({});\n\n    const labels = useMemo<DataTableEditLabels>(\n        () => ({ ...DEFAULT_EDIT_LABELS, ...editLabels }),\n        [editLabels],\n    );\n    const editingEnabled = onCellChange !== undefined && columns.some((column) => column.editable);\n\n    const effectiveSearchKeys = useMemo<(keyof T)[]>(() => {\n        if (!searchable || searchIsManual) return [];\n        if (searchKeys && searchKeys.length > 0) return searchKeys;\n        return columns\n            .filter((column) => {\n                const sample = data.find((row) => row[column.key] != null);\n                const value = sample ? sample[column.key] : undefined;\n                return typeof value === \"string\" || typeof value === \"number\";\n            })\n            .map((column) => column.key);\n    }, [searchable, searchIsManual, searchKeys, columns, data]);\n\n    const filtered = useMemo<T[]>(() => {\n        const term = search.trim().toLowerCase();\n        if (!term || !searchable || searchIsManual) return data;\n        return data.filter((row) =>\n            effectiveSearchKeys.some((key) => {\n                const value = row[key];\n                return value != null && String(value).toLowerCase().includes(term);\n            }),\n        );\n    }, [data, search, searchable, searchIsManual, effectiveSearchKeys]);\n\n    const sorted = useMemo<T[]>(() => {\n        if (!sort || sortIsManual) return filtered;\n        const factor = sort.direction === \"asc\" ? 1 : -1;\n        return [...filtered].sort((a, b) => compareValues(a[sort.key], b[sort.key]) * factor);\n    }, [filtered, sort, sortIsManual]);\n\n    const rowCount = totalItems ?? sorted.length;\n    const totalPages = Math.max(1, Math.ceil(rowCount / pageSize));\n\n    /**\n     * Clamp the current page when the dataset shrinks (e.g. after filtering).\n     *\n     * Skipped in server mode: `page` belongs to the caller there, and a clamp\n     * fired against a `totalItems` that has not caught up with the new filter\n     * yet would send them a page they did not ask for, mid-fetch.\n     */\n    useEffect(() => {\n        if (!serverMode && page > totalPages) setPage(totalPages);\n    }, [serverMode, page, totalPages, setPage]);\n\n    const safePage = serverMode ? page : Math.min(page, totalPages);\n    const pageRows = useMemo<T[]>(() => {\n        if (serverMode) return sorted;\n        const start = (safePage - 1) * pageSize;\n        return sorted.slice(start, start + pageSize);\n    }, [serverMode, sorted, safePage, pageSize]);\n\n    function toggleSort(key: keyof T): void {\n        const current = sort;\n        const next: DataTableSort<T> | null =\n            !current || current.key !== key\n                ? { key, direction: \"asc\" }\n                : current.direction === \"asc\"\n                  ? { key, direction: \"desc\" }\n                  : null;\n        setSort(next);\n        onSortChange?.(next);\n    }\n\n    const absoluteIndex = useCallback(\n        (pageIndex: number) => (safePage - 1) * pageSize + pageIndex,\n        [safePage, pageSize],\n    );\n\n    /**\n     * Every editable cell on the page, row-major — the order `Tab` walks.\n     *\n     * Row-major and not column-major because a row is the record a user is\n     * correcting; walking down a column would make them re-find their place on\n     * every keystroke.\n     */\n    const editableCellIds = useMemo<string[]>(() => {\n        if (!editingEnabled) return [];\n        const ids: string[] = [];\n        pageRows.forEach((row, index) => {\n            const key = rowKey(row, absoluteIndex(index));\n            for (const column of columns) {\n                if (column.editable) ids.push(cellId(key, column.key));\n            }\n        });\n        return ids;\n        // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, [editingEnabled, pageRows, columns, absoluteIndex]);\n\n    const displayed = useCallback(\n        (row: T, column: DataTableColumn<T>, id: string): unknown =>\n            id in overrides ? overrides[id] : row[column.key],\n        [overrides],\n    );\n\n    /**\n     * Run the caller's `onCellChange` behind the optimistic update.\n     *\n     * Only the *success* is announced. The failure already renders as a\n     * `role=\"alert\"` inside the cell, which screen readers read on insertion —\n     * announcing it again from the shared region would read it twice and put the\n     * same text in the document twice.\n     */\n    const persist = useCallback(\n        async (id: string, column: DataTableColumn<T>, change: DataTableCellChange<T>) => {\n            setSaving((current) => ({ ...current, [id]: true }));\n            try {\n                await onCellChange?.(change);\n                announce(labels.saved(headerText(column)));\n            } catch (error) {\n                setOverrides((current) => {\n                    const next = { ...current };\n                    delete next[id];\n                    return next;\n                });\n                const message =\n                    error instanceof Error && error.message\n                        ? error.message\n                        : labels.saveFailed(headerText(column));\n                setErrors((current) => ({ ...current, [id]: message }));\n            } finally {\n                setSaving((current) => {\n                    const next = { ...current };\n                    delete next[id];\n                    return next;\n                });\n            }\n        },\n        [onCellChange, announce, labels],\n    );\n\n    const moveFrom = useCallback(\n        (id: string, move: CellCommitMove): void => {\n            if (move === \"none\") {\n                setEditing(null);\n                setRefocus(id);\n                return;\n            }\n            const index = editableCellIds.indexOf(id);\n            const target = editableCellIds[index + (move === \"next\" ? 1 : -1)];\n            if (target === undefined) {\n                setEditing(null);\n                setRefocus(id);\n                return;\n            }\n            setEditing(target);\n            setRefocus(null);\n        },\n        [editableCellIds],\n    );\n\n    /**\n     * Parse, validate, stage optimistically, then save in the background.\n     *\n     * Validation runs before anything is staged, and a rejection leaves the editor\n     * open with the message attached to the input — the user has to be able to fix\n     * what they typed without retyping it.\n     */\n    const commit = useCallback(\n        (\n            row: T,\n            column: DataTableColumn<T>,\n            id: string,\n            pageIndex: number,\n            raw: string,\n            move: CellCommitMove,\n        ): void => {\n            const previous = displayed(row, column, id);\n            const currentText = column.formatEdit ? column.formatEdit(row) : String(previous ?? \"\");\n            if (raw === currentText) {\n                moveFrom(id, move);\n                return;\n            }\n\n            const value = column.parse\n                ? column.parse(raw, row)\n                : column.editorType === \"number\"\n                  ? Number(raw)\n                  : raw.trim();\n\n            const invalid = column.validate?.(value, row) ?? null;\n            if (invalid) {\n                setErrors((current) => ({ ...current, [id]: invalid }));\n                return;\n            }\n\n            setErrors((current) => {\n                const next = { ...current };\n                delete next[id];\n                return next;\n            });\n            setOverrides((current) => ({ ...current, [id]: value }));\n            moveFrom(id, move);\n            void persist(id, column, {\n                row,\n                key: column.key,\n                value,\n                previous,\n                rowIndex: absoluteIndex(pageIndex),\n            });\n        },\n        [displayed, moveFrom, persist, absoluteIndex],\n    );\n\n    const tableColumns = useMemo<TableColumn<T>[]>(\n        () =>\n            columns.map((column) => {\n                const isSorted = sort?.key === column.key;\n                const indicator = isSorted ? (sort?.direction === \"asc\" ? \" ▲\" : \" ▼\") : \"\";\n                const header = column.sortable ? (\n                    <button\n                        type=\"button\"\n                        className={styles.sortButton}\n                        onClick={() => toggleSort(column.key)}\n                        aria-label={`Ordenar por ${headerText(column)}`}\n                    >\n                        {column.header}\n                        <span className={styles.sortIndicator} aria-hidden>\n                            {indicator}\n                        </span>\n                    </button>\n                ) : (\n                    column.header\n                );\n\n                const plainCell = (row: T): ReactNode => {\n                    if (column.render) return column.render(row);\n                    return (row[column.key] as ReactNode) ?? null;\n                };\n\n                /**\n                 * Render an editable cell's content against the optimistic value.\n                 *\n                 * The row is shallow-patched rather than the value passed alongside it,\n                 * because a column with a custom `render` (a `<Money>`, a badge) reads\n                 * the row — handing it the stale row would show the old number under a\n                 * cell the user just changed.\n                 */\n                const patchedCell = (row: T, value: unknown): ReactNode => {\n                    const patched = { ...row, [column.key]: value } as T;\n                    if (column.render) return column.render(patched);\n                    return (patched[column.key] as ReactNode) ?? null;\n                };\n\n                const editable = editingEnabled && column.editable === true;\n\n                return {\n                    key: String(column.key),\n                    header,\n                    align: column.align,\n                    priority: column.priority,\n                    width: column.width,\n                    render: editable\n                        ? (row: T, index: number) => {\n                              const id = cellId(rowKey(row, absoluteIndex(index)), column.key);\n                              const value = displayed(row, column, id);\n                              const text = column.formatEdit\n                                  ? column.formatEdit(row)\n                                  : String(value ?? \"\");\n                              return (\n                                  <EditableCell\n                                      text={text}\n                                      columnLabel={headerText(column)}\n                                      rowNumber={index + 1}\n                                      inputType={column.editorType ?? \"text\"}\n                                      editing={editing === id}\n                                      refocus={refocus === id}\n                                      saving={saving[id] === true}\n                                      error={errors[id] ?? null}\n                                      errorId={`tempest-cell-error-${id.replace(/[^\\w-]/g, \"_\")}`}\n                                      labels={labels}\n                                      onOpen={() => {\n                                          setEditing(id);\n                                          setRefocus(null);\n                                      }}\n                                      onCommit={(raw, move) =>\n                                          commit(row, column, id, index, raw, move)\n                                      }\n                                      onCancel={() => {\n                                          setEditing(null);\n                                          setRefocus(id);\n                                          setErrors((current) => {\n                                              const next = { ...current };\n                                              delete next[id];\n                                              return next;\n                                          });\n                                      }}\n                                  >\n                                      {patchedCell(row, value)}\n                                  </EditableCell>\n                              );\n                          }\n                        : plainCell,\n                };\n            }),\n        // eslint-disable-next-line react-hooks/exhaustive-deps\n        [\n            columns,\n            sort,\n            editingEnabled,\n            editing,\n            refocus,\n            saving,\n            errors,\n            labels,\n            overrides,\n            absoluteIndex,\n            commit,\n        ],\n    );\n\n    const showSkeleton = loading && pageRows.length === 0;\n\n    return (\n        <div className={cn(styles.wrapper, className)} {...rest}>\n            {searchable && (\n                <SearchBar\n                    value={search}\n                    onChange={(value) => {\n                        setSearch(value);\n                        setPage(1);\n                        onSearchChange?.(value);\n                    }}\n                    wrapperClassName={styles.search}\n                />\n            )}\n            <div\n                className={cn(loading && !showSkeleton && styles.pending)}\n                aria-busy={loading || undefined}\n                data-testid=\"tempest-datatable-body\"\n            >\n                {showSkeleton ? (\n                    <LoadingRows columns={tableColumns.length} rows={Math.min(pageSize, 8)} />\n                ) : (\n                    <Table\n                        columns={tableColumns}\n                        data={pageRows}\n                        rowKey={(row, index) => rowKey(row, absoluteIndex(index))}\n                        emptyMessage={emptyMessage}\n                    />\n                )}\n            </div>\n            {totalPages > 1 && (\n                <Pagination\n                    page={safePage}\n                    totalPages={totalPages}\n                    onPageChange={setPage}\n                    totalItems={rowCount}\n                />\n            )}\n        </div>\n    );\n}\n"],"mappings":"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"}