import { type ComponentType, type ReactNode } from "react";
import { type BreakpointKey, type LayoutStyle } from "../../style/index.js";
import { type CheckboxProps } from "../../atoms/checkbox/checkbox.shared.js";
import { type PaginationProps } from "../../atoms/pagination/pagination.shared.js";
import { type SkeletonProps } from "../../atoms/skeleton/skeleton.shared.js";
import { type Density, type DataTableSkin } from "./data-table.styles.js";
export type { Density };
/**
* A column descriptor. Plain strings stay supported (a string is shorthand for
* `{ label }`); the object form unlocks per-column alignment, fixed widths, and
* sorting.
*/
export interface DataTableColumn {
/** Column header label. */
label: string;
/** Stable identity used by `sort.column`; defaults to the label. */
key?: string;
/** Right-align the header and cells (amounts, counts, measurements). */
numeric?: boolean;
/** Center the header and cells (short status/flag columns). */
centered?: boolean;
/** Fixed width in px instead of the equal flex share. Wins over `fit`, `grow` and `minWidth`. */
width?: number;
/**
* Size the column to its widest cell, its heading included, instead of the equal flex
* share: a grid's `max-content` track. The table measures the column's cells and holds
* every one at the widest, so a column of buttons lines up at the width of its longest
* label. Wins over `grow` and `minWidth`; a table holding a `fit` column pans once the
* measured columns add up to more than it has.
*/
fit?: boolean;
/**
* The column's relative weight in the width the fixed columns leave: a column with
* `grow: 2` takes twice the share of one with `grow: 1` (the default every column
* has), the way a grid's `2fr` does beside `1fr`. Mixes freely with fixed `width`s.
*/
grow?: number;
/**
* The narrowest the column's box (its cell padding included) may get, in px, as a
* grid's `minmax(min, fr)` floor. Once the declared floors add up to more than the
* table's width, the table pans horizontally at any width instead of crushing the
* columns (a table without a declared floor pans only below the `sm` width).
*/
minWidth?: number;
/**
* Opt this column into header-press sorting. Unnecessary when the table-level
* `sortable` is set (there it opts back OUT via `sortable: false`).
*/
sortable?: boolean;
/**
* Derive the comparable value for sorting when this column's cells are custom
* ReactNodes (a Badge, a link). String/number cells sort out of the box;
* without this, custom-node cells sort last. Keep this function pure: its
* results are cached until rows or columns change. If it closes over changing
* external data, replace the function, its descriptor, and the columns array.
*/
sortValue?: (cell: ReactNode, row: ReactNode[], rowIndex: number) => string | number | null | undefined;
}
/**
* A titled group of rows (`groups`): a band spanning every column above the group's
* rows, carrying its label, an optional adornment and an optional count.
*/
export interface DataTableGroup {
/** The band's label. A string takes the band's label type; any other node renders as given. */
label: ReactNode;
/** A node after the label, such as a `pick one` marking the group's rule. */
adornment?: ReactNode;
/** A count after the adornment, in the muted monospace meta type. */
count?: string | number;
/** The group's rows, in the shape `rows` takes. */
rows: ReactNode[][];
}
/** The active sort: which column (by `key`, or label) and which direction. */
export interface DataTableSort {
/** The sorted column's `key` (the label when no key was given). */
column: string;
/** Descending when true; ascending otherwise. */
descending?: boolean;
}
export interface DataTableProps {
/**
* Columns: a header label per column, or a `DataTableColumn` descriptor for
* per-column alignment (`numeric`/`centered`), a fixed `width`, and sorting
* (`sortable`, `sortValue`). Strings and descriptors mix freely. Treat the
* array and descriptors as immutable: replace both when a column changes.
*/
columns: Array;
/**
* Row data: an array of rows, each an array of cells (one per column). A cell is
* a string (rendered in the default cell type) or any ReactNode for a custom
* cell, such as a link, a `Badge`, or a monospace name (rendered directly).
* Treat this data as immutable: replace the outer array and each changed row
* when data changes, so cached sorting and pagination update correctly.
*/
rows?: ReactNode[][];
/**
* Group the rows under titled bands (the props table's "Intent", "Size" and "State"
* groups): each group draws a band spanning every column, its label, an optional
* adornment and an optional count on the sunken fill, then its own rows. Given
* `groups`, the table's rows are the groups' rows in order and `rows` is ignored;
* every row index a callback reports (`onRowPress`, `onRowEdit`, `rowKey` and the
* rest) counts through them in that order. Sorting reorders rows within their group
* and never moves a group; paging pages the rows, and each page draws the band of
* every group it shows. A group with no rows draws no band.
*/
groups?: DataTableGroup[];
/** Tint every other data row for easier horizontal scanning. */
striped?: boolean;
/** Draw the table's frame on the firmer field boundary rather than the hairline. */
bordered?: boolean;
/**
* The table sits flush inside a frame its parent draws (a `flush` Card, a
* bordered panel that clips to its corners), so it draws no frame of its own.
* Without it a standalone table frames itself
*
* (on the web and Android, a
* hairline at the table corner over the card fill),
*
* which is the standalone
* look.
*/
attached?: boolean;
/**
* Responsive: when the table's own CONTAINER is at or below `stackBreakpoint`
* (default `sm` = 640), each row lays its cells out top to bottom at the full
* width instead of side by side, so long text reads at the width of the
* table rather than a column's share of it. The first cell leads the row as
* its title; every later cell carries its column label above its value. The
* header row is drawn only while it holds a control (a sortable column, or
* the box that selects every row), as a band of its labels that wraps; the
* selection box and the row actions stay at the row's leading and trailing
* edges. A stacked table never pans,
*
* and on iOS it stacks instead of
* collapsing to its first column.
*
* Container-measured with a viewport seed for
* the first frame, like Row `stacks`; crossing the breakpoint changes the
* layout only.
*/
stacks?: boolean;
/** The breakpoint at and below which `stacks` stacks the rows (default
* `"sm"`). Only meaningful with `stacks` (DEV warns without it). */
stackBreakpoint?: BreakpointKey;
/** Tighter vertical padding on header and data cells. */
compact?: boolean;
/** Looser vertical padding on header and data cells. */
comfortable?: boolean;
/**
* The reference sheet (a component page's props table): the column headings as the
* page's small uppercase mono label on a header row with no fill of its own, 12 px above
* and below whatever the density; rows 10 px above and below with a rule above each;
* the columns 16 px apart and 16 px in from the frame's sides; and the frame at the
* panel corner on the `border` hairline over the card fill, so `bordered` only firms the
* hairline and `attached` still drops the frame.
*
* On iOS the table keeps its own look and this changes nothing.
*
*
* The table keeps its own look and this changes nothing.
*
*/
reference?: boolean;
/**
* The bare hairline table: no frame and no fill, a `field-border` rule under the
* headings (the reference sheet's mono uppercase label) and a `border` rule under every
* row, the first column flush with the table's start, each cell keeping 12 px clear at
* its end inside its column's width, and 12 px above and below whatever the density.
* `reference` wins over it.
*
* On iOS the table keeps its own look and this changes nothing.
*
*
* The table keeps its own look and this changes nothing.
*
*/
bare?: boolean;
/**
* The specimen matrix (a section page's states grid): no frame, no fill and no rules, the
* headings as the page's small uppercase mono label in the third ink, the cells unpadded,
* the rows 12 px apart and the columns 20 px apart. Pair it with `fit` columns for the
* hand-off's content-sized tracks. `reference` and `bare` win over it.
*
* On iOS the table keeps its own look and this changes nothing.
*
*
* The table keeps its own look and this changes nothing.
*
*/
matrix?: boolean;
/**
* Align every cell to the top of its row rather than its middle, so a row whose
* description wraps keeps its name, type and default beside the description's first
* line. The selection box and the row actions center on that first line, as they do in
* a stacked row.
*/
alignTop?: boolean;
/**
* A row drawn inside the table's frame under the last row (and under the pagination
* bar when `paginated`): 44 px tall with its content centered, for a "Show all"
* control or a note. A hairline separates it from what sits above it: the one the last
* row draws already, or its own where nothing above it draws one.
*/
footer?: ReactNode;
/**
* Make every column sortable: pressing a header cycles ascending, descending,
* off. A column descriptor opts back out with `sortable: false`. Sorting is
* self-managed out of the box; control it via `sort`/`onSortChange`.
*/
sortable?: boolean;
/** Controlled sort state (`null` = unsorted). Omit for uncontrolled use. */
sort?: DataTableSort | null;
/** Initial sort for uncontrolled use. */
defaultSort?: DataTableSort | null;
/** Fired with the next sort (or `null` when cleared) on header press. */
onSortChange?: (sort: DataTableSort | null) => void;
/**
* Row selection: a leading checkbox column with a select-all header checkbox
* (indeterminate on a partial selection). Selection is keyed by `rowKey` (the
* row's original index when omitted) and self-managed out of the box; control
* it via `selectedKeys`/`onSelectionChange`. When no `onRowPress` is set,
* pressing anywhere on a row toggles it.
*/
selectable?: boolean;
/** Controlled selected row keys. Omit for uncontrolled use. */
selectedKeys?: Array;
/** Initial selected row keys for uncontrolled use. */
defaultSelectedKeys?: Array;
/** Fired with the next selected keys when a row or the select-all is toggled. */
onSelectionChange?: (keys: Array) => void;
/**
* Page the rows through a built-in footer (the kit Pagination): a
* "Showing X-Y of N" range with Prev/Next, plus the selection count when
* `selectable`. Sorting applies before paging. Self-managed out of the box;
* control the page via `page`/`onPageChange`.
*/
paginated?: boolean;
/** Rows per page (CONTROLLED; default 10, or the first of `pageSizes`). */
pageSize?: number;
/** Initial rows per page for uncontrolled use. */
defaultPageSize?: number;
/**
* Selectable rows-per-page values. Supplying them upgrades the footer to the
* Pagination `withSize` variant (a "Rows per page" selector).
*/
pageSizes?: number[];
/** Fired with the next rows-per-page value when the footer selector changes it. */
onPageSizeChange?: (size: number) => void;
/** Current page, 1-based (CONTROLLED). Omit for uncontrolled use. */
page?: number;
/** Initial page for uncontrolled use. */
defaultPage?: number;
/** Fired with the next 1-based page when the footer pagination navigates. */
onPageChange?: (page: number) => void;
/**
* Loading state: the body renders pulsing skeleton placeholder rows (one per
* would-be row on the page) instead of data.
*/
loading?: boolean;
/**
* What to render, centered under the header, when `rows` is empty (and not
* `loading`). A string gets the muted caption type; any ReactNode renders as
* given (an `EmptyState`, a retry Button). Omitted = just the header row, as
* before.
*/
emptyMessage?: ReactNode;
/**
* When set, each data row is pressable, reporting the row data and its index
* in `rows`. A press anywhere on the row acts; the keyboard and screen-reader
* path is a button inside the row's FIRST column, named from the row's plain
* text cells (or, when it has none, by that cell's own content). The row
* itself stays a `row`, so keep your own controls out of the first column
* here: a control there would nest inside the activator.
*/
onRowPress?: (row: ReactNode[], index: number) => void;
/**
* Row editing: passing this adds a trailing actions column with a pencil
* button per row. Pressing the pencil opens the row's edit mode (its string
* cells become fields with a trailing Save/Cancel pair) and fires this with
* the row's original index in `rows`. Save reports the edited cells through
* `onRowCommit`; Cancel (or Escape in a field) closes without committing.
*/
onRowEdit?: (rowIndex: number) => void;
/**
* Row deletion: passing this adds a delete (bin) button to the trailing
* actions column. Delete is second-press confirm: the first press ARMS it
* (the bin turns destructive and its accessible name says confirm), a second
* press within the confirm window fires this with the row's original index,
* and pressing anywhere else in the table (or the window lapsing) disarms.
*/
onRowDelete?: (rowIndex: number) => void;
/**
* Let string cells be edited in place: pressing one swaps it to a field.
* Enter or blur commits through `onCellCommit`; Escape restores the cell.
* Custom ReactNode cells (badges, links) are not editable.
*/
inlineEdit?: boolean;
/**
* Fired when an `inlineEdit` cell commits (Enter or blur) with a changed
* value: the row's original index in `rows`, the column index, and the next
* text. Data stays yours: re-render with updated `rows` to keep the edit.
*/
onCellCommit?: (rowIndex: number, colIndex: number, next: string) => void;
/**
* Fired when a pencil-opened row edit is saved: the row's original index in
* `rows` and the full cells array with the edited strings in place (custom
* ReactNode cells pass through unchanged).
*/
onRowCommit?: (rowIndex: number, cells: ReactNode[]) => void;
/**
* Render the data rows through a windowed `FlatList` instead of mounting every
* row up front, for large tables. The header row stays fixed above it. Give the
* table a bounded height (via `style`, e.g. `{ maxHeight: 400 }`) so the body can
* scroll; without one it warns and renders eagerly. Default mounts all rows.
*/
virtualized?: boolean;
/**
* Stable key for a row, derived from the row data and its index in `rows`.
* Selection is keyed by it, and it keeps React row identity stable when rows
* reorder (sorting, live data) and a cell is a stateful custom ReactNode. When
* omitted, rows key off their original array index (safe for string/number
* cells and stateless custom cells; selection then tracks row POSITIONS, so
* supply a real key when the data itself can be reordered, inserted, or
* deleted). Keep this function pure; replace its identity when external data
* changes how keys are derived, so the cached selection summary updates.
*/
rowKey?: (row: ReactNode[], index: number) => string | number;
/** E2E hook forwarded to the root element. */
testID?: string;
/** Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds. */
style?: LayoutStyle;
}
export declare function densityOf(p: DataTableProps): Density;
export declare function lookOf(p: Pick): "reference" | "bare" | "matrix" | "table";
export declare function rowAlignOf(p: Pick): "top" | "center";
export declare function columnAlignOf(col: Pick): "end" | "center" | "start";
export interface DataTableParts {
Checkbox: ComponentType;
Pagination: ComponentType;
Skeleton: ComponentType;
}
/** Build a DataTable component from a platform skin plus its platform parts. */
export declare function createDataTable(skin: DataTableSkin, parts: DataTableParts): (props: DataTableProps) => import("react").JSX.Element;
//# sourceMappingURL=data-table.shared.d.ts.map