@gridkitjs/react 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/DataGrid/DataGrid.tsx","../src/DataGrid/components/GridHeader.tsx","../src/DataGrid/ariaAttr.ts","../src/DataGrid/classNames.ts","../src/DataGrid/useGridNavigation.ts","../src/DataGrid/useGridSelection.ts","../src/DataGrid/commitIfChanged.ts","../src/DataGrid/components/GridBody.tsx","../src/DataGrid/components/GridGroupRow.tsx","../src/DataGrid/components/GridRow.tsx","../src/DataGrid/components/GroupByBar.tsx","../src/DataGrid/groupByDropTarget.ts","../src/DataGrid/useDragReorder.ts","../src/DataGrid/pointerGesture.ts","../src/DataGrid/useGroupByDrag.ts","../src/DataGrid/useColumnDrag.ts","../src/DataGrid/useColumnResize.ts","../src/DataGrid/measureColumnContent.ts","../src/DataGrid/useColumnSort.ts","../src/DataGrid/useElementWidth.ts","../src/DataGrid/useRowGrouping.ts"],"sourcesContent":["import {\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport {\n applyColumnOrder,\n defineColumnsFromRows,\n fitColumnsToWidth,\n groupRows,\n moveColumnBefore,\n resolveColumnWidths,\n resolveRowId,\n resolveShownRows,\n totalColumnWidth,\n type ColumnDefinition as CoreColumnDefinition,\n type ResolvedColumn as CoreResolvedColumn,\n type ColumnOrderEvent,\n type ColumnOrderState,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n type ColumnSortEvent,\n type ColumnSortState,\n type DisplayRow,\n type FilterState,\n type GroupByEvent,\n type GroupByState,\n type GroupExpansionEvent,\n type GroupExpansionState,\n type ResolvedRow,\n type CellSelectionState,\n type SelectableConfig,\n type SelectedCell as CoreSelectedCell,\n type SelectedColumn as CoreSelectedColumn,\n type SelectionState,\n type CellSelectEvent as CoreCellSelectEvent,\n type CellSelectionChangeEvent as CoreCellSelectionChangeEvent,\n type ColumnSelectEvent as CoreColumnSelectEvent,\n type ColumnSelectionChangeEvent as CoreColumnSelectionChangeEvent,\n type ColumnsSelectEvent as CoreColumnsSelectEvent,\n} from \"@gridkitjs/core\";\nimport GridHeader from \"./components/GridHeader\";\nimport GridBody from \"./components/GridBody\";\nimport GroupByBar from \"./components/GroupByBar\";\nimport { ariaAttr } from \"./ariaAttr\";\nimport { classNames } from \"./classNames\";\nimport useColumnDrag, { type DropTarget } from \"./useColumnDrag\";\nimport useColumnResize from \"./useColumnResize\";\nimport useColumnSort from \"./useColumnSort\";\nimport useElementWidth from \"./useElementWidth\";\nimport useGridNavigation, { HEADER_ROW } from \"./useGridNavigation\";\nimport useGridSelection, { type SelectionCallbacks } from \"./useGridSelection\";\nimport useRowGrouping from \"./useRowGrouping\";\n\n/**\n * A column whose header and cells may render arbitrary React content.\n * @gridkitjs/core stays framework-agnostic and so leaves that output type open;\n * this is the binding React consumers want, and the one they should import.\n */\nexport type ColumnDefinition<Row> = CoreColumnDefinition<Row, ReactNode>;\n\n/** A column paired with the width it renders at. */\nexport type ResolvedColumn<Row> = CoreResolvedColumn<Row, ReactNode>;\n\n/**\n * The selection payloads, bound to React's node type for the same reason\n * `ColumnDefinition` is: they carry a resolved column, whose label is whatever\n * a `headerTemplate` returned.\n *\n * The row payloads name no node type at all and so are re-exported from\n * `@gridkitjs/core` as they are.\n */\nexport type SelectedColumn<Row> = CoreSelectedColumn<Row, ReactNode>;\nexport type SelectedCell<Row> = CoreSelectedCell<Row, ReactNode>;\nexport type ColumnSelectEvent<Row> = CoreColumnSelectEvent<Row, ReactNode>;\nexport type ColumnsSelectEvent<Row> = CoreColumnsSelectEvent<Row, ReactNode>;\nexport type ColumnSelectionChangeEvent<Row> = CoreColumnSelectionChangeEvent<\n Row,\n ReactNode\n>;\nexport type CellSelectEvent<Row> = CoreCellSelectEvent<Row, ReactNode>;\nexport type CellSelectionChangeEvent<Row> = CoreCellSelectionChangeEvent<\n Row,\n ReactNode\n>;\n\n/**\n * Imperative handle for a mounted `DataGridComponent`, reached via its `ref`\n * prop. Read-plus-standard-actions: getters mirror the grid's live state,\n * and the actions are the ones every grid ref carries (focus, clear/select\n * all, scroll-to). Sizing, order, sort, and selection stay uncontrolled via\n * their existing `default*` props — this is not a second, imperative-only\n * way to drive that same state.\n */\nexport interface DataGridApi<Row> {\n /** The grid's scrollable viewport element. */\n readonly element: HTMLDivElement | null;\n /** The grid's `<table>` element. */\n readonly table: HTMLTableElement | null;\n\n /** Rows as currently filtered and sorted — what's rendered, ungrouped. */\n getRows(): readonly ResolvedRow<Row>[];\n /**\n * `getRows()` regrouped into the active `groupBy` — group headers\n * interleaved with data rows, in render order. Identical to `getRows()`\n * when `groupBy` is empty.\n */\n getDisplayRows(): readonly DisplayRow<Row>[];\n /** Columns as currently sized and ordered — what's rendered. */\n getColumns(): readonly ResolvedColumn<Row>[];\n\n getColumnSizing(): ColumnSizingState;\n getColumnOrder(): ColumnOrderState;\n getColumnSort(): ColumnSortState;\n getGroupBy(): GroupByState;\n getGroupExpansion(): GroupExpansionState;\n getRowSelection(): SelectionState;\n getColumnSelection(): SelectionState;\n getCellSelection(): CellSelectionState;\n /** The cell currently holding the grid's single tab stop. */\n getFocusedCell(): { rowIndex: number; columnIndex: number };\n\n focusCell(rowIndex: number, columnIndex: number): void;\n clearSelection(): void;\n selectAllRows(): void;\n /** Expands every group at once — there is no dedicated UI control for it. */\n expandAllGroups(): void;\n /** Collapses every group currently shown at once — see `collapseAllGroups` in `@gridkitjs/core` for what \"currently shown\" means for a group already nested under a collapsed one. */\n collapseAllGroups(): void;\n /** Scrolls the row with the given id into view, if it is currently shown. */\n scrollToRow(rowId: string, options?: ScrollIntoViewOptions): void;\n /** Scrolls the column with the given id into view. */\n scrollToColumn(columnId: string, options?: ScrollIntoViewOptions): void;\n}\n\nexport type Borders = \"horizontal\" | \"vertical\" | \"all\" | \"none\";\n\n/**\n * How a column's width relates to the grid's.\n *\n * `\"fit\"` keeps the columns filling the grid: the space a column gives up is\n * handed to the others, and the space it takes comes out of them. `\"fixed\"`\n * lets every column keep its own width, so a resize moves one column and\n * nothing else, and the grid scrolls or leaves a gap accordingly.\n */\nexport type ResizeMode = \"fit\" | \"fixed\";\n\n/**\n * How the group-by bar's visibility follows the active grouping. `\"always\"`\n * renders it even with an empty `groupBy` — a fixed drop target and a\n * constant reminder grouping exists. `\"never\"` never renders it, for a grid\n * driving `groupBy` entirely by its own UI (a header toggle, `Alt+ArrowDown`)\n * or programmatically. `\"auto\"` renders it once `groupBy` is non-empty, or\n * while a header drag eligible to drop into it is in progress — so there is\n * always somewhere to drop the very first column, even from a fully empty\n * grouping.\n */\nexport type GroupByBarVisibility = \"always\" | \"auto\" | \"never\";\n\nexport interface HoverableConfig {\n rows?: boolean;\n columns?: boolean;\n cells?: boolean;\n}\n\nexport interface DataGridProps<Row> extends SelectionCallbacks<Row> {\n columns?: readonly ColumnDefinition<Row>[] | undefined;\n dataSource?: readonly Row[] | undefined;\n /**\n * A row's stable identity, for state keyed by it. Defaults to the row's\n * position, which is enough for a static grid but ties that state to where a\n * row sits rather than to the row — so anything sorting, filtering or paging\n * its data should give one.\n *\n * Called for every row on every change to `dataSource`, so it should be\n * cheap and stable; an inline arrow is fine, one that re-reads the data is\n * not.\n */\n getRowId?: ((row: Row, index: number) => string) | undefined;\n borders?: Borders | undefined;\n hoverable?: HoverableConfig | undefined;\n /**\n * Which parts of the grid the user may select, and how many of each —\n * `{ rows: \"multiple\", cells: \"single\" }`. A cell addresses one value, so it\n * has no `\"multiple\"`.\n *\n * Off by default, unlike `hoverable`: selection claims the click, which a\n * grid that only displays data should not do. Give `getRowId` alongside it\n * for data that sorts, filters or pages, or a selection follows the position\n * rather than the row.\n */\n selectable?: SelectableConfig | undefined;\n /** Row ids selected to start with, keyed as `getRowId` resolves them. Uncontrolled. */\n defaultRowSelection?: SelectionState | undefined;\n /** Column ids selected to start with. Uncontrolled. */\n defaultColumnSelection?: SelectionState | undefined;\n /** The cell selected to start with. Uncontrolled. */\n defaultCellSelection?: CellSelectionState | undefined;\n /** Whether columns can be dragged wider, unless a column says otherwise. */\n resizableColumns?: boolean | undefined;\n /**\n * Whether columns can be dragged into a new position, unless a column says\n * otherwise. Turning it off leaves an order the user already made in place.\n */\n reorderableColumns?: boolean | undefined;\n /**\n * Whether columns fill the grid's width or sit at their own. Defaults to\n * `\"fit\"`, under which columns the user has sized keep their width and the\n * rest share what is left.\n */\n resizeMode?: ResizeMode | undefined;\n /** Column widths to start from, keyed by column id. Uncontrolled. */\n defaultColumnSizing?: ColumnSizingState | undefined;\n /**\n * Column ids in the order to start in. Uncontrolled, and partial: ids it\n * omits keep their position among `columns` and follow those it lists.\n */\n defaultColumnOrder?: ColumnOrderState | undefined;\n /**\n * Sizes applied to columns that do not set their own — the width they start\n * at and the bounds they may be resized between. Distinct from\n * `defaultColumnSizing`, which sets specific columns' starting widths.\n */\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n /**\n * Called as the user resizes a column. Fires continuously with\n * `phase: \"move\"` and once on release with `phase: \"end\"` — the latter being\n * the one to persist. Auto-fit does not call it; it reports user intent only.\n */\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n /**\n * Called once when the user drops a column somewhere new. A drop that leaves\n * the order as it was does not call it.\n */\n onColumnOrderChange?: ((event: ColumnOrderEvent) => void) | undefined;\n /**\n * Whether columns can be sorted by clicking their header toggle, unless a\n * column says otherwise. Shift-click stacks a column into the sort instead\n * of replacing it.\n */\n sortableColumns?: boolean | undefined;\n /** The sort to start with, in priority order. Uncontrolled. */\n defaultColumnSort?: ColumnSortState | undefined;\n /**\n * Called once when the user changes the sort — a toggle, a stack, or a\n * clear back to \"none\".\n */\n onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;\n /**\n * Whether columns can be grouped by — a header's click/`Alt+ArrowDown`\n * toggle — unless a column says otherwise. The grouping itself still\n * applies when this is off, via `defaultGroupBy` or the imperative API;\n * this only gates that one interaction, the same way `sortableColumns`\n * gates the sort toggle without disabling `defaultColumnSort`. Independent\n * of `groupByBarVisibility` and `groupByDraggableColumns`, which gate the\n * bar and the drag-in gesture respectively.\n */\n groupableColumns?: boolean | undefined;\n /**\n * Whether a groupable header shows its group-toggle icon, unless a column\n * says otherwise. Purely a rendering choice: `Alt+ArrowDown` keeps working\n * on a groupable header with the icon hidden.\n */\n groupToggleIconColumns?: boolean | undefined;\n /**\n * Whether a column's header may be dragged into the group-by bar to add\n * it to the grouping, unless a column says otherwise. Independent of\n * `groupableColumns`: a column can be groupable via its header's\n * click/keyboard toggle, via this drag, both, or neither.\n */\n groupByDraggableColumns?: boolean | undefined;\n /** How the group-by bar's visibility follows the active grouping. */\n groupByBarVisibility?: GroupByBarVisibility | undefined;\n /** The group-by stack to start with, outer to inner. Uncontrolled. */\n defaultGroupBy?: GroupByState | undefined;\n /**\n * Called once when the user changes the group-by stack — adding, removing,\n * or reordering a level.\n */\n onGroupByChange?: ((event: GroupByEvent) => void) | undefined;\n /** Group keys collapsed to start with — every other group starts expanded. Uncontrolled. */\n defaultGroupExpansion?: GroupExpansionState | undefined;\n /** Called once when the user expands or collapses a group, or every group at once. */\n onGroupExpansionChange?: ((event: GroupExpansionEvent) => void) | undefined;\n /** The filter to start with — every applied entry, ANDed together. Uncontrolled. */\n defaultFilter?: FilterState<Row> | undefined;\n /**\n * The grid's accessible name, announced when it takes focus. A grid without\n * one is read only as \"grid\", which says nothing about which grid.\n */\n label?: string | undefined;\n /**\n * The id of an element naming the grid, for a heading already on the page.\n * Takes precedence over `label`, as `aria-labelledby` does.\n */\n labelledBy?: string | undefined;\n /** Imperative handle for reading live grid state and triggering actions. */\n ref?: Ref<DataGridApi<Row>> | undefined;\n}\n\nexport function DataGridComponent<Row>({\n dataSource,\n columns,\n getRowId,\n borders,\n hoverable,\n selectable,\n defaultRowSelection,\n defaultColumnSelection,\n defaultCellSelection,\n resizableColumns = false,\n reorderableColumns = false,\n resizeMode = \"fit\",\n defaultColumnSizing,\n defaultColumnOrder,\n columnSizeDefaults,\n onColumnResize,\n onColumnOrderChange,\n sortableColumns = false,\n defaultColumnSort,\n onColumnSortChange,\n groupableColumns = false,\n groupToggleIconColumns = true,\n groupByDraggableColumns = false,\n groupByBarVisibility = \"auto\",\n defaultGroupBy,\n onGroupByChange,\n defaultGroupExpansion,\n onGroupExpansionChange,\n defaultFilter,\n label,\n labelledBy,\n ref,\n ...callbacks\n}: DataGridProps<Row>) {\n const hoverRows = hoverable?.rows ?? true;\n const hoverColumns = hoverable?.columns ?? true;\n const hoverCells = hoverable?.cells ?? true;\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const viewportWidth = useElementWidth(viewportRef, resizeMode === \"fit\");\n const [sizing, setSizing] = useState<ColumnSizingState>(\n defaultColumnSizing ?? {},\n );\n const [order, setOrder] = useState<ColumnOrderState>(\n defaultColumnOrder ?? [],\n );\n const [sort, setSort] = useState<ColumnSortState>(defaultColumnSort ?? []);\n const [groupBy, setGroupBy] = useState<GroupByState>(defaultGroupBy ?? []);\n const [expansion, setExpansion] = useState<GroupExpansionState>(\n defaultGroupExpansion ?? [],\n );\n const [filter] = useState<FilterState<Row>>(defaultFilter ?? []);\n const [announcement, setAnnouncement] = useState(\"\");\n const [rowSelection, setRowSelection] = useState<SelectionState>(\n defaultRowSelection ?? [],\n );\n const [columnSelection, setColumnSelection] = useState<SelectionState>(\n defaultColumnSelection ?? [],\n );\n const [cellSelection, setCellSelection] = useState<CellSelectionState>(\n defaultCellSelection ?? null,\n );\n\n /**\n * The rows as rendered, each carrying the id everything downstream keys it\n * by. Resolved once here rather than per consumer so a row's id cannot come\n * out differently in two places — the same reason `resolveColumnWidths` runs\n * once ahead of the header and the body.\n *\n * An array rather than a map keyed by id: two rows given the same id is a\n * caller's mistake, and one that should render twice and look wrong rather\n * than silently lose a row.\n */\n const rows = useMemo<readonly ResolvedRow<Row>[]>(\n () =>\n dataSource?.map((row, rowIndex) => ({\n rowId: resolveRowId(row, rowIndex, getRowId),\n row,\n rowIndex,\n })) ?? [],\n [dataSource, getRowId],\n );\n\n const definedColumns = useMemo<readonly ColumnDefinition<Row>[]>(() => {\n if (columns && columns.length !== 0) return columns;\n if (dataSource && dataSource.length > 0)\n return defineColumnsFromRows(dataSource);\n return [];\n }, [columns, dataSource]);\n\n /**\n * Ahead of sizing, so everything downstream reads one already-ordered list\n * and no part of the grid has to know a reorder happened.\n */\n const orderedColumns = useMemo(\n () => applyColumnOrder(definedColumns, order),\n [definedColumns, order],\n );\n\n /**\n * Auto-fit is a derivation rather than a write back into `sizing`, so that a\n * `width` set in a column definition is never overwritten and the effect\n * cannot chase its own output. `\"fixed\"` is then simply the absence of it.\n */\n const resolved = useMemo(() => {\n const widths = resolveColumnWidths(orderedColumns, sizing, {\n sizes: columnSizeDefaults,\n resizable: resizableColumns,\n reorderable: reorderableColumns,\n groupByDraggable: groupByDraggableColumns,\n });\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults)\n : widths;\n }, [\n orderedColumns,\n sizing,\n resizeMode,\n viewportWidth,\n columnSizeDefaults,\n resizableColumns,\n reorderableColumns,\n groupByDraggableColumns,\n ]);\n\n /**\n * `rows`, filtered then sorted — needs `resolved` for each column's\n * `field` and `type`, so it runs after sizing rather than alongside\n * `rows` itself. Everything downstream that renders or interacts with row\n * order and membership reads this rather than `rows`, so what the user\n * sees, filters, sorts, and clicks all agree.\n */\n const shownRows = useMemo(\n () => resolveShownRows(rows, filter, sort, resolved),\n [rows, filter, sort, resolved],\n );\n\n /**\n * `shownRows` regrouped into `groupBy` — group headers interleaved with\n * data rows, in render order. `GridBody` renders this rather than\n * `shownRows` directly, grouped or not: `groupRows` returns `shownRows`\n * itself, untouched, when `groupBy` is empty, so an ungrouped grid pays\n * only the cost of that check.\n */\n const displayRows = useMemo(\n () => groupRows(shownRows, groupBy, expansion, resolved),\n [shownRows, groupBy, expansion, resolved],\n );\n\n /**\n * `displayRows` narrowed back to its data rows, in the same (possibly\n * regrouped) order — what row/cell selection anchors its range-select\n * against, so that a Shift-click spans the rows actually adjacent on\n * screen rather than their pre-grouping order. A group collapsed at\n * selection time contributes no rows here at all, so a range spanning its\n * position includes only what was visible when the range was drawn, not\n * the rows hidden beneath it.\n */\n const displayDataRows = useMemo(\n () =>\n groupBy.length === 0\n ? shownRows\n : displayRows.filter(\n (entry): entry is ResolvedRow<Row> => !(\"kind\" in entry),\n ),\n [displayRows, groupBy.length, shownRows],\n );\n\n /**\n * What a column is called in an announcement. `label` carries whatever a\n * `headerTemplate` returned, which need not be text at all, so the field\n * path stands in whenever it is not.\n */\n function columnName(columnId: string): string {\n const entry = resolved.find((candidate) => candidate.id === columnId);\n if (entry === undefined) {\n return columnId;\n }\n return typeof entry.label === \"string\" ? entry.label : entry.column.field;\n }\n\n /**\n * Reports a change no visual cue can carry to a screen reader. Held as state\n * rather than written to the DOM directly so React owns the one element the\n * live region watches.\n */\n function announce(message: string): void {\n setAnnouncement(message);\n }\n\n /**\n * Wrapped rather than announced from the resize hook, which reports the\n * continuous `\"move\"` phase as well — a live region given every frame of a\n * drag says nothing an assistive technology can keep up with.\n */\n function handleColumnResize(event: ColumnResizeEvent): void {\n onColumnResize?.(event);\n if (event.phase === \"end\") {\n announce(\n `${columnName(event.columnId)}, ${String(Math.round(event.width))} pixels wide`,\n );\n }\n }\n\n const resize = useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize: handleColumnResize,\n });\n\n /** Wrapped the same way `handleColumnResize` is, for its own announcement. */\n function handleGroupByChange(event: GroupByEvent): void {\n onGroupByChange?.(event);\n const entry = event.groupBy.find(\n (candidate) => candidate.columnId === event.columnId,\n );\n if (entry === undefined) {\n announce(`${columnName(event.columnId)}, grouping removed`);\n return;\n }\n announce(\n event.groupBy.length > 1\n ? `Grouped by ${columnName(event.columnId)}, level ${String(event.groupBy.indexOf(entry) + 1)} of ${String(event.groupBy.length)}`\n : `Grouped by ${columnName(event.columnId)}`,\n );\n }\n\n /**\n * `groupId: null` marks `expandAll`/`collapseAll`, which touch every group\n * in one call rather than one at a time — announced as a single summary\n * instead of naming a group that doesn't apply.\n */\n function handleGroupExpansionChange(event: GroupExpansionEvent): void {\n onGroupExpansionChange?.(event);\n if (event.groupId === null) {\n announce(\n event.expansion.length === 0\n ? \"All groups expanded\"\n : \"All groups collapsed\",\n );\n return;\n }\n announce(\n event.expansion.includes(event.groupId)\n ? \"Group collapsed\"\n : \"Group expanded\",\n );\n }\n\n /**\n * Constructed ahead of `handleDrop`/`drag` below (rather than alongside\n * `columnSort`, its closest sibling) because `handleDrop`'s `\"group-by\"`\n * arm calls `grouping.moveGroupBy` directly.\n */\n const grouping = useRowGrouping<Row>({\n groupBy,\n setGroupBy,\n expansion,\n setExpansion,\n onGroupByChange: handleGroupByChange,\n onGroupExpansionChange: handleGroupExpansionChange,\n });\n\n const nav = useGridNavigation({\n tableRef,\n // Group headers are addressable rows too — the whole point of the flat\n // `DisplayRow[]` shape is that they share one position space with data\n // rows, so navigation counts them the same way.\n rowCount: displayRows.length,\n columnCount: resolved.length,\n });\n\n /**\n * The ids as displayed, which a drop is expressed against — the order state\n * starts empty and may name only some columns, so moving against it directly\n * would have nothing to rearrange.\n */\n const displayedIds = useMemo(\n () => orderedColumns.map((column) => column.id ?? column.field),\n [orderedColumns],\n );\n\n /** Column ids whose header may be dragged into the group-by bar at all. */\n const groupByDraggableIds = useMemo(\n () =>\n new Set(\n resolved\n .filter((entry) => entry.groupByDraggable)\n .map((entry) => entry.id),\n ),\n [resolved],\n );\n\n /**\n * The one place a drop is applied — the two-armed switch on `target.kind`\n * the group-by bar's own second drop zone was always going to need.\n */\n function handleDrop(target: DropTarget, movedId: string): void {\n if (target.kind === \"group-by\") {\n // Already announced: `grouping.moveGroupBy` commits through the same\n // `onGroupByChange` pipeline the header toggle and the bar's own chip\n // drag do, so this needs no announcement or focus-follow of its own —\n // unlike a column-order drop, the moved thing leaves the grid's single\n // tab-stop system entirely for the bar's own independently-focusable\n // chips, which have no shared index to update.\n grouping.moveGroupBy(movedId, target.beforeColumnId);\n return;\n }\n\n const next = moveColumnBefore(displayedIds, movedId, target.beforeId);\n // `moveColumnBefore` hands back the same reference for a move that changes\n // nothing, so a drop in place neither renders nor reports.\n if (next === displayedIds) {\n return;\n }\n const position = next.indexOf(movedId);\n setOrder(next);\n onColumnOrderChange?.({ columnId: movedId, order: next });\n announce(\n `${columnName(movedId)}, column ${String(position + 1)} of ${String(next.length)}`,\n );\n /**\n * The tab stop travels with the column. React reorders the headers by key,\n * so the browser's focus stays on the moved one by itself — without this\n * the stop would be left on whichever column took its index, and the next\n * arrow key would appear to do nothing.\n */\n nav.focusCell(HEADER_ROW, position);\n }\n\n const drag = useColumnDrag<Row>({\n order: displayedIds,\n groupBy,\n groupByDraggableIds,\n onDrop: handleDrop,\n });\n\n /** Whether the header drag currently open (if any) is for a column already in the group-by stack — reordering it is the chip's job, so dragging it back in is never a valid target. */\n const draggedColumnAlreadyGrouped =\n drag.draggedColumnId !== null &&\n groupBy.some((entry) => entry.columnId === drag.draggedColumnId);\n\n /**\n * Whether the drag currently open (if any) could land on the group-by bar\n * — the signal `groupByBarVisibility=\"auto\"` needs to show the bar as a\n * drop target even while `groupBy` is still empty. Depends only on\n * `draggedColumnId` (set once the drag opens), the static\n * `groupByDraggableIds`, and whether that column is already grouped, never\n * the pointer's current position, so the bar mounts for the drag's whole\n * duration rather than flickering in only while directly hovering it.\n */\n const dragEligibleForGroupBy =\n drag.draggedColumnId !== null &&\n groupByDraggableIds.has(drag.draggedColumnId) &&\n !draggedColumnAlreadyGrouped;\n\n const showGroupByBar =\n groupByBarVisibility === \"always\" ||\n (groupByBarVisibility === \"auto\" &&\n (groupBy.length > 0 || dragEligibleForGroupBy));\n\n const headerGroupByDropTarget =\n drag.dropTarget?.kind === \"group-by\" ? drag.dropTarget : null;\n\n /**\n * Wrapped the same way `handleColumnResize`/`handleDrop` are, so a toggle,\n * a stack, or a clear back to \"none\" each get their own announcement.\n */\n function handleColumnSortChange(event: ColumnSortEvent): void {\n onColumnSortChange?.(event);\n const entry = event.sort.find(\n (candidate) => candidate.columnId === event.columnId,\n );\n if (entry === undefined) {\n announce(`${columnName(event.columnId)}, sort cleared`);\n return;\n }\n const direction = entry.direction === \"asc\" ? \"ascending\" : \"descending\";\n announce(\n event.sort.length > 1\n ? `${columnName(event.columnId)} sorted ${direction}, key ${String(event.sort.indexOf(entry) + 1)} of ${String(event.sort.length)}`\n : `${columnName(event.columnId)} sorted ${direction}`,\n );\n }\n\n const columnSort = useColumnSort<Row>({\n sort,\n setSort,\n onColumnSortChange: handleColumnSortChange,\n });\n\n const selection = useGridSelection<Row>({\n rows: displayDataRows,\n columns: resolved,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n columnName,\n });\n\n const multiselectable =\n selection.rowMode === \"multiple\" || selection.columnMode === \"multiple\";\n\n /**\n * No deps array: `nav`, `selection`, `resize`, and `drag` are all freshly\n * constructed every render (none of those hooks memoize their returned\n * API), so the handle has to be rebuilt every render too or its closures\n * would go stale.\n */\n useImperativeHandle(ref, () => ({\n get element() {\n return viewportRef.current;\n },\n get table() {\n return tableRef.current;\n },\n getRows: () => shownRows,\n getDisplayRows: () => displayRows,\n getColumns: () => resolved,\n getColumnSizing: () => sizing,\n getColumnOrder: () => order,\n getColumnSort: () => sort,\n getGroupBy: () => groupBy,\n getGroupExpansion: () => expansion,\n getRowSelection: () => rowSelection,\n getColumnSelection: () => columnSelection,\n getCellSelection: () => cellSelection,\n getFocusedCell: () => nav.focus,\n focusCell: nav.focusCell,\n clearSelection: selection.clear,\n selectAllRows: selection.selectAllRows,\n expandAllGroups: grouping.expandAll,\n collapseAllGroups: () => {\n grouping.collapseAll(displayRows);\n },\n scrollToRow: (rowId, options) => {\n // `displayRows`, not `shownRows`: with grouping active a data row's DOM\n // position is its place in the grouped, flattened output, not its\n // pre-grouping index — group headers are siblings in the same `<tbody>`.\n const index = displayRows.findIndex(\n (entry) => !(\"kind\" in entry) && entry.rowId === rowId,\n );\n if (index === -1) return;\n tableRef.current?.tBodies[0]?.rows[index]?.scrollIntoView(options);\n },\n scrollToColumn: (columnId, options) => {\n const cells = tableRef.current?.querySelectorAll(\"[data-gridkit-column]\");\n const cell = cells\n ? Array.from(cells).find(\n (entry) => entry.getAttribute(\"data-gridkit-column\") === columnId,\n )\n : undefined;\n cell?.scrollIntoView(options);\n },\n }));\n\n return (\n <div className=\"gridkit-data-grid-viewport\" ref={viewportRef}>\n {showGroupByBar && (\n <GroupByBar<Row>\n columns={resolved}\n grouping={grouping}\n columnName={columnName}\n headerDragEligible={dragEligibleForGroupBy}\n headerDragBlocked={draggedColumnAlreadyGrouped}\n headerDropTarget={headerGroupByDropTarget}\n />\n )}\n <table\n ref={tableRef}\n /*\n * `role=\"grid\"` rather than the table's own semantics: it is what makes\n * the arrow keys a navigation the grid owns, and later what lets a row\n * report whether it is selected. It obliges the single tab stop\n * `useGridNavigation` keeps.\n *\n * Switches to `\"treegrid\"` — the WAI-ARIA pattern for expandable,\n * collapsible rows — whenever `groupBy` is non-empty, rather than\n * committing to it unconditionally. The alternative (always\n * `treegrid`) would change what every existing, ungrouped consumer\n * announces to assistive technology the moment this feature shipped;\n * that regression is certain, while the edge case this trades away —\n * the role flipping mid-session if a consumer removes its last\n * group-by level — is rare and, per the WAI-ARIA grid pattern, still\n * a valid `role` change to make when the row structure itself\n * changes shape. See the \"Scope note\" this mirrors: grouping stays\n * an internal detail for an ungrouped grid, ARIA role included.\n */\n role={groupBy.length > 0 ? \"treegrid\" : \"grid\"}\n // The header is a row too, and counted from one; group headers count\n // as rows here too, the same way they do in `nav`'s `rowCount`.\n aria-rowcount={displayRows.length + 1}\n aria-colcount={resolved.length}\n {...ariaAttr(multiselectable, \"aria-multiselectable\", true)}\n {...ariaAttr(labelledBy !== undefined, \"aria-labelledby\", labelledBy)}\n {...ariaAttr(\n labelledBy === undefined && label !== undefined,\n \"aria-label\",\n label,\n )}\n onKeyDown={(event) => {\n /*\n * The two keys that address the grid rather than a cell, and so are\n * caught here where everything bubbles to rather than in each of\n * them.\n */\n if (event.key === \"Escape\") {\n // A gesture in flight has its own use for Escape — cancelling —\n // and gets it first.\n if (drag.draggedColumnId !== null || resize.activeColumnId !== null)\n return;\n selection.clear();\n return;\n }\n if (\n (event.ctrlKey || event.metaKey) &&\n (event.key === \"a\" || event.key === \"A\")\n ) {\n // Left to the browser unless the grid has something to do with it,\n // so a grid without multiple rows does not swallow select-all.\n if (selection.rowMode !== \"multiple\") return;\n event.preventDefault();\n selection.selectAllRows();\n }\n }}\n // Widths are only honoured exactly when the table is as wide as its\n // columns; at `100%` the fixed layout redistributes the difference.\n style={{ width: totalColumnWidth(resolved) }}\n className={classNames(\n \"gridkit-data-grid\",\n borders ? `borders-${borders}` : \"\",\n // Hover is on by default and selection off, so one set of classes\n // turns styling off and the other turns it on. The polarity differs\n // because the defaults do.\n hoverRows ? \"\" : \"no-hover-rows\",\n hoverColumns ? \"\" : \"no-hover-columns\",\n hoverCells ? \"\" : \"no-hover-cells\",\n selection.rowMode === false ? \"\" : \"selectable-rows\",\n selection.columnMode === false ? \"\" : \"selectable-columns\",\n selection.cellMode === false ? \"\" : \"selectable-cells\",\n )}\n >\n <colgroup>\n {resolved.map((entry) => (\n <col key={entry.id} style={{ width: entry.width }} />\n ))}\n </colgroup>\n <GridHeader<Row>\n columns={resolved}\n resize={resize}\n drag={drag}\n sort={columnSort}\n sortableColumns={sortableColumns}\n grouping={grouping}\n groupableColumns={groupableColumns}\n groupToggleIconColumns={groupToggleIconColumns}\n nav={nav}\n selection={selection}\n />\n <GridBody<Row>\n columns={resolved}\n rows={displayRows}\n activeColumnId={resize.activeColumnId}\n nav={nav}\n selection={selection}\n grouping={grouping}\n />\n </table>\n {/*\n * Outside the table, which admits no `div`, and polite so it waits for a\n * pause rather than cutting across what the user is already hearing.\n */}\n <div className=\"gridkit-sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </div>\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { buildKeyShortcuts, intentOf, KEYBOARD_STEP } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { ariaAttr } from \"../ariaAttr\";\nimport { classNames } from \"../classNames\";\nimport type { ColumnDragApi } from \"../useColumnDrag\";\nimport type { ColumnResizeApi } from \"../useColumnResize\";\nimport type { ColumnSortApi } from \"../useColumnSort\";\nimport { HEADER_ROW, type GridNavigationApi } from \"../useGridNavigation\";\nimport {\n keyboardSelectIntent,\n type GridSelectionApi,\n} from \"../useGridSelection\";\nimport type { RowGroupingApi } from \"../useRowGrouping\";\n\ninterface GridHeaderProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n resize: ColumnResizeApi<Row>;\n drag: ColumnDragApi<Row>;\n sort: ColumnSortApi<Row>;\n sortableColumns: boolean;\n grouping: RowGroupingApi<Row>;\n groupableColumns: boolean;\n groupToggleIconColumns: boolean;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n}\n\n/** The common attributes behind every icon here — just the `<path>`s differ. */\nfunction Icon({ children }: { children: ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n {children}\n </svg>\n );\n}\n\n/**\n * The two glyphs a sort toggle shows: a neutral hint before a column has a\n * direction, and a single chevron reused for both directions once it does —\n * `theme-tailwind` rotates it 180° for `desc` rather than swapping icons.\n */\nfunction ChevronsUpDownIcon() {\n return (\n <Icon>\n <path d=\"m7 15 5 5 5-5\" />\n <path d=\"m7 9 5-5 5 5\" />\n </Icon>\n );\n}\n\nfunction ChevronUpIcon() {\n return (\n <Icon>\n <path d=\"m18 15-6-6-6 6\" />\n </Icon>\n );\n}\n\n/** Three stacked panes, standing in for \"group by this column\". */\nfunction GroupIcon() {\n return (\n <Icon>\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"8.5\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\" />\n </Icon>\n );\n}\n\nexport default function GridHeader<Row>({\n columns,\n resize,\n drag,\n sort,\n sortableColumns,\n grouping,\n groupableColumns,\n groupToggleIconColumns,\n nav,\n selection,\n}: GridHeaderProps<Row>) {\n // Only meaningful for the \"column-order\" branch — a drop headed for the\n // group-by bar instead (`kind: \"group-by\"`) draws no indicator here at\n // all; `GroupByBar` draws its own from the same `drag.dropTarget`.\n const beforeId =\n drag.dropTarget?.kind === \"column-order\"\n ? drag.dropTarget.beforeId\n : undefined;\n const draggedEntry =\n columns.find((entry) => entry.id === drag.draggedColumnId) ?? null;\n\n return (\n <thead>\n <tr className=\"grid-header\" role=\"row\" aria-rowindex={1}>\n {columns.map((entry, index) => {\n const { column } = entry;\n const resizing = resize.activeColumnId === entry.id;\n const dragging = drag.draggedColumnId === entry.id;\n\n /**\n * Drawn on the gap's own edge, so the one gap between two columns is\n * marked once. No guard against the dragged column: the hook reports\n * only gaps that would move it.\n */\n const dropBefore = beforeId !== undefined && beforeId === entry.id;\n const dropAfter = beforeId === null && index === columns.length - 1;\n const selected = selection.selectedColumnIds.has(entry.id);\n const sortable = column.sortable ?? sortableColumns;\n const sortDirection = sort.directionFor(entry.id);\n const sortPriority = sort.priorityFor(entry.id);\n const groupable = column.groupable ?? groupableColumns;\n // Purely a rendering choice — see the prop's own doc comment. Never\n // gates `groupable` itself, `aria-keyshortcuts`, or `Alt+ArrowDown`.\n const showGroupToggleIcon =\n column.groupToggleIcon ?? groupToggleIconColumns;\n const isGrouped = grouping.groupBy.some(\n (level) => level.columnId === entry.id,\n );\n\n const shortcuts = buildKeyShortcuts({\n reorderable: entry.reorderable,\n resizable: entry.resizable,\n sortable,\n groupable,\n });\n\n return (\n <th\n key={entry.id}\n scope=\"col\"\n // Explicit, matching `GridRow.tsx`'s `role=\"gridcell\"` on the\n // body `<td>`: both sit inside a `<table role=\"grid\">`, and\n // mixing that non-native ancestor role with descendants that\n // rely on implicit native role mapping is inconsistently\n // resolved across browser/AT combinations.\n role=\"columnheader\"\n data-gridkit-column={entry.id}\n aria-colindex={index + 1}\n tabIndex={nav.tabIndexFor(HEADER_ROW, index)}\n {...ariaAttr(\n selection.columnMode !== false,\n \"aria-selected\",\n selected,\n )}\n onFocus={() => {\n nav.focusCell(HEADER_ROW, index);\n }}\n onClick={(event) => {\n /*\n * A drag ends in a click on the header it started from, and a\n * resize in one on the handle inside it. Neither is the press\n * that selects a column, so both are shown the door here —\n * the drag by the distance it travelled, the resize by where\n * it began.\n */\n if (drag.justDragged()) {\n return;\n }\n if (\n event.target instanceof Element &&\n (event.target.closest(\".header-resize-handle\") !== null ||\n event.target.closest(\".header-sort-toggle\") !== null ||\n event.target.closest(\".header-group-toggle\") !== null)\n ) {\n return;\n }\n selection.selectColumn(entry.id, intentOf(event));\n }}\n onKeyDown={(event) => {\n const horizontal =\n event.key === \"ArrowLeft\" || event.key === \"ArrowRight\";\n const direction = event.key === \"ArrowLeft\" ? -1 : 1;\n\n if (horizontal && event.ctrlKey && entry.reorderable) {\n event.preventDefault();\n drag.moveByKeyboard(entry, direction);\n return;\n }\n if (horizontal && event.altKey && entry.resizable) {\n event.preventDefault();\n resize.nudge(entry, direction * KEYBOARD_STEP);\n return;\n }\n // The keyboard equivalent of double-clicking the resize\n // handle, which auto-fits the column to its content.\n if (event.key === \"Enter\" && event.altKey && entry.resizable) {\n event.preventDefault();\n resize.sizeToContent(entry);\n return;\n }\n if (event.key === \"ArrowUp\" && event.altKey && sortable) {\n event.preventDefault();\n sort.toggle(entry, { shiftKey: event.shiftKey });\n return;\n }\n if (event.key === \"ArrowDown\" && event.altKey && groupable) {\n event.preventDefault();\n grouping.toggleGroupBy(entry.id);\n return;\n }\n // Space builds a selection up and Enter replaces it, as in the\n // body. Taken either way, or Space scrolls the grid away.\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n selection.selectColumn(\n entry.id,\n intentOf(keyboardSelectIntent(event)),\n );\n return;\n }\n nav.onKeyDown(event);\n }}\n className={classNames(\n \"header-cell\",\n // The grab affordance a header showing either drag\n // destination shares — a column dragged only for grouping\n // (`groupByDraggable` without `reorderable`) grabs the same\n // way one dragged only for reordering does.\n entry.reorderable || entry.groupByDraggable\n ? \"is-reorderable\"\n : \"\",\n selected ? \"is-selected\" : \"\",\n resizing ? \"is-resizing\" : \"\",\n dragging ? \"is-dragging\" : \"\",\n dropBefore ? \"is-drop-before\" : \"\",\n dropAfter ? \"is-drop-after\" : \"\",\n column.wrap?.header ? \"is-wrapped\" : \"\",\n column.headerClassName ?? \"\",\n )}\n {...ariaAttr(shortcuts !== \"\", \"aria-keyshortcuts\", shortcuts)}\n {...ariaAttr<\"aria-sort\", \"ascending\" | \"descending\">(\n sortable && sortDirection !== null,\n \"aria-sort\",\n sortDirection === \"asc\" ? \"ascending\" : \"descending\",\n )}\n {...((entry.reorderable || entry.groupByDraggable) && {\n onPointerDown: (event) => {\n drag.startDrag(entry, event);\n },\n })}\n >\n {groupable && showGroupToggleIcon && (\n /*\n * Inline, before the label, rather than absolutely\n * positioned like the sort toggle and resize handle: those\n * two already share the header's right edge, and a third\n * overlay there would need its own carve-out. Sitting in\n * normal flow costs nothing but a few pixels of label width.\n * A pointer affordance only, same as the other two — the\n * keyboard equivalent is Alt+ArrowDown on the header itself.\n */\n <span\n className={classNames(\n \"header-group-toggle\",\n isGrouped ? \"is-grouped\" : \"\",\n )}\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n // See the sort toggle's own note: otherwise a\n // reorderable header's drag would swallow this click.\n event.stopPropagation();\n }}\n onClick={(event) => {\n event.stopPropagation();\n grouping.toggleGroupBy(entry.id);\n }}\n >\n <GroupIcon />\n </span>\n )}\n {entry.label}\n {sortable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology like the resize handle: the keyboard equivalent\n * lives on the header itself, under Alt+ArrowUp (plain) /\n * Alt+Shift+ArrowUp (stacking).\n */\n <span\n className={classNames(\n \"header-sort-toggle\",\n sortDirection !== null ? `is-sorted-${sortDirection}` : \"\",\n )}\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n /*\n * Otherwise a reorderable header's own `onPointerDown`\n * sees this bubble up and starts a column drag, whose\n * `setPointerCapture` then redirects the click that\n * follows to the `th` — the same reason `startResize`\n * stops it for the resize handle.\n */\n event.stopPropagation();\n }}\n onClick={(event) => {\n sort.toggle(entry, { shiftKey: event.shiftKey });\n }}\n >\n {sortDirection === null ? (\n <ChevronsUpDownIcon />\n ) : (\n <ChevronUpIcon />\n )}\n {sortPriority !== null && sortPriority > 1 && (\n <span className=\"header-sort-priority\">{sortPriority}</span>\n )}\n </span>\n )}\n {entry.resizable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology accordingly: a focusable handle per column would\n * put N tab stops inside a widget that is meant to have one.\n * The keyboard resizes from the header itself, under Alt.\n */\n <span\n className=\"header-resize-handle\"\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n resize.startResize(entry, event);\n }}\n onDoubleClick={() => {\n resize.sizeToContent(entry);\n }}\n />\n )}\n </th>\n );\n })}\n </tr>\n {/*\n * Portalled to the body, and not only because a `div` cannot sit in a\n * `tr`: inside the viewport the overflow that makes the grid scroll\n * would clip it.\n */}\n {draggedEntry !== null &&\n drag.ghostTransform !== null &&\n createPortal(\n <div\n className=\"gridkit-data-grid header-cell drag-ghost\"\n style={{\n width: draggedEntry.width,\n transform: drag.ghostTransform,\n }}\n aria-hidden=\"true\"\n >\n {draggedEntry.label}\n </div>,\n document.body,\n )}\n </thead>\n );\n}\n","/**\n * Collapses the `{...(condition && { \"aria-foo\": value })}` idiom for\n * conditionally including a single ARIA attribute in a JSX spread.\n */\nexport function ariaAttr<K extends string, V>(\n condition: boolean,\n key: K,\n value: V,\n): Record<K, V> | Record<string, never> {\n return condition ? ({ [key]: value } as Record<K, V>) : {};\n}\n","export function classNames(\n ...values: (string | false | null | undefined)[]\n): string {\n return values.filter(Boolean).join(\" \");\n}\n","import {\n useEffect,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\nimport {\n clampFocus,\n nextFocusForKey,\n HEADER_ROW,\n type GridFocus,\n} from \"@gridkitjs/core\";\n\nexport { HEADER_ROW, type GridFocus };\n\n/** Rows a page key moves when the viewport cannot be measured. */\nconst FALLBACK_PAGE = 10;\n\ninterface UseGridNavigationOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n rowCount: number;\n columnCount: number;\n}\n\nexport interface GridNavigationApi {\n focus: GridFocus;\n /**\n * `0` for the focused cell and `-1` for every other. A grid is one tab stop:\n * tabbing reaches it, and the arrow keys move within it.\n */\n tabIndexFor: (rowIndex: number, columnIndex: number) => 0 | -1;\n /** Moves the tab stop, and the browser's focus with it. */\n focusCell: (rowIndex: number, columnIndex: number) => void;\n /** Handles the navigation keys, leaving every other key to bubble. */\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n}\n\n/**\n * `0` for the column holding the tab stop and `-1` for every other.\n * Standalone rather than reached only through the hook's own `tabIndexFor`,\n * because `GridRow` is `memo()`-wrapped and cannot take the whole `nav`\n * object as a prop without defeating that boundary. Takes the row's own\n * already-narrowed `focusedColumnIndex` (`null` when focus sits on a\n * different row) rather than a `rowIndex`/`GridFocus` pair, since that\n * narrowing — done once per row in `GridBody` — is what keeps a focus move\n * from re-rendering every row instead of the two it actually touches.\n */\nexport function tabIndexFor(\n columnIndex: number,\n focusedColumnIndex: number | null,\n): 0 | -1 {\n return columnIndex === focusedColumnIndex ? 0 : -1;\n}\n\n/**\n * The cell at a coordinate, found through the table's own row and cell\n * collections rather than a selector.\n *\n * Ids can hold anything a consumer's data holds, and an attribute selector\n * built from one would have to escape it; positions need no quoting.\n *\n * `columnIndex` is clamped to the row's own last cell rather than read\n * directly: a group-header row renders one `<td colSpan>` regardless of\n * `columnCount`, so a focus arriving from a data row further right (or a\n * `columnIndex` a keyboard `End` left behind) would otherwise address a cell\n * that row doesn't have.\n */\nfunction cellAt(table: HTMLTableElement, focus: GridFocus): HTMLElement | null {\n const row =\n focus.rowIndex === HEADER_ROW\n ? (table.tHead?.rows[0] ?? null)\n : (table.tBodies[0]?.rows[focus.rowIndex] ?? null);\n if (row === null) {\n return null;\n }\n const columnIndex = Math.min(focus.columnIndex, row.cells.length - 1);\n return row.cells[columnIndex] ?? null;\n}\n\n/**\n * Moves one tab stop around the grid, which is what `role=\"grid\"` obliges:\n * arrow keys travel cell to cell and Tab passes the whole grid by.\n *\n * Separate from selection because focus and selection are different states — a\n * cell is focused while travelling before anything is selected, and every cell\n * of a range is selected without being focused. Navigation also has to work\n * with selection turned off entirely, so it cannot depend on it.\n */\nexport default function useGridNavigation({\n tableRef,\n rowCount,\n columnCount,\n}: UseGridNavigationOptions): GridNavigationApi {\n const [stored, setStored] = useState<GridFocus>({\n rowIndex: HEADER_ROW,\n columnIndex: 0,\n });\n\n /**\n * Clamped on the way out rather than written back, so that a coordinate\n * pushed out of range by a change to the data is restored when the data\n * comes back — and so the effect below cannot chase its own output.\n */\n const focus = clampFocus(stored, rowCount, columnCount);\n\n /**\n * Whether the browser's focus still has to be moved to match. Without it\n * every render would pull focus into the grid, including the first.\n */\n const pending = useRef(false);\n\n useEffect(() => {\n if (!pending.current) {\n return;\n }\n pending.current = false;\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n cellAt(table, { rowIndex: focus.rowIndex, columnIndex: focus.columnIndex })\n // Focusing the cell the browser already sits on is a no-op, which is what\n // makes one method serve both a key press and a cell reporting a click.\n ?.focus();\n }, [tableRef, focus.rowIndex, focus.columnIndex]);\n\n /** How many rows fit the viewport, which is what a page key should move. */\n function pageSize(): number {\n const table = tableRef.current;\n const firstRow = table?.tBodies[0]?.rows[0];\n const viewport = table?.parentElement;\n if (\n firstRow === undefined ||\n viewport === null ||\n viewport === undefined ||\n firstRow.offsetHeight === 0\n ) {\n return FALLBACK_PAGE;\n }\n return Math.max(\n 1,\n Math.floor(viewport.clientHeight / firstRow.offsetHeight),\n );\n }\n\n function focusCell(rowIndex: number, columnIndex: number): void {\n const next = clampFocus({ rowIndex, columnIndex }, rowCount, columnCount);\n if (\n next.rowIndex === focus.rowIndex &&\n next.columnIndex === focus.columnIndex\n ) {\n return;\n }\n pending.current = true;\n setStored(next);\n }\n\n function onKeyDown(event: ReactKeyboardEvent<HTMLElement>): void {\n const next = nextFocusForKey(\n event.key,\n {\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n altKey: event.altKey,\n shiftKey: event.shiftKey,\n },\n focus,\n rowCount,\n columnCount,\n pageSize(),\n );\n if (next === null) {\n return;\n }\n\n // Taken even when the move lands nowhere: an arrow at the last row would\n // otherwise scroll the page out from under the grid.\n event.preventDefault();\n focusCell(next.rowIndex, next.columnIndex);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the focus they move from.\n return {\n focus,\n tabIndexFor: (rowIndex, columnIndex) =>\n tabIndexFor(\n columnIndex,\n rowIndex === focus.rowIndex ? focus.columnIndex : null,\n ),\n focusCell,\n onKeyDown,\n };\n}\n","import {\n useMemo,\n useRef,\n type Dispatch,\n type KeyboardEvent as ReactKeyboardEvent,\n type SetStateAction,\n} from \"react\";\nimport {\n applySelectionIntent,\n clearSelection,\n diffSelection,\n resolveCell,\n resolveColumns,\n resolveRows,\n selectAll,\n selectCell,\n toggleCellSelection,\n type CellSelectionMode,\n type CellSelectionState,\n type ResolvedRow,\n type SelectableConfig,\n type SelectedCellRef,\n type SelectIntent,\n type SelectionMode,\n type SelectionState,\n type RowSelectEvent,\n type RowSelectionChangeEvent,\n type RowsSelectEvent,\n} from \"@gridkitjs/core\";\nimport type {\n CellSelectEvent,\n CellSelectionChangeEvent,\n ColumnSelectEvent,\n ColumnSelectionChangeEvent,\n ColumnsSelectEvent,\n ResolvedColumn,\n} from \"./DataGrid\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\n/**\n * The modifiers a Space or Enter keydown carries, for a caller that means to\n * hand them to `intentOf` as a click's modifiers would be. Space builds a\n * selection up and Enter replaces it, as in the body — so Space is mapped to\n * act like Ctrl, matching Ctrl-click and the plain click they stand in for.\n */\nexport function keyboardSelectIntent(event: ReactKeyboardEvent): {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n} {\n return {\n ctrlKey: event.key === \" \" || event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n };\n}\n\n/**\n * Reported as the user selects. Every one of these is fanned out from a single\n * diff of the transition it describes, so no two can disagree about what one\n * interaction did.\n */\nexport interface SelectionCallbacks<Row> {\n /** Called once per row newly selected. The last call names the last row. */\n onRowSelect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n /** Called once with every row one interaction selected. */\n onRowsSelect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n onRowDeselect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n onRowsDeselect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n /**\n * Called once per change with what it added, what it removed and everything\n * selected after it — the one to persist from.\n */\n onRowSelectionChange?:\n ((event: RowSelectionChangeEvent<Row>) => void) | undefined;\n onColumnSelect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsSelect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnDeselect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsDeselect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnSelectionChange?:\n ((event: ColumnSelectionChangeEvent<Row>) => void) | undefined;\n onCellSelect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellDeselect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellSelectionChange?:\n ((event: CellSelectionChangeEvent<Row>) => void) | undefined;\n}\n\ninterface UseGridSelectionOptions<Row> {\n rows: readonly ResolvedRow<Row>[];\n columns: readonly ResolvedColumn<Row>[];\n selectable: SelectableConfig | undefined;\n rowSelection: SelectionState;\n setRowSelection: Dispatch<SetStateAction<SelectionState>>;\n columnSelection: SelectionState;\n setColumnSelection: Dispatch<SetStateAction<SelectionState>>;\n cellSelection: CellSelectionState;\n setCellSelection: Dispatch<SetStateAction<CellSelectionState>>;\n callbacks: SelectionCallbacks<Row>;\n announce: (message: string) => void;\n /** What a column is called in an announcement — see `DataGrid.tsx`. */\n columnName: (columnId: string) => string;\n}\n\nexport interface GridSelectionApi {\n rowMode: SelectionMode;\n columnMode: SelectionMode;\n cellMode: CellSelectionMode;\n /**\n * Lookups for the render pass. The state itself stays an ordered list, which\n * is what makes the most recent selection its last entry.\n */\n selectedRowIds: ReadonlySet<string>;\n selectedColumnIds: ReadonlySet<string>;\n selectedCell: CellSelectionState;\n selectRow: (rowId: string, intent: SelectIntent) => void;\n selectColumn: (columnId: string, intent: SelectIntent) => void;\n selectCell: (cell: SelectedCellRef, intent: SelectIntent) => void;\n selectAllRows: () => void;\n /** Lets go of every selection at once, as Escape does. */\n clear: () => void;\n}\n\nfunction countMessage(count: number, noun: string): string {\n if (count === 0) {\n return `No ${noun}s selected`;\n }\n return count === 1\n ? `1 ${noun} selected`\n : `${String(count)} ${noun}s selected`;\n}\n\n/** A `Set` re-derived only when `values` changes. */\nfunction useAsSet<T>(values: readonly T[]): ReadonlySet<T> {\n return useMemo(() => new Set(values), [values]);\n}\n\n/**\n * A `Map` keying `values` by their `key` property, re-derived only when\n * `values` changes. Takes the key as a property name rather than an\n * extractor function so that it stays a stable dependency across\n * renders — an inline extractor handed in fresh each render would otherwise\n * force a recompute on every render regardless of whether `values` changed.\n */\nfunction useIndexedBy<T, K extends keyof T>(\n values: readonly T[],\n key: K,\n): ReadonlyMap<T[K], T> {\n return useMemo(\n () => new Map(values.map((value) => [value[key], value])),\n [values, key],\n );\n}\n\n/** `values.map((value) => value[key])`, re-derived only when `values` changes. */\nfunction useMappedArray<T, K extends keyof T>(\n values: readonly T[],\n key: K,\n): readonly T[K][] {\n return useMemo(() => values.map((value) => value[key]), [values, key]);\n}\n\n/**\n * Turns an intent against a row, column or cell into the selection it implies,\n * and reports what changed.\n *\n * Holds no state of its own: the three selections live in `DataGrid` beside\n * the sizing and the order, so that a ref exposing them later, or a feature\n * reading them, finds them in one place.\n */\nexport default function useGridSelection<Row>({\n rows,\n columns,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n columnName,\n}: UseGridSelectionOptions<Row>): GridSelectionApi {\n const rowMode = selectable?.rows ?? false;\n const columnMode = selectable?.columns ?? false;\n const cellMode = selectable?.cells ?? false;\n\n const rowsById = useIndexedBy(rows, \"rowId\");\n const rowIds = useMappedArray(rows, \"rowId\");\n const columnIds = useMappedArray(columns, \"id\");\n\n const selectedRowIds = useAsSet(rowSelection);\n const selectedColumnIds = useAsSet(columnSelection);\n\n /**\n * Where a range is measured from: the last row or column selected by\n * anything but a range, so that repeated Shift-clicks re-draw one span\n * instead of walking the anchor along with them.\n */\n const rowAnchor = useRef<string | null>(null);\n const columnAnchor = useRef<string | null>(null);\n\n /**\n * Announced only for a change touching more than one member. A single\n * selection is already carried by the focused row's own `aria-selected`, and\n * repeating it here would talk over that.\n */\n function announceCount(changed: number, total: number, noun: string): void {\n if (changed > 1) {\n announce(countMessage(total, noun));\n }\n }\n\n function commitRows(next: SelectionState): void {\n // The unchanged-reference contract the core transforms keep: a click that\n // selects what was already selected neither renders nor reports.\n commitIfChanged(rowSelection, next, setRowSelection, (committed) => {\n const { added, removed } = diffSelection(rowSelection, committed);\n const addedRows = resolveRows(rowsById, added);\n const removedRows = resolveRows(rowsById, removed);\n\n for (const row of addedRows) {\n callbacks.onRowSelect?.({ row, selection: committed });\n }\n if (addedRows.length > 0) {\n callbacks.onRowsSelect?.({ rows: addedRows, selection: committed });\n }\n for (const row of removedRows) {\n callbacks.onRowDeselect?.({ row, selection: committed });\n }\n if (removedRows.length > 0) {\n callbacks.onRowsDeselect?.({ rows: removedRows, selection: committed });\n }\n callbacks.onRowSelectionChange?.({\n added: addedRows,\n removed: removedRows,\n selected: resolveRows(rowsById, committed),\n selection: committed,\n });\n announceCount(added.length + removed.length, committed.length, \"row\");\n });\n }\n\n function commitColumns(next: SelectionState): void {\n commitIfChanged(columnSelection, next, setColumnSelection, (committed) => {\n const { added, removed } = diffSelection(columnSelection, committed);\n const addedColumns = resolveColumns(columns, added);\n const removedColumns = resolveColumns(columns, removed);\n\n for (const column of addedColumns) {\n callbacks.onColumnSelect?.({ column, selection: committed });\n }\n if (addedColumns.length > 0) {\n callbacks.onColumnsSelect?.({\n columns: addedColumns,\n selection: committed,\n });\n }\n for (const column of removedColumns) {\n callbacks.onColumnDeselect?.({ column, selection: committed });\n }\n if (removedColumns.length > 0) {\n callbacks.onColumnsDeselect?.({\n columns: removedColumns,\n selection: committed,\n });\n }\n callbacks.onColumnSelectionChange?.({\n added: addedColumns,\n removed: removedColumns,\n selected: resolveColumns(columns, committed),\n selection: committed,\n });\n announceCount(added.length + removed.length, committed.length, \"column\");\n });\n }\n\n function commitCell(next: CellSelectionState): void {\n commitIfChanged(cellSelection, next, setCellSelection, (committed) => {\n // Resolved before and after in one place, so that moving between two\n // cells reports the leaving and the arriving as one change.\n const selected = resolveCell(rowsById, columns, committed);\n const deselected = resolveCell(rowsById, columns, cellSelection);\n\n if (deselected !== null) {\n callbacks.onCellDeselect?.({ cell: deselected, selection: committed });\n }\n if (selected !== null) {\n callbacks.onCellSelect?.({ cell: selected, selection: committed });\n }\n callbacks.onCellSelectionChange?.({\n selected,\n deselected,\n selection: committed,\n });\n // Unlike rows and columns, a cell selection is always exactly one cell\n // — there is no multi-cell range — so it never crosses\n // `announceCount`'s >1 threshold and the focused cell's own\n // `aria-selected` is the only feedback a screen-reader user would\n // otherwise get. Announced unconditionally here instead, on every\n // commit that lands on a cell.\n if (selected !== null) {\n announce(\n `${columnName(selected.columnId)}, row ${String(selected.rowIndex + 1)}, selected`,\n );\n }\n });\n }\n\n function selectRow(rowId: string, intent: SelectIntent): void {\n const next = applySelectionIntent(\n rowSelection,\n rowIds,\n rowAnchor.current,\n rowId,\n intent,\n rowMode,\n );\n if (intent !== \"range\") {\n rowAnchor.current = rowId;\n }\n commitRows(next);\n }\n\n function selectColumn(columnId: string, intent: SelectIntent): void {\n const next = applySelectionIntent(\n columnSelection,\n columnIds,\n columnAnchor.current,\n columnId,\n intent,\n columnMode,\n );\n if (intent !== \"range\") {\n columnAnchor.current = columnId;\n }\n commitColumns(next);\n }\n\n function selectCellAt(cell: SelectedCellRef, intent: SelectIntent): void {\n // A cell holds one value, so a range over cells has nothing to span and\n // reads as the plain click it looks like.\n commitCell(\n intent === \"toggle\"\n ? toggleCellSelection(cellSelection, cell, cellMode)\n : selectCell(cellSelection, cell, cellMode),\n );\n }\n\n function selectAllRows(): void {\n commitRows(selectAll(rowSelection, rowIds, rowMode));\n }\n\n function clear(): void {\n commitRows(clearSelection(rowSelection));\n commitColumns(clearSelection(columnSelection));\n commitCell(null);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the selections they transform.\n return {\n rowMode,\n columnMode,\n cellMode,\n selectedRowIds,\n selectedColumnIds,\n selectedCell: cellSelection,\n selectRow,\n selectColumn,\n selectCell: selectCellAt,\n selectAllRows,\n clear,\n };\n}\n","/**\n * The shape behind a click or keypress that changes sort, resize, or\n * selection state: compute the next value, bail out if it's reference-equal\n * to the current one, persist it, then report it. Returns whether it\n * actually committed, for a caller with more to do only when it did.\n */\nexport function commitIfChanged<T>(\n current: T,\n next: T,\n setState: (value: T) => void,\n onCommit?: (next: T) => void,\n): boolean {\n if (next === current) {\n return false;\n }\n setState(next);\n onCommit?.(next);\n return true;\n}\n","import { useMemo } from \"react\";\nimport { groupRowId, intentOf, type DisplayRow } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { GridNavigationApi } from \"../useGridNavigation\";\nimport type { RowGroupingApi } from \"../useRowGrouping\";\nimport {\n keyboardSelectIntent,\n type GridSelectionApi,\n} from \"../useGridSelection\";\nimport GridGroupRow from \"./GridGroupRow\";\nimport GridRow from \"./GridRow\";\n\ninterface GridBodyProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rows: readonly DisplayRow<Row>[];\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n grouping: RowGroupingApi<Row>;\n}\n\n/** Where a cell sits, read off the table's own indices rather than an attribute. */\ninterface CellPosition {\n rowIndex: number;\n columnIndex: number;\n columnId: string;\n}\n\n/**\n * The cell an event happened in. `closest` is what makes the whole cell the\n * target: a click on a template's own markup resolves to the cell holding it.\n *\n * Never matches inside a group-header row: that row's single `<td>` carries\n * no `data-gridkit-column` (it spans every column at once, so no one column\n * id applies), which is what keeps this function — and everything built on\n * it — data-row-only without an explicit `\"kind\"` check of its own.\n */\nfunction cellFrom(target: EventTarget): CellPosition | null {\n if (!(target instanceof Element)) {\n return null;\n }\n const cell = target.closest(\"td[data-gridkit-column]\");\n const row = cell?.parentElement;\n const columnId = cell?.getAttribute(\"data-gridkit-column\");\n if (\n !(cell instanceof HTMLTableCellElement) ||\n !(row instanceof HTMLTableRowElement) ||\n columnId === null ||\n columnId === undefined\n ) {\n return null;\n }\n return {\n rowIndex: row.sectionRowIndex,\n columnIndex: cell.cellIndex,\n columnId,\n };\n}\n\n/** The group-header row an event happened in, if any. */\nfunction groupRowFrom(\n target: EventTarget,\n): { rowIndex: number; groupId: string } | null {\n if (!(target instanceof Element)) {\n return null;\n }\n const row = target.closest(\"tr[data-gridkit-group]\");\n const groupId = row?.getAttribute(\"data-gridkit-group\");\n if (\n !(row instanceof HTMLTableRowElement) ||\n groupId === null ||\n groupId === undefined\n ) {\n return null;\n }\n return { rowIndex: row.sectionRowIndex, groupId };\n}\n\ninterface GroupAriaMeta {\n posinset: number;\n setsize: number;\n}\n\n/**\n * `aria-posinset`/`aria-setsize` per group header: its 1-based position\n * among, and count of, the group headers sharing its level and immediate\n * parent. Depth-first order (see `groupRows`) keeps siblings contiguous, so\n * one pass tallies each parent's total and a second assigns each header's\n * position within it.\n */\nfunction groupAriaMeta<Row>(\n rows: readonly DisplayRow<Row>[],\n): ReadonlyMap<string, GroupAriaMeta> {\n const totals = new Map<string, number>();\n for (const entry of rows) {\n if (!(\"kind\" in entry)) continue;\n const parentKey = groupRowId(entry.path.slice(0, -1));\n totals.set(parentKey, (totals.get(parentKey) ?? 0) + 1);\n }\n\n const seen = new Map<string, number>();\n const meta = new Map<string, GroupAriaMeta>();\n for (const entry of rows) {\n if (!(\"kind\" in entry)) continue;\n const parentKey = groupRowId(entry.path.slice(0, -1));\n const posinset = (seen.get(parentKey) ?? 0) + 1;\n seen.set(parentKey, posinset);\n meta.set(entry.groupId, {\n posinset,\n setsize: totals.get(parentKey) ?? posinset,\n });\n }\n return meta;\n}\n\n/**\n * Events are delegated to the body rather than bound per cell, which is what\n * lets `GridRow` be memoised: a handler rebuilt each render is a prop that\n * changes each render, and one reaching every row would defeat the boundary\n * entirely.\n */\nexport default function GridBody<Row>({\n columns,\n rows,\n activeColumnId,\n nav,\n selection,\n grouping,\n}: GridBodyProps<Row>) {\n const { selectedCell, rowMode, cellMode } = selection;\n const ariaMeta = useMemo(() => groupAriaMeta(rows), [rows]);\n\n /** The row and cell an event addresses, resolved once for every handler. */\n function targetOf(\n target: EventTarget,\n ): { position: CellPosition; rowId: string } | null {\n const position = cellFrom(target);\n const entry = position === null ? undefined : rows[position.rowIndex];\n if (position === null || entry === undefined || \"kind\" in entry) {\n return null;\n }\n return { position, rowId: entry.rowId };\n }\n\n function select(\n rowId: string,\n columnId: string,\n modifiers: { ctrlKey: boolean; metaKey: boolean; shiftKey: boolean },\n ): void {\n const intent = intentOf(modifiers);\n // Independent of each other: selecting a cell says nothing about its row,\n // so a grid with both on reports both.\n if (rowMode !== false) {\n selection.selectRow(rowId, intent);\n }\n if (cellMode !== false) {\n selection.selectCell({ rowId, columnId }, intent);\n }\n }\n\n return (\n <tbody\n className=\"grid-body\"\n onFocus={(event) => {\n const group = groupRowFrom(event.target);\n if (group !== null) {\n // One cell for the whole row — see the note on `focused` below.\n nav.focusCell(group.rowIndex, 0);\n return;\n }\n const found = targetOf(event.target);\n if (found === null) return;\n nav.focusCell(found.position.rowIndex, found.position.columnIndex);\n }}\n onClick={(event) => {\n const group = groupRowFrom(event.target);\n if (group !== null) {\n grouping.toggleExpansion(group.groupId);\n return;\n }\n const found = targetOf(event.target);\n if (found === null) return;\n select(found.rowId, found.position.columnId, event);\n }}\n onKeyDown={(event) => {\n const group = groupRowFrom(event.target);\n if (group !== null) {\n // One cell spans every column, so there is nothing to move within —\n // left/right stay a no-op rather than silently moving `nav`'s\n // stored column index off of a cell this row doesn't have.\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n event.preventDefault();\n return;\n }\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n grouping.toggleExpansion(group.groupId);\n return;\n }\n nav.onKeyDown(event);\n return;\n }\n\n // Space builds a selection up and Enter replaces it, matching the\n // Ctrl-click and the plain click they stand in for.\n if (event.key === \" \" || event.key === \"Enter\") {\n const found = targetOf(event.target);\n if (found === null) return;\n // Taken whether or not anything is selectable: Space would otherwise\n // scroll the grid out from under the focused cell.\n event.preventDefault();\n select(\n found.rowId,\n found.position.columnId,\n keyboardSelectIntent(event),\n );\n return;\n }\n nav.onKeyDown(event);\n }}\n >\n {rows.map((entry) =>\n \"kind\" in entry ? (\n <GridGroupRow\n key={entry.groupId}\n columnCount={columns.length}\n groupId={entry.groupId}\n level={entry.level}\n columnLabel={\n columns.find((column) => column.id === entry.columnId)?.label ??\n entry.columnId\n }\n value={entry.value}\n expanded={entry.expanded}\n count={entry.count}\n rowIndex={entry.rowIndex}\n posinset={ariaMeta.get(entry.groupId)?.posinset ?? 1}\n setsize={ariaMeta.get(entry.groupId)?.setsize ?? 1}\n // Ignores `nav.focus.columnIndex`: with only one cell in this\n // row, whether it holds the tab stop depends on `rowIndex`\n // alone.\n focused={nav.focus.rowIndex === entry.rowIndex}\n />\n ) : (\n <GridRow<Row>\n key={entry.rowId}\n columns={columns}\n rowId={entry.rowId}\n row={entry.row}\n rowIndex={entry.rowIndex}\n activeColumnId={activeColumnId}\n selectedColumnIds={selection.selectedColumnIds}\n selected={selection.selectedRowIds.has(entry.rowId)}\n /*\n * Narrowed to this row before it crosses the boundary, so that\n * moving the selected cell re-renders the two rows it moved\n * between rather than all of them.\n */\n selectedColumnId={\n selectedCell?.rowId === entry.rowId ? selectedCell.columnId : null\n }\n focusedColumnIndex={\n nav.focus.rowIndex === entry.rowIndex\n ? nav.focus.columnIndex\n : null\n }\n rowsSelectable={rowMode !== false}\n cellsSelectable={cellMode !== false}\n />\n ),\n )}\n </tbody>\n );\n}\n","import { memo, type ReactNode } from \"react\";\nimport { classNames } from \"../classNames\";\n\ninterface GridGroupRowProps {\n /** How many columns this group's header spans, matching the grid's own count. */\n columnCount: number;\n groupId: string;\n /** Nesting depth, 0 for a top-level group — indents the header and feeds `aria-level`. */\n level: number;\n /** The grouped column's own label, whatever its `headerTemplate` returns. */\n columnLabel: ReactNode;\n /** This group's own value — the last entry of its `path`. */\n value: unknown;\n expanded: boolean;\n /** Leaf row count under this group, regardless of collapse state. */\n count: number;\n /** Position among the display rows as rendered, matching `ResolvedGroupRow.rowIndex`. */\n rowIndex: number;\n /** This group's 1-based position among its own siblings, for `aria-posinset`. */\n posinset: number;\n /** How many siblings this group has, for `aria-setsize`. */\n setsize: number;\n /** Whether this row currently holds the grid's single tab stop. */\n focused: boolean;\n}\n\n/**\n * How a group's own value renders in its header — blank rather than the\n * literal word \"null\"/\"undefined\", and never `Object`'s own\n * `[object Object]` for a value `String()` can't stringify meaningfully.\n */\nfunction formatGroupValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"(blank)\";\n }\n if (value instanceof Date) {\n return value.toLocaleString();\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return String(value);\n case \"function\":\n return \"(function)\";\n default:\n // Arrays, and anything else a grouped column's value could still be.\n return JSON.stringify(value);\n }\n}\n\nfunction GridGroupRowComponent({\n columnCount,\n groupId,\n level,\n columnLabel,\n value,\n expanded,\n count,\n rowIndex,\n posinset,\n setsize,\n focused,\n}: GridGroupRowProps) {\n return (\n <tr\n role=\"row\"\n // Two past the index: rows are counted from one, and the header is the\n // first of them — the same convention `GridRow` uses.\n aria-rowindex={rowIndex + 2}\n // 1-based, per the WAI-ARIA treegrid pattern.\n aria-level={level + 1}\n aria-expanded={expanded}\n aria-setsize={setsize}\n aria-posinset={posinset}\n data-gridkit-group={groupId}\n className={classNames(\n \"grid-group-row\",\n `is-group-level-${String(level)}`,\n )}\n >\n <td\n role=\"gridcell\"\n colSpan={columnCount}\n tabIndex={focused ? 0 : -1}\n aria-keyshortcuts=\"Space Enter\"\n className=\"grid-group-cell\"\n >\n {/*\n * The flex layout lives on this inner `div`, not the `<td>` itself:\n * a `display` other than `table-cell` on the cell element changes\n * its box type entirely, and the browser fixes that up by wrapping\n * it in an anonymous table-cell — which throws off the cell's own\n * hit-testing (a click landing where the row's bounding box says\n * the cell is can miss it and hit the table underneath instead).\n */}\n <div\n className=\"grid-group-cell-content\"\n style={{ paddingInlineStart: `${String(level * 1.25 + 0.5)}rem` }}\n >\n <span\n className={classNames(\n \"group-toggle\",\n expanded ? \"is-expanded\" : \"is-collapsed\",\n )}\n aria-hidden=\"true\"\n />\n <span className=\"group-label\">\n {columnLabel}: {formatGroupValue(value)}\n </span>\n <span className=\"group-count\">({count})</span>\n </div>\n </td>\n </tr>\n );\n}\n\n/**\n * `memo()`-wrapped for the same reason `GridRow` is: every prop here is a\n * scalar or an already-narrowed value, and no handler reaches this component\n * directly — `GridBody` delegates group-header clicks and keydowns the same\n * way it does for data rows.\n */\nconst GridGroupRow = memo(GridGroupRowComponent);\n\nexport default GridGroupRow;\n","import { accessDotted } from \"@gridkitjs/core\";\nimport { memo, type ReactNode } from \"react\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { ariaAttr } from \"../ariaAttr\";\nimport { classNames } from \"../classNames\";\nimport { tabIndexFor } from \"../useGridNavigation\";\n\ninterface GridRowProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rowId: string;\n row: Row;\n rowIndex: number;\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n selectedColumnIds: ReadonlySet<string>;\n selected: boolean;\n /** Which of this row's cells is the selected one, if any. */\n selectedColumnId: string | null;\n /** Which of this row's cells holds the grid's tab stop, if any. */\n focusedColumnIndex: number | null;\n rowsSelectable: boolean;\n cellsSelectable: boolean;\n}\n\nfunction GridRowComponent<Row>({\n columns,\n rowId,\n row,\n rowIndex,\n activeColumnId,\n selectedColumnIds,\n selected,\n selectedColumnId,\n focusedColumnIndex,\n rowsSelectable,\n cellsSelectable,\n}: GridRowProps<Row>) {\n return (\n <tr\n role=\"row\"\n // Two past the index: rows are counted from one, and the header is the\n // first of them.\n aria-rowindex={rowIndex + 2}\n // Omitted rather than `false` when rows cannot be selected, which would\n // otherwise have every row announce that it is not.\n {...ariaAttr(rowsSelectable, \"aria-selected\", selected)}\n className={classNames(\"grid-row\", selected ? \"is-selected\" : \"\")}\n >\n {columns.map(({ id, column, alignment }, columnIndex) => {\n // Resolved either way, so a template that only formats the value never\n // has to walk the field path a second time.\n const value = accessDotted(row, column.field);\n const cellSelected = id === selectedColumnId;\n\n return (\n <td\n key={id}\n role=\"gridcell\"\n data-gridkit-column={id}\n aria-colindex={columnIndex + 1}\n tabIndex={tabIndexFor(columnIndex, focusedColumnIndex)}\n {...ariaAttr(cellsSelectable, \"aria-selected\", cellSelected)}\n {...ariaAttr(cellsSelectable, \"aria-keyshortcuts\", \"Space Enter\")}\n className={classNames(\n \"grid-cell\",\n id === activeColumnId ? \"is-resizing\" : \"\",\n cellSelected || selectedColumnIds.has(id) ? \"is-selected\" : \"\",\n column.wrap?.cells ? \"is-wrapped\" : \"\",\n column.cellClassName ?? \"\",\n )}\n style={{ textAlign: alignment }}\n >\n {column.cellTemplate\n ? column.cellTemplate({ value, row, rowIndex, rowId, selected })\n : (value as ReactNode)}\n </td>\n );\n })}\n </tr>\n );\n}\n\n/**\n * Selection lives at the top of the grid, so any change to it re-renders the\n * whole body — without this boundary a click would rebuild every cell of every\n * row rather than the one or two rows that changed.\n *\n * Every prop above is a scalar or already memoised for that reason, and no\n * handler reaches here at all: the body delegates its events, so a row has\n * nothing to compare that changes each render.\n *\n * `memo` erases the type parameter, and the cast puts it back — the standard\n * price of memoising a generic component.\n */\nconst GridRow = memo(GridRowComponent) as typeof GridRowComponent;\n\nexport default GridRow;\n","import { createPortal } from \"react-dom\";\nimport { resolveKeyboardDropTarget } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { classNames } from \"../classNames\";\nimport type { GroupByDropTarget } from \"../groupByDropTarget\";\nimport useGroupByDrag from \"../useGroupByDrag\";\nimport type { RowGroupingApi } from \"../useRowGrouping\";\n\ninterface GroupByBarProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n grouping: RowGroupingApi<Row>;\n /** A column's accessible name — see `DataGrid.tsx`'s own `columnName`. */\n columnName: (columnId: string) => string;\n /** Whether the header drag currently open (if any) could drop into this bar. */\n headerDragEligible: boolean;\n /**\n * Whether the header drag currently open (if any) is for a column already\n * in the group-by stack — a drag this bar rejects outright, since\n * repositioning a grouped column is the chip's job, not the header's.\n */\n headerDragBlocked: boolean;\n /** That header drag's own target within this bar, or `null`. */\n headerDropTarget: GroupByDropTarget | null;\n}\n\n/**\n * The active group-by stack, outer to inner, as removable, reorderable\n * chips — and the drop target for a header dragged in from outside it.\n * Each column's own header already carries a group toggle (a pointer\n * affordance, plus `Alt+ArrowDown`) for adding or removing a level without\n * dragging at all; this bar shows the resulting stack, lets a level be\n * removed from it directly, lets a chip be dragged to reorder the stack (or\n * moved via `Ctrl+ArrowLeft`/`Ctrl+ArrowRight` on a focused one), and — for\n * a column whose header sets `groupByDraggable` and isn't grouped yet —\n * accepts a header dropped onto it, at whatever position among the existing\n * chips it's released. A header for a column already in the stack is\n * rejected outright (`is-drag-blocked`, `cursor: not-allowed`): the header\n * only ever adds, and repositioning an existing level is the chip's job.\n *\n * Whether this component mounts at all is `DataGrid.tsx`'s call\n * (`groupByBarVisibility`), not this component's own — it never bails out\n * on its own initiative once rendered.\n *\n * Chips sit outside the grid's own single-roving-tabstop model: there is no\n * shared index to keep in sync the way a row or a header cell has, so each\n * chip (and its own remove button) is simply, always `tabIndex={0}` — plain\n * DOM tab order, no roving-focus bookkeeping.\n */\nexport default function GroupByBar<Row>({\n columns,\n grouping,\n columnName,\n headerDragEligible,\n headerDragBlocked,\n headerDropTarget,\n}: GroupByBarProps<Row>) {\n const { groupBy } = grouping;\n const groupByIds = groupBy.map((entry) => entry.columnId);\n\n const chipDrag = useGroupByDrag({\n groupBy,\n onDrop: (movedId, beforeColumnId) => {\n grouping.moveGroupBy(movedId, beforeColumnId);\n },\n });\n\n // Mutually exclusive by construction — one pointer, so at most one of \"a\n // chip dragged within this bar\" and \"a header dragged in from outside it\"\n // is ever active at once.\n const activeDropTarget = chipDrag.dropTarget ?? headerDropTarget;\n const isDragTarget = chipDrag.draggedColumnId !== null || headerDragEligible;\n const showPlaceholder =\n groupBy.length === 0 && columns.some((entry) => entry.groupByDraggable);\n\n function labelFor(columnId: string) {\n return columns.find((entry) => entry.id === columnId)?.label ?? columnId;\n }\n\n function moveByKeyboard(columnId: string, direction: -1 | 1): void {\n const beforeColumnId = resolveKeyboardDropTarget(\n groupByIds,\n columnId,\n direction,\n );\n if (beforeColumnId === undefined) {\n return;\n }\n grouping.moveGroupBy(columnId, beforeColumnId);\n }\n\n return (\n <div\n className={classNames(\n \"gridkit-group-by-bar\",\n isDragTarget ? \"is-drag-target\" : \"\",\n headerDragBlocked ? \"is-drag-blocked\" : \"\",\n )}\n data-gridkit-group-by-bar=\"\"\n role=\"group\"\n aria-label=\"Grouped by\"\n >\n {showPlaceholder && (\n <span className=\"group-by-bar-placeholder\">\n Drag a column here to group by it\n </span>\n )}\n {groupBy.map((entry, index) => {\n const dropBefore = activeDropTarget?.beforeColumnId === entry.columnId;\n const dropAfter =\n activeDropTarget?.beforeColumnId === null &&\n index === groupBy.length - 1;\n const dragging = chipDrag.draggedColumnId === entry.columnId;\n\n return (\n <span\n key={entry.columnId}\n className={classNames(\n \"group-by-chip\",\n dragging ? \"is-dragging\" : \"\",\n dropBefore ? \"is-drop-before\" : \"\",\n dropAfter ? \"is-drop-after\" : \"\",\n )}\n data-gridkit-group-chip={entry.columnId}\n tabIndex={0}\n aria-label={\n groupBy.length > 1\n ? `${columnName(entry.columnId)}, level ${String(index + 1)} of ${String(groupBy.length)}`\n : columnName(entry.columnId)\n }\n aria-keyshortcuts=\"Control+ArrowLeft Control+ArrowRight\"\n onPointerDown={(event) => {\n chipDrag.startDrag(entry.columnId, event);\n }}\n onKeyDown={(event) => {\n const horizontal =\n event.key === \"ArrowLeft\" || event.key === \"ArrowRight\";\n if (horizontal && event.ctrlKey) {\n event.preventDefault();\n moveByKeyboard(\n entry.columnId,\n event.key === \"ArrowLeft\" ? -1 : 1,\n );\n }\n }}\n >\n <span className=\"group-by-chip-label\">\n {labelFor(entry.columnId)}\n </span>\n <button\n type=\"button\"\n className=\"group-by-chip-remove\"\n aria-label={`Stop grouping by ${columnName(entry.columnId)}`}\n onPointerDown={(event) => {\n // Otherwise the chip's own `onPointerDown` sees this bubble\n // up and starts a drag — the same reason the header's own\n // sort toggle stops it.\n event.stopPropagation();\n }}\n onClick={() => {\n grouping.toggleGroupBy(entry.columnId);\n }}\n >\n ×\n </button>\n </span>\n );\n })}\n {/*\n * Portalled to the body, the same reason the header's own drag ghost\n * is: inside the viewport the overflow that makes the grid scroll\n * would clip it, and this bar sits right above that viewport.\n */}\n {chipDrag.draggedColumnId !== null &&\n chipDrag.ghostTransform !== null &&\n createPortal(\n <span\n className=\"group-by-chip drag-ghost\"\n style={{ transform: chipDrag.ghostTransform }}\n aria-hidden=\"true\"\n >\n {labelFor(chipDrag.draggedColumnId)}\n </span>,\n document.body,\n )}\n </div>\n );\n}\n","import {\n movesGroupBy,\n resolveDropBefore,\n type GroupByState,\n} from \"@gridkitjs/core\";\nimport { elementAt, sideOf } from \"./useDragReorder\";\n\nexport interface GroupByDropTarget {\n readonly kind: \"group-by\";\n readonly beforeColumnId: string | null;\n}\n\n/**\n * Where a header or chip dropped at `(clientX, clientY)` would land within\n * the group-by bar, or `null` when the pointer isn't over the bar at all, or\n * when the drop would change nothing. Shared by `useColumnDrag` (a header\n * dragged in from outside the bar) and `useGroupByDrag` (a chip dragged\n * within it), so the two can never disagree about where a drop lands.\n */\nexport function resolveGroupByDropTarget(\n clientX: number,\n clientY: number,\n movedId: string,\n groupBy: GroupByState,\n): GroupByDropTarget | null {\n const overBar = elementAt(clientX, clientY, \"[data-gridkit-group-by-bar]\");\n if (overBar === null) {\n return null;\n }\n\n const overChip = elementAt(clientX, clientY, \"[data-gridkit-group-chip]\");\n const chipId = overChip?.getAttribute(\"data-gridkit-group-chip\");\n const beforeColumnId =\n overChip && chipId\n ? resolveDropBefore(\n groupBy.map((entry) => entry.columnId),\n chipId,\n sideOf(overChip, clientX),\n )\n : null; // Over the (possibly empty) bar itself, past every chip: append.\n\n return movesGroupBy(groupBy, movedId, beforeColumnId)\n ? { kind: \"group-by\", beforeColumnId }\n : null;\n}\n","import {\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport type { DropSide } from \"@gridkitjs/core\";\nimport { startPointerGesture } from \"./pointerGesture\";\n\n/**\n * How far the pointer travels before a press becomes a drag. Below it the\n * gesture is still a click, which is what leaves the pressed element free to\n * take one — shared by every drag-to-reorder gesture in the grid.\n */\nconst DRAG_THRESHOLD = 4;\n\n/**\n * The closest ancestor of (or the element itself at) `(x, y)` matching\n * `selector`. `closest` is what makes the whole matched element the target:\n * a hit on a descendant (a header's label, a chip's remove button) resolves\n * to it.\n */\nexport function elementAt(\n x: number,\n y: number,\n selector: string,\n): Element | null {\n return document.elementFromPoint(x, y)?.closest(selector) ?? null;\n}\n\n/** Which half of `element` `x` falls in. */\nexport function sideOf(element: Element, x: number): DropSide {\n const rect = element.getBoundingClientRect();\n return x < rect.left + rect.width / 2 ? \"before\" : \"after\";\n}\n\ninterface UseDragReorderOptions<Target> {\n /**\n * Where a drop at `(clientX, clientY)` would land, or `null` for nowhere\n * valid — including a gap `id` already occupies, the same \"promises only\n * moves that happen\" contract every reorder here keeps. Called on every\n * pointer move once the drag has opened; in full control of its own\n * hit-testing, against one destination or several.\n */\n resolveTarget: (\n clientX: number,\n clientY: number,\n id: string,\n ) => Target | null;\n onDrop: (target: Target, id: string) => void;\n}\n\nexport interface DragReorderApi<Target> {\n /** The item being dragged, for as long as the drag lasts. */\n draggedId: string | null;\n /** Where it would land if released now. */\n dropTarget: Target | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (\n id: string,\n grabElement: HTMLElement,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n /**\n * Whether the gesture that just ended was a drag rather than a click, for\n * a press that has something of its own to do with a click.\n *\n * Reading it clears it, so that a press which never opened a drag at all\n * does not see the last one's answer.\n */\n justDragged: () => boolean;\n}\n\n/**\n * The pointer mechanics behind every drag-to-reorder gesture in the grid —\n * capture, the drag threshold, the trailing ghost, and the click/drag\n * disambiguation `justDragged` reports — extracted so a column header drag\n * and a group-by chip drag (`useColumnDrag`, `useGroupByDrag`) share one\n * implementation and can only ever drift apart in their own hit-testing\n * (`resolveTarget`), not in how a pointer becomes a drag.\n *\n * Pointer events rather than HTML5 drag-and-drop, for the same reason\n * `useColumnDrag` originally chose them: `dragenter`/`dragleave` fire per\n * descendant, so a dragged item's own inner markup would each report the\n * target leaving and re-entering as the pointer crossed them.\n */\nexport default function useDragReorder<Target>({\n resolveTarget,\n onDrop,\n}: UseDragReorderOptions<Target>): DragReorderApi<Target> {\n const [draggedId, setDraggedId] = useState<string | null>(null);\n const [dropTarget, setDropTarget] = useState<Target | null>(null);\n const [ghostTransform, setGhostTransform] = useState<string | null>(null);\n const dragged = useRef(false);\n\n function justDragged(): boolean {\n const answer = dragged.current;\n dragged.current = false;\n return answer;\n }\n\n function startDrag(\n id: string,\n grabElement: HTMLElement,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const { pointerId, clientX: startX } = event;\n const grabX = startX - grabElement.getBoundingClientRect().left;\n let dragging = false;\n let target: Target | null = null;\n\n /** Keeps the grab offset, so the pointer holds the spot it picked up. */\n function placeGhost(x: number, y: number): void {\n setGhostTransform(`translate(${String(x - grabX)}px, ${String(y)}px)`);\n }\n\n function reset(): void {\n setGhostTransform(null);\n setDraggedId(null);\n setDropTarget(null);\n }\n\n startPointerGesture(grabElement, pointerId, {\n onMove(moveEvent) {\n const { clientX, clientY } = moveEvent;\n\n if (!dragging) {\n if (Math.abs(clientX - startX) < DRAG_THRESHOLD) {\n return;\n }\n dragging = true;\n // Latched for the `click` that follows the release, which is the\n // only thing that can tell a drag apart from a press in the same\n // spot.\n dragged.current = true;\n setDraggedId(id);\n }\n\n placeGhost(clientX, clientY);\n\n target = resolveTarget(clientX, clientY, id);\n setDropTarget(target);\n },\n onEnd() {\n const dropped = target;\n reset();\n if (dragging && dropped !== null) {\n onDrop(dropped, id);\n }\n },\n // Escape and a cancelled pointer both leave the order as it was.\n onCancel() {\n target = null;\n reset();\n },\n });\n }\n\n // A new object each render, as `useColumnDrag`/`useColumnResize` return:\n // the handlers close over `resolveTarget`/`onDrop`, and a stable identity\n // would buy nothing.\n return {\n draggedId,\n dropTarget,\n ghostTransform,\n startDrag,\n justDragged,\n };\n}\n","interface PointerGestureHandlers {\n onMove: (event: PointerEvent) => void;\n onEnd: () => void;\n onCancel: () => void;\n}\n\n/**\n * Wires up a pointer-driven gesture — capture, move tracking, and an\n * Escape-to-cancel — leaving the caller's `onMove`/`onEnd`/`onCancel` to own\n * the gesture's own domain logic (and any state reset that goes with it).\n *\n * A plain function rather than a hook: the caller already owns every piece of\n * state involved via closures, so there is nothing here for React to manage.\n */\nexport function startPointerGesture(\n element: HTMLElement,\n pointerId: number,\n handlers: PointerGestureHandlers,\n): void {\n element.setPointerCapture(pointerId);\n\n function stop(): void {\n element.removeEventListener(\"pointermove\", move);\n element.removeEventListener(\"pointerup\", end);\n element.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (element.hasPointerCapture(pointerId)) {\n element.releasePointerCapture(pointerId);\n }\n }\n\n function move(event: PointerEvent): void {\n handlers.onMove(event);\n }\n\n function end(): void {\n stop();\n handlers.onEnd();\n }\n\n function cancel(): void {\n stop();\n handlers.onCancel();\n }\n\n function onKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n cancel();\n }\n }\n\n element.addEventListener(\"pointermove\", move);\n element.addEventListener(\"pointerup\", end);\n element.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n}\n","import type { PointerEvent as ReactPointerEvent } from \"react\";\nimport type { GroupByState } from \"@gridkitjs/core\";\nimport {\n resolveGroupByDropTarget,\n type GroupByDropTarget,\n} from \"./groupByDropTarget\";\nimport useDragReorder from \"./useDragReorder\";\n\ninterface UseGroupByDragOptions {\n groupBy: GroupByState;\n onDrop: (movedColumnId: string, beforeColumnId: string | null) => void;\n}\n\nexport interface GroupByDragApi {\n /** The chip being dragged, for as long as the drag lasts. */\n draggedColumnId: string | null;\n /** Where it would land if released now. */\n dropTarget: GroupByDropTarget | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (columnId: string, event: ReactPointerEvent<HTMLElement>) => void;\n /** Whether the gesture that just ended was a drag rather than a click. */\n justDragged: () => boolean;\n}\n\n/**\n * Drag-to-reorder for chips inside the group-by bar, built on the same\n * `useDragReorder` mechanics `useColumnDrag` uses for headers — only the\n * hit-testing (`resolveGroupByDropTarget`, shared with a header dropped in\n * from outside the bar) differs.\n */\nexport default function useGroupByDrag({\n groupBy,\n onDrop,\n}: UseGroupByDragOptions): GroupByDragApi {\n const drag = useDragReorder<GroupByDropTarget>({\n resolveTarget: (clientX, clientY, movedId) =>\n resolveGroupByDropTarget(clientX, clientY, movedId, groupBy),\n onDrop: (target, movedId) => {\n onDrop(movedId, target.beforeColumnId);\n },\n });\n\n return {\n draggedColumnId: drag.draggedId,\n dropTarget: drag.dropTarget,\n ghostTransform: drag.ghostTransform,\n startDrag: (columnId, event) => {\n drag.startDrag(columnId, event.currentTarget, event);\n },\n justDragged: drag.justDragged,\n };\n}\n","import type { PointerEvent as ReactPointerEvent } from \"react\";\nimport {\n movesColumn,\n resolveDropBefore,\n resolveKeyboardDropTarget,\n type ColumnOrderState,\n type GroupByState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport {\n resolveGroupByDropTarget,\n type GroupByDropTarget,\n} from \"./groupByDropTarget\";\nimport useDragReorder, { elementAt, sideOf } from \"./useDragReorder\";\n\n/**\n * Where a drop would land. A second drop zone — the group-by bar — is a\n * second member here rather than a reshaping of this state, exactly as\n * originally planned: a header dragged past every other header and onto the\n * bar produces `\"group-by\"` instead of `\"column-order\"`, and `handleDrop`\n * switches on `kind`.\n */\nexport type DropTarget =\n { kind: \"column-order\"; beforeId: string | null } | GroupByDropTarget;\n\ninterface UseColumnDragOptions {\n order: ColumnOrderState;\n /** What a drop onto the group-by bar is resolved against. */\n groupBy: GroupByState;\n /** Column ids whose header may be dragged into the group-by bar at all. */\n groupByDraggableIds: ReadonlySet<string>;\n onDrop: (target: DropTarget, movedId: string) => void;\n}\n\nexport interface ColumnDragApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n draggedColumnId: string | null;\n /** Where it would land if released now. */\n dropTarget: DropTarget | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n /** Moves a column one place left (`-1`) or right (`1`). */\n moveByKeyboard: (entry: ResolvedColumn<Row>, direction: -1 | 1) => void;\n /**\n * Whether the gesture that just ended was a drag rather than a click, for a\n * header that has something of its own to do with a click.\n *\n * Reading it clears it, so that a press which never opened a drag at all —\n * on a column that cannot be reordered — does not see the last one's answer.\n */\n justDragged: () => boolean;\n}\n\n/**\n * Turns a pointer drag over the header into a drop target, leaving `onDrop` to\n * apply it. Built on `useDragReorder`'s shared pointer mechanics — this hook\n * supplies only the hit-testing: another header (reorder among columns) or\n * the group-by bar (add this column to the grouping), tried in that order.\n */\nexport default function useColumnDrag<Row>({\n order,\n groupBy,\n groupByDraggableIds,\n onDrop,\n}: UseColumnDragOptions): ColumnDragApi<Row> {\n const drag = useDragReorder<DropTarget>({\n resolveTarget(clientX, clientY, movedId) {\n // Hit-tested rather than read from the event's target, which pointer\n // capture pins to the header the drag opened on.\n const over = elementAt(clientX, clientY, \"th[data-gridkit-column]\");\n const overId = over?.getAttribute(\"data-gridkit-column\");\n\n // The rect is read fresh each move, so a width changed mid-drag\n // cannot leave the midpoint stale.\n const beforeId =\n over && overId\n ? resolveDropBefore(order, overId, sideOf(over, clientX))\n : undefined;\n\n if (beforeId !== undefined) {\n // A gap the column already sits in would promise a move that\n // `moveColumnBefore` then declines to make.\n return movesColumn(order, movedId, beforeId)\n ? { kind: \"column-order\", beforeId }\n : null;\n }\n\n // Already grouped: reordering it is the chip's job, not the header's —\n // dragging it back into the bar is never a valid target.\n const alreadyGrouped = groupBy.some(\n (entry) => entry.columnId === movedId,\n );\n\n return groupByDraggableIds.has(movedId) && !alreadyGrouped\n ? resolveGroupByDropTarget(clientX, clientY, movedId, groupBy)\n : null;\n },\n onDrop,\n });\n\n function startDrag(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n drag.startDrag(entry.id, event.currentTarget, event);\n }\n\n function moveByKeyboard(entry: ResolvedColumn<Row>, direction: -1 | 1): void {\n const beforeId = resolveKeyboardDropTarget(order, entry.id, direction);\n if (beforeId === undefined) {\n return;\n }\n onDrop({ kind: \"column-order\", beforeId }, entry.id);\n }\n\n // A new object each render, as `useColumnResize` returns: the handlers close\n // over `order`/`groupBy`, and a stable identity would buy nothing.\n return {\n draggedColumnId: drag.draggedId,\n dropTarget: drag.dropTarget,\n ghostTransform: drag.ghostTransform,\n startDrag,\n moveByKeyboard,\n justDragged: drag.justDragged,\n };\n}\n","import {\n useState,\n type Dispatch,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n type SetStateAction,\n} from \"react\";\nimport {\n applyColumnResize,\n beginColumnResize,\n clampColumnWidth,\n resolveColumnConstraints,\n revertColumnSize,\n sizeColumnToContent,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport measureColumnContent from \"./measureColumnContent\";\nimport { startPointerGesture } from \"./pointerGesture\";\n\ninterface UseColumnResizeOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n sizing: ColumnSizingState;\n setSizing: Dispatch<SetStateAction<ColumnSizingState>>;\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport interface ColumnResizeApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n activeColumnId: string | null;\n startResize: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n sizeToContent: (entry: ResolvedColumn<Row>) => void;\n nudge: (entry: ResolvedColumn<Row>, delta: number) => void;\n}\n\n/**\n * Turns pointer and keyboard input into column widths. Every width it produces\n * comes from `@gridkitjs/core`; this hook only supplies the coordinates.\n */\nexport default function useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n}: UseColumnResizeOptions): ColumnResizeApi<Row> {\n const [activeColumnId, setActiveColumnId] = useState<string | null>(null);\n\n /**\n * Deliberately not built on `commitIfChanged`: its \"move\" phase is called\n * on every pointer move, including ones pinned against a min/max clamp\n * where the resulting width doesn't change, and it intentionally fires\n * `onColumnResize` anyway rather than adopting the bail-if-unchanged guard\n * every other commit-style call site has.\n */\n function commit(\n base: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n const next = { ...base, [columnId]: width };\n setSizing(next);\n onColumnResize?.({ columnId, width, sizing: next, phase });\n }\n\n function startResize(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const handle = event.currentTarget;\n const { pointerId } = event;\n const session = beginColumnResize(\n entry.column,\n entry.width,\n event.clientX,\n columnSizeDefaults,\n );\n /**\n * Only the dragged column can change while the drag lasts, so the state as\n * it was when the drag opened stays a correct base to merge into — no ref\n * mirror is needed to dodge a stale closure.\n */\n const base = sizing;\n let width = session.startWidth;\n\n // Otherwise the drag selects the header text it started on.\n event.preventDefault();\n event.stopPropagation();\n setActiveColumnId(session.columnId);\n\n startPointerGesture(handle, pointerId, {\n onMove(moveEvent) {\n width = applyColumnResize(session, moveEvent.clientX);\n commit(base, session.columnId, width, \"move\");\n },\n onEnd() {\n setActiveColumnId(null);\n // A click with no intervening `move` — as every double-click's two\n // constituent clicks are — leaves `width` at `startWidth`. Committing\n // that anyway would fire a spurious onColumnResize on every click.\n if (width !== session.startWidth) {\n commit(base, session.columnId, width, \"end\");\n }\n },\n /**\n * Escape puts back only the dragged column's pre-drag width, merged\n * into whatever the sizing state is *now* — not the `base` snapshot\n * taken at drag-start — so a different column resized via keyboard\n * while this drag was still open keeps its change instead of being\n * clobbered by a stale restore.\n */\n onCancel() {\n setActiveColumnId(null);\n setSizing((current) => {\n const next = revertColumnSize(current, base, session.columnId);\n onColumnResize?.({\n columnId: session.columnId,\n width: session.startWidth,\n sizing: next,\n phase: \"end\",\n });\n return next;\n });\n },\n });\n }\n\n function sizeToContent(entry: ResolvedColumn<Row>): void {\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n\n const measured = measureColumnContent(table, entry.id);\n if (measured === null) {\n return;\n }\n\n commit(\n sizing,\n entry.id,\n sizeColumnToContent(\n measured,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n function nudge(entry: ResolvedColumn<Row>, delta: number): void {\n commit(\n sizing,\n entry.id,\n clampColumnWidth(\n entry.width + delta,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n // Deliberately a new object each render: the handlers close over `sizing` to\n // merge into, and a stable identity would need either `sizing` in a\n // `useCallback` dep list (no gain) or the ref mirror avoided above.\n return { activeColumnId, startResize, sizeToContent, nudge };\n}\n","/**\n * The width the widest cell in `columnId` needs to show its content in full,\n * or `null` when the column has no cells.\n *\n * Measured with a `Range` over each cell's contents rather than the cell's own\n * `scrollWidth`. A range shrink-wraps what is actually laid out, so a column\n * far wider than its content reports the content width and can be sized *down*;\n * `scrollWidth` never reports less than the cell it is read from and so can\n * only ever grow a column.\n *\n * Only rendered rows are measured — once paging or virtualisation lands, that\n * means the visible ones.\n */\nexport default function measureColumnContent(\n table: HTMLTableElement,\n columnId: string,\n): number | null {\n const cells = table.querySelectorAll<HTMLElement>(\n `td[data-gridkit-column=\"${CSS.escape(columnId)}\"]`,\n );\n const range = document.createRange();\n let widest: number | null = null;\n\n for (const cell of cells) {\n range.selectNodeContents(cell);\n const style = getComputedStyle(cell);\n // The range covers the content box only, so the cell's own spacing has to\n // be added back or the column would clip by exactly its padding.\n const width =\n range.getBoundingClientRect().width +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth);\n\n if (widest === null || width > widest) {\n widest = width;\n }\n }\n\n return widest;\n}\n","import type { Dispatch, SetStateAction } from \"react\";\nimport {\n sortDirectionFor,\n sortPriorityFor,\n toggleColumnSort,\n type ColumnSortEvent,\n type ColumnSortState,\n type SortDirection,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\ninterface UseColumnSortOptions {\n sort: ColumnSortState;\n setSort: Dispatch<SetStateAction<ColumnSortState>>;\n onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;\n}\n\nexport interface ColumnSortApi<Row> {\n sort: ColumnSortState;\n /** This column's direction, or `null` if it takes no part in the sort. */\n directionFor: (columnId: string) => SortDirection | null;\n /**\n * This column's 1-based place in the stack, or `null` outside it. Only\n * meaningful once two or more columns are stacked.\n */\n priorityFor: (columnId: string) => number | null;\n /** Cycles `entry`'s sort. A `shiftKey` stacks it; its absence replaces the stack. */\n toggle: (entry: ResolvedColumn<Row>, event: { shiftKey: boolean }) => void;\n}\n\n/**\n * Turns a click or keypress into a sort. Every transition it produces comes\n * from `@gridkitjs/core`; this hook only supplies the state to transform and\n * reports the result.\n */\nexport default function useColumnSort<Row>({\n sort,\n setSort,\n onColumnSortChange,\n}: UseColumnSortOptions): ColumnSortApi<Row> {\n function toggle(\n entry: ResolvedColumn<Row>,\n event: { shiftKey: boolean },\n ): void {\n const next = toggleColumnSort(sort, entry.id, { stack: event.shiftKey });\n commitIfChanged(sort, next, setSort, (committed) => {\n onColumnSortChange?.({ columnId: entry.id, sort: committed });\n });\n }\n\n // A new object each render, as the other hooks here return.\n return {\n sort,\n directionFor: (columnId) => sortDirectionFor(sort, columnId),\n priorityFor: (columnId) => sortPriorityFor(sort, columnId),\n toggle,\n };\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * The inner width of `ref`'s element, tracked as it changes.\n *\n * A layout effect rather than an effect so the first measurement lands before\n * paint — otherwise columns show at their natural width for a frame and then\n * visibly jump once auto-fit runs. Server rendering would want the usual\n * isomorphic-layout-effect shim here.\n *\n * Reads `clientWidth` rather than the observer entry's `contentRect` so the\n * first measurement and every later one come from the same, already-rounded,\n * source.\n *\n * @param enabled Whether to observe at all. A caller that does not read the\n * width passes `false` rather than paying a re-render of the whole grid on\n * every frame of a window resize.\n */\nexport default function useElementWidth(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean,\n): number | null {\n const [width, setWidth] = useState<number | null>(null);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (element === null || !enabled) {\n return undefined;\n }\n\n setWidth(element.clientWidth);\n\n const observer = new ResizeObserver(() => {\n setWidth(element.clientWidth);\n });\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref, enabled]);\n\n return width;\n}\n","import type { Dispatch, SetStateAction } from \"react\";\nimport {\n collapseAllGroups,\n expandAllGroups,\n moveGroupByBefore,\n toggleGroupExpansion,\n type DisplayRow,\n type GroupByEvent,\n type GroupByState,\n type GroupExpansionEvent,\n type GroupExpansionState,\n} from \"@gridkitjs/core\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\ninterface UseRowGroupingOptions {\n groupBy: GroupByState;\n setGroupBy: Dispatch<SetStateAction<GroupByState>>;\n expansion: GroupExpansionState;\n setExpansion: Dispatch<SetStateAction<GroupExpansionState>>;\n onGroupByChange?: ((event: GroupByEvent) => void) | undefined;\n onGroupExpansionChange?: ((event: GroupExpansionEvent) => void) | undefined;\n}\n\nexport interface RowGroupingApi<Row> {\n groupBy: GroupByState;\n expansion: GroupExpansionState;\n isExpanded: (groupId: string) => boolean;\n toggleExpansion: (groupId: string) => void;\n expandAll: () => void;\n collapseAll: (rows: readonly DisplayRow<Row>[]) => void;\n /** Appends or removes columnId from the group-by stack — the state change a group-bar drop or a \"group by this column\" header action produces. */\n toggleGroupBy: (columnId: string) => void;\n /**\n * Adds `columnId` to the group-by stack at a position, or repositions it\n * if it's already there — what dragging a header into the bar, dragging a\n * chip within it, or `Ctrl+ArrowLeft`/`Ctrl+ArrowRight` on a focused chip\n * all produce.\n */\n moveGroupBy: (columnId: string, beforeColumnId: string | null) => void;\n}\n\n/**\n * Turns a group-header click, a \"group by this column\" action, or a\n * group-bar rearrange into the next `GroupByState`/`GroupExpansionState`,\n * committing through `commitIfChanged` exactly as `useColumnSort` does, so a\n * no-op neither re-renders nor fires its `onChange`.\n */\nexport default function useRowGrouping<Row>({\n groupBy,\n setGroupBy,\n expansion,\n setExpansion,\n onGroupByChange,\n onGroupExpansionChange,\n}: UseRowGroupingOptions): RowGroupingApi<Row> {\n function commitExpansion(\n next: GroupExpansionState,\n groupId: string | null,\n ): void {\n commitIfChanged(expansion, next, setExpansion, (committed) => {\n onGroupExpansionChange?.({ groupId, expansion: committed });\n });\n }\n\n function commitGroupBy(next: GroupByState, columnId: string): void {\n commitIfChanged(groupBy, next, setGroupBy, (committed) => {\n onGroupByChange?.({ columnId, groupBy: committed });\n });\n }\n\n function toggleGroupBy(columnId: string): void {\n const isGrouped = groupBy.some((entry) => entry.columnId === columnId);\n const next = isGrouped\n ? groupBy.filter((entry) => entry.columnId !== columnId)\n : [...groupBy, { columnId }];\n commitGroupBy(next, columnId);\n }\n\n function moveGroupBy(columnId: string, beforeColumnId: string | null): void {\n commitGroupBy(\n moveGroupByBefore(groupBy, columnId, beforeColumnId),\n columnId,\n );\n }\n\n return {\n groupBy,\n expansion,\n isExpanded: (groupId) => !expansion.includes(groupId),\n toggleExpansion: (groupId) => {\n commitExpansion(toggleGroupExpansion(expansion, groupId), groupId);\n },\n expandAll: () => {\n commitExpansion(expandAllGroups(expansion), null);\n },\n collapseAll: (rows) => {\n commitExpansion(collapseAllGroups(rows), null);\n },\n toggleGroupBy,\n moveGroupBy,\n };\n}\n"],"mappings":"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","names":["useMemo","useRef","useState","useRef","useRef","useMemo","intentOf","jsx","jsxs","memo","jsx","memo","jsx","useMemo","intentOf","createPortal","useRef","useState","useState","useRef","jsx","jsxs","createPortal","resolveDropBefore","resolveKeyboardDropTarget","resolveDropBefore","resolveKeyboardDropTarget","useState","useState","useState","jsx","jsxs","useRef","useState","useMemo"]}
1
+ {"version":3,"sources":["../src/DataGrid/DataGrid.tsx","../src/DataGrid/components/GridHeader.tsx","../src/DataGrid/ariaAttr.ts","../src/DataGrid/classNames.ts","../src/DataGrid/useGridNavigation.ts","../src/DataGrid/useGridSelection.ts","../src/DataGrid/commitIfChanged.ts","../src/DataGrid/components/GridBody.tsx","../src/DataGrid/components/GridGroupRow.tsx","../src/DataGrid/components/formatAggregateValue.ts","../src/DataGrid/components/GridGroupSummaryRow.tsx","../src/DataGrid/components/GridRow.tsx","../src/DataGrid/components/GridFooter.tsx","../src/DataGrid/components/GridPager.tsx","../src/DataGrid/components/GroupByBar.tsx","../src/DataGrid/groupByDropTarget.ts","../src/DataGrid/useDragReorder.ts","../src/DataGrid/pointerGesture.ts","../src/DataGrid/useGroupByDrag.ts","../src/DataGrid/useColumnDrag.ts","../src/DataGrid/useColumnResize.ts","../src/DataGrid/measureColumnContent.ts","../src/DataGrid/useColumnSort.ts","../src/DataGrid/useElementWidth.ts","../src/DataGrid/usePagination.ts","../src/DataGrid/useRowGrouping.ts","../src/DataGrid/hooks/usePaginationState.ts","../src/DataGrid/hooks/useGridSnapshot.ts","../src/DataGrid/hooks/useGroupByState.ts","../src/DataGrid/hooks/useColumnSortState.ts","../src/DataGrid/hooks/useSelectionState.ts","../src/DataGrid/hooks/useAggregateState.ts","../src/DataGrid/hooks/useColumnSizingState.ts","../src/DataGrid/hooks/useColumnOrderState.ts"],"sourcesContent":["import {\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport {\n applyColumnOrder,\n computeAggregates,\n defineColumnsFromRows,\n fitColumnsToWidth,\n groupRows,\n moveColumnBefore,\n paginateRows,\n resolveColumnWidths,\n resolveRowId,\n resolveShownRows,\n totalColumnWidth,\n withGroupAggregates,\n type ColumnDefinition as CoreColumnDefinition,\n type ResolvedColumn as CoreResolvedColumn,\n type AggregateResults,\n type AggregateState,\n type ColumnOrderEvent,\n type ColumnOrderState,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n type ColumnSortEvent,\n type ColumnSortState,\n type DisplayRow,\n type FilterState,\n type GroupAggregateDisplay,\n type GroupByEvent,\n type GroupByState,\n type GroupExpansionEvent,\n type GroupExpansionState,\n type PaginationChangeEvent,\n type PaginationState,\n type ResolvedRow,\n type CellSelectionState,\n type SelectableConfig,\n type SelectedCell as CoreSelectedCell,\n type SelectedColumn as CoreSelectedColumn,\n type SelectionState,\n type CellSelectEvent as CoreCellSelectEvent,\n type CellSelectionChangeEvent as CoreCellSelectionChangeEvent,\n type ColumnSelectEvent as CoreColumnSelectEvent,\n type ColumnSelectionChangeEvent as CoreColumnSelectionChangeEvent,\n type ColumnsSelectEvent as CoreColumnsSelectEvent,\n} from \"@gridkitjs/core\";\nimport GridHeader from \"./components/GridHeader\";\nimport GridBody from \"./components/GridBody\";\nimport GridFooter from \"./components/GridFooter\";\nimport GridPager from \"./components/GridPager\";\nimport GroupByBar from \"./components/GroupByBar\";\nimport { ariaAttr } from \"./ariaAttr\";\nimport { classNames } from \"./classNames\";\nimport useColumnDrag, { type DropTarget } from \"./useColumnDrag\";\nimport useColumnResize from \"./useColumnResize\";\nimport useColumnSort from \"./useColumnSort\";\nimport useElementWidth from \"./useElementWidth\";\nimport useGridNavigation, { HEADER_ROW } from \"./useGridNavigation\";\nimport useGridSelection, { type SelectionCallbacks } from \"./useGridSelection\";\nimport usePagination from \"./usePagination\";\nimport useRowGrouping from \"./useRowGrouping\";\n\n/**\n * A column whose header and cells may render arbitrary React content.\n * @gridkitjs/core stays framework-agnostic and so leaves that output type open;\n * this is the binding React consumers want, and the one they should import.\n */\nexport type ColumnDefinition<Row> = CoreColumnDefinition<Row, ReactNode>;\n\n/** A column paired with the width it renders at. */\nexport type ResolvedColumn<Row> = CoreResolvedColumn<Row, ReactNode>;\n\n/**\n * The selection payloads, bound to React's node type for the same reason\n * `ColumnDefinition` is: they carry a resolved column, whose label is whatever\n * a `headerTemplate` returned.\n *\n * The row payloads name no node type at all and so are re-exported from\n * `@gridkitjs/core` as they are.\n */\nexport type SelectedColumn<Row> = CoreSelectedColumn<Row, ReactNode>;\nexport type SelectedCell<Row> = CoreSelectedCell<Row, ReactNode>;\nexport type ColumnSelectEvent<Row> = CoreColumnSelectEvent<Row, ReactNode>;\nexport type ColumnsSelectEvent<Row> = CoreColumnsSelectEvent<Row, ReactNode>;\nexport type ColumnSelectionChangeEvent<Row> = CoreColumnSelectionChangeEvent<\n Row,\n ReactNode\n>;\nexport type CellSelectEvent<Row> = CoreCellSelectEvent<Row, ReactNode>;\nexport type CellSelectionChangeEvent<Row> = CoreCellSelectionChangeEvent<\n Row,\n ReactNode\n>;\n\n/**\n * Imperative handle for a mounted `DataGridComponent`, reached via its `ref`\n * prop. Read-plus-standard-actions: getters mirror the grid's live state,\n * and the actions are the ones every grid ref carries (focus, clear/select\n * all, scroll-to). Sizing, order, sort, and selection stay uncontrolled via\n * their existing `default*` props — this is not a second, imperative-only\n * way to drive that same state. `subscribe` doesn't change that: it's a\n * read/notify channel for reacting to state that already lives here, not a\n * write path — nothing becomes newly *driven* through the ref by its\n * existence. See `packages/react/src/DataGrid/hooks/` for the public hooks\n * built on it.\n */\nexport interface DataGridApi<Row> {\n /** The grid's scrollable viewport element. */\n readonly element: HTMLDivElement | null;\n /** The grid's `<table>` element. */\n readonly table: HTMLTableElement | null;\n\n /** Rows as currently filtered and sorted — what's rendered, ungrouped. */\n getRows(): readonly ResolvedRow<Row>[];\n /**\n * `getRows()` regrouped into the active `groupBy` — group headers\n * interleaved with data rows, in render order. Identical to `getRows()`\n * when `groupBy` is empty.\n */\n getDisplayRows(): readonly DisplayRow<Row>[];\n /** Columns as currently sized and ordered — what's rendered. */\n getColumns(): readonly ResolvedColumn<Row>[];\n\n getColumnSizing(): ColumnSizingState;\n getColumnOrder(): ColumnOrderState;\n getColumnSort(): ColumnSortState;\n getGroupBy(): GroupByState;\n getGroupExpansion(): GroupExpansionState;\n /** The active page and page size. Meaningful even when `paginated` is off — it stays at page 0 over the grid's whole (single) page. */\n getPagination(): PaginationState;\n /** How many pages the current `pagination.pageSize` splits the grid's rows into — `1` whenever `paginated` is off. */\n getPageCount(): number;\n /**\n * The grand-total aggregate results — every active aggregate computed over\n * the whole filtered/sorted dataset, ungrouped and unpaginated. A specific\n * group's own results are read off `getDisplayRows()` instead, on that\n * group header's `aggregates` field.\n */\n getAggregates(): AggregateResults;\n getRowSelection(): SelectionState;\n getColumnSelection(): SelectionState;\n getCellSelection(): CellSelectionState;\n /** The cell currently holding the grid's single tab stop. */\n getFocusedCell(): { rowIndex: number; columnIndex: number };\n\n focusCell(rowIndex: number, columnIndex: number): void;\n clearSelection(): void;\n selectAllRows(): void;\n /** Expands every group at once — there is no dedicated UI control for it. */\n expandAllGroups(): void;\n /** Collapses every group currently shown at once — see `collapseAllGroups` in `@gridkitjs/core` for what \"currently shown\" means for a group already nested under a collapsed one. */\n collapseAllGroups(): void;\n /** Moves to the given page, clamped into range. */\n goToPage(pageIndex: number): void;\n /** Moves to the next page. A no-op on the last page. */\n nextPage(): void;\n /** Moves to the previous page. A no-op on the first page. */\n previousPage(): void;\n /** Changes the page size, resetting to the first page. */\n setPageSize(pageSize: number): void;\n /** Scrolls the row with the given id into view, if it is currently shown. */\n scrollToRow(rowId: string, options?: ScrollIntoViewOptions): void;\n /** Scrolls the column with the given id into view. */\n scrollToColumn(columnId: string, options?: ScrollIntoViewOptions): void;\n\n /**\n * Registers `listener` to be called after any render in which the grid's\n * internal state may have changed — every getter above may return a\n * different value once `listener` fires, not just one. Returns an\n * unsubscribe function. The primitive the `use*State` hooks under\n * `packages/react/src/DataGrid/hooks/` build on; most consumers should\n * reach for one of those instead of calling `subscribe` directly.\n */\n subscribe(listener: () => void): () => void;\n}\n\nexport type Borders = \"horizontal\" | \"vertical\" | \"all\" | \"none\";\n\n/**\n * How a column's width relates to the grid's.\n *\n * `\"fit\"` keeps the columns filling the grid: the space a column gives up is\n * handed to the others, and the space it takes comes out of them. `\"fixed\"`\n * lets every column keep its own width, so a resize moves one column and\n * nothing else, and the grid scrolls or leaves a gap accordingly.\n */\nexport type ResizeMode = \"fit\" | \"fixed\";\n\n/** `pagination.pageSize` a paginated grid starts at when `defaultPagination` omits one — a reasonable default for an ERP-grade dataset. */\nconst DEFAULT_PAGE_SIZE = 25;\n\n/**\n * A stable empty fallback for an omitted `aggregates` prop — a fresh `[]`\n * every render would change identity each time and defeat the `useMemo`s\n * that depend on it, the same reason `groupRows`/`withGroupAggregates`\n * themselves return their input untouched for an empty array rather than a\n * new one.\n */\nconst NO_AGGREGATES: AggregateState<never> = [];\n\n/**\n * How the group-by bar's visibility follows the active grouping. `\"always\"`\n * renders it even with an empty `groupBy` — a fixed drop target and a\n * constant reminder grouping exists. `\"never\"` never renders it, for a grid\n * driving `groupBy` entirely by its own UI (a header toggle, `Alt+ArrowDown`)\n * or programmatically. `\"auto\"` renders it once `groupBy` is non-empty, or\n * while a header drag eligible to drop into it is in progress — so there is\n * always somewhere to drop the very first column, even from a fully empty\n * grouping.\n */\nexport type GroupByBarVisibility = \"always\" | \"auto\" | \"never\";\n\nexport interface HoverableConfig {\n rows?: boolean;\n columns?: boolean;\n cells?: boolean;\n}\n\n/**\n * Everything a `pager.template` render prop needs to rebuild the built-in\n * pager's UI itself. Passed fresh on every render where pagination-relevant\n * state changed, so it's current by construction — unlike `DataGridApi`'s\n * imperative methods and snapshot getters, which carry no \"something\n * changed, re-render\" signal of their own.\n */\nexport interface PagerTemplateContext {\n /** Same shape as `DataGridApi.getPagination()` — 0-based `pageIndex`. */\n pagination: PaginationState;\n /** `pagination.pageIndex + 1`, clamped — the display-ready page number. */\n currentPage: number;\n pageCount: number;\n /** Passthrough of `pager.sizeOptions`, undefined when not given. */\n pageSizeOptions: readonly number[] | undefined;\n /** 0-based, same as `DataGridApi.goToPage` — not `currentPage`'s numbering. */\n goToPage: (pageIndex: number) => void;\n nextPage: () => void;\n previousPage: () => void;\n setPageSize: (pageSize: number) => void;\n}\n\n/** Presentation options for the grid's built-in pager. */\nexport interface PagerConfig {\n /** Page sizes offered by the built-in pager's page-size control. */\n sizeOptions?: readonly number[] | undefined;\n /** Defaults to `\"compact\"` — today's Prev/status/Next. */\n variant?: \"compact\" | \"numbered\" | undefined;\n /** Numbered variant only. How many pages to always show at each end. Defaults to 1. */\n boundaryCount?: number | undefined;\n /** Numbered variant only. How many pages to show on each side of the current page. Defaults to 1. */\n siblingCount?: number | undefined;\n /** Replaces the built-in pager entirely when given. `variant` is ignored. */\n template?: ((context: PagerTemplateContext) => ReactNode) | undefined;\n}\n\nexport interface DataGridProps<Row> extends SelectionCallbacks<Row> {\n columns?: readonly ColumnDefinition<Row>[] | undefined;\n dataSource?: readonly Row[] | undefined;\n /**\n * A row's stable identity, for state keyed by it. Defaults to the row's\n * position, which is enough for a static grid but ties that state to where a\n * row sits rather than to the row — so anything sorting, filtering or paging\n * its data should give one.\n *\n * Called for every row on every change to `dataSource`, so it should be\n * cheap and stable; an inline arrow is fine, one that re-reads the data is\n * not.\n */\n getRowId?: ((row: Row, index: number) => string) | undefined;\n borders?: Borders | undefined;\n hoverable?: HoverableConfig | undefined;\n /**\n * Which parts of the grid the user may select, and how many of each —\n * `{ rows: \"multiple\", cells: \"single\" }`. A cell addresses one value, so it\n * has no `\"multiple\"`.\n *\n * Off by default, unlike `hoverable`: selection claims the click, which a\n * grid that only displays data should not do. Give `getRowId` alongside it\n * for data that sorts, filters or pages, or a selection follows the position\n * rather than the row.\n */\n selectable?: SelectableConfig | undefined;\n /** Row ids selected to start with, keyed as `getRowId` resolves them. Uncontrolled. */\n defaultRowSelection?: SelectionState | undefined;\n /** Column ids selected to start with. Uncontrolled. */\n defaultColumnSelection?: SelectionState | undefined;\n /** The cell selected to start with. Uncontrolled. */\n defaultCellSelection?: CellSelectionState | undefined;\n /** Whether columns can be dragged wider, unless a column says otherwise. */\n resizableColumns?: boolean | undefined;\n /**\n * Whether columns can be dragged into a new position, unless a column says\n * otherwise. Turning it off leaves an order the user already made in place.\n */\n reorderableColumns?: boolean | undefined;\n /**\n * Whether columns fill the grid's width or sit at their own. Defaults to\n * `\"fit\"`, under which columns the user has sized keep their width and the\n * rest share what is left.\n */\n resizeMode?: ResizeMode | undefined;\n /** Column widths to start from, keyed by column id. Uncontrolled. */\n defaultColumnSizing?: ColumnSizingState | undefined;\n /**\n * Column ids in the order to start in. Uncontrolled, and partial: ids it\n * omits keep their position among `columns` and follow those it lists.\n */\n defaultColumnOrder?: ColumnOrderState | undefined;\n /**\n * Sizes applied to columns that do not set their own — the width they start\n * at and the bounds they may be resized between. Distinct from\n * `defaultColumnSizing`, which sets specific columns' starting widths.\n */\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n /**\n * Called as the user resizes a column. Fires continuously with\n * `phase: \"move\"` and once on release with `phase: \"end\"` — the latter being\n * the one to persist. Auto-fit does not call it; it reports user intent only.\n */\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n /**\n * Called once when the user drops a column somewhere new. A drop that leaves\n * the order as it was does not call it.\n */\n onColumnOrderChange?: ((event: ColumnOrderEvent) => void) | undefined;\n /**\n * Whether columns can be sorted by clicking their header toggle, unless a\n * column says otherwise. Shift-click stacks a column into the sort instead\n * of replacing it.\n */\n sortableColumns?: boolean | undefined;\n /** The sort to start with, in priority order. Uncontrolled. */\n defaultColumnSort?: ColumnSortState | undefined;\n /**\n * Called once when the user changes the sort — a toggle, a stack, or a\n * clear back to \"none\".\n */\n onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;\n /**\n * Whether columns can be grouped by — a header's click/`Alt+ArrowDown`\n * toggle — unless a column says otherwise. The grouping itself still\n * applies when this is off, via `defaultGroupBy` or the imperative API;\n * this only gates that one interaction, the same way `sortableColumns`\n * gates the sort toggle without disabling `defaultColumnSort`. Independent\n * of `groupByBarVisibility` and `groupByDraggableColumns`, which gate the\n * bar and the drag-in gesture respectively.\n */\n groupableColumns?: boolean | undefined;\n /**\n * Whether a groupable header shows its group-toggle icon, unless a column\n * says otherwise. Purely a rendering choice: `Alt+ArrowDown` keeps working\n * on a groupable header with the icon hidden.\n */\n groupToggleIconColumns?: boolean | undefined;\n /**\n * Whether a column's header may be dragged into the group-by bar to add\n * it to the grouping, unless a column says otherwise. Independent of\n * `groupableColumns`: a column can be groupable via its header's\n * click/keyboard toggle, via this drag, both, or neither.\n */\n groupByDraggableColumns?: boolean | undefined;\n /** How the group-by bar's visibility follows the active grouping. */\n groupByBarVisibility?: GroupByBarVisibility | undefined;\n /** The group-by stack to start with, outer to inner. Uncontrolled. */\n defaultGroupBy?: GroupByState | undefined;\n /**\n * Called once when the user changes the group-by stack — adding, removing,\n * or reordering a level.\n */\n onGroupByChange?: ((event: GroupByEvent) => void) | undefined;\n /** Group keys collapsed to start with — every other group starts expanded. Uncontrolled. */\n defaultGroupExpansion?: GroupExpansionState | undefined;\n /** Called once when the user expands or collapses a group, or every group at once. */\n onGroupExpansionChange?: ((event: GroupExpansionEvent) => void) | undefined;\n /** The filter to start with — every applied entry, ANDed together. Uncontrolled. */\n defaultFilter?: FilterState<Row> | undefined;\n /**\n * Whether the grid's rows are split into pages. A page's unit is a\n * top-level group or a bare data row, never a leaf row — a group is never\n * split across a page boundary. Off by default, matching `sortableColumns`.\n */\n paginated?: boolean | undefined;\n /**\n * The page and page size to start on. Uncontrolled. Defaults to\n * `{ pageIndex: 0, pageSize: 25 }` when `paginated` is on and this is\n * omitted.\n */\n defaultPagination?: PaginationState | undefined;\n /** Presentation options for the built-in pager. */\n pager?: PagerConfig | undefined;\n /** Called once when the user changes the page or the page size. */\n onPaginationChange?: ((event: PaginationChangeEvent) => void) | undefined;\n /**\n * Aggregates to compute — a subtotal per group (rendered in that group's\n * header) plus a grand total over the whole filtered/grouped dataset\n * (rendered in a footer). Always computed over every row, never scoped to\n * the current page. A plain controlled prop, unlike `sort`/`filter`/\n * `groupBy`/`pagination`: there is no built-in UI for a user to add or\n * remove an aggregate interactively, so there is no `defaultAggregates`/\n * `onAggregatesChange` pair to go with it.\n */\n aggregates?: AggregateState<Row> | undefined;\n /**\n * Where a group's own aggregate results render. `\"inline\"` (the default)\n * keeps them as text in the group header, next to its leaf-row count.\n * `\"row\"` instead renders a dedicated row after that group's last visible\n * entry, with each aggregate's value in the `<td>` for its own column —\n * the same alignment the grand-total footer's own cells have. Has no\n * effect when `aggregates` is empty or omitted.\n */\n groupAggregateDisplay?: GroupAggregateDisplay | undefined;\n /**\n * The grid's accessible name, announced when it takes focus. A grid without\n * one is read only as \"grid\", which says nothing about which grid.\n */\n label?: string | undefined;\n /**\n * The id of an element naming the grid, for a heading already on the page.\n * Takes precedence over `label`, as `aria-labelledby` does.\n */\n labelledBy?: string | undefined;\n /** Imperative handle for reading live grid state and triggering actions. */\n ref?: Ref<DataGridApi<Row>> | undefined;\n}\n\nexport function DataGridComponent<Row>({\n dataSource,\n columns,\n getRowId,\n borders,\n hoverable,\n selectable,\n defaultRowSelection,\n defaultColumnSelection,\n defaultCellSelection,\n resizableColumns = false,\n reorderableColumns = false,\n resizeMode = \"fit\",\n defaultColumnSizing,\n defaultColumnOrder,\n columnSizeDefaults,\n onColumnResize,\n onColumnOrderChange,\n sortableColumns = false,\n defaultColumnSort,\n onColumnSortChange,\n groupableColumns = false,\n groupToggleIconColumns = true,\n groupByDraggableColumns = false,\n groupByBarVisibility = \"auto\",\n defaultGroupBy,\n onGroupByChange,\n defaultGroupExpansion,\n onGroupExpansionChange,\n defaultFilter,\n paginated = false,\n defaultPagination,\n pager,\n onPaginationChange,\n aggregates,\n groupAggregateDisplay = \"inline\",\n label,\n labelledBy,\n ref,\n ...callbacks\n}: DataGridProps<Row>) {\n const hoverRows = hoverable?.rows ?? true;\n const hoverColumns = hoverable?.columns ?? true;\n const hoverCells = hoverable?.cells ?? true;\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const viewportWidth = useElementWidth(viewportRef, resizeMode === \"fit\");\n const subscribersRef = useRef(new Set<() => void>());\n const [sizing, setSizing] = useState<ColumnSizingState>(\n defaultColumnSizing ?? {},\n );\n const [order, setOrder] = useState<ColumnOrderState>(\n defaultColumnOrder ?? [],\n );\n const [sort, setSort] = useState<ColumnSortState>(defaultColumnSort ?? []);\n const [groupBy, setGroupBy] = useState<GroupByState>(defaultGroupBy ?? []);\n const [expansion, setExpansion] = useState<GroupExpansionState>(\n defaultGroupExpansion ?? [],\n );\n const [filter] = useState<FilterState<Row>>(defaultFilter ?? []);\n const [pagination, setPagination] = useState<PaginationState>(\n defaultPagination ?? { pageIndex: 0, pageSize: DEFAULT_PAGE_SIZE },\n );\n const [announcement, setAnnouncement] = useState(\"\");\n const [rowSelection, setRowSelection] = useState<SelectionState>(\n defaultRowSelection ?? [],\n );\n const [columnSelection, setColumnSelection] = useState<SelectionState>(\n defaultColumnSelection ?? [],\n );\n const [cellSelection, setCellSelection] = useState<CellSelectionState>(\n defaultCellSelection ?? null,\n );\n\n /**\n * The rows as rendered, each carrying the id everything downstream keys it\n * by. Resolved once here rather than per consumer so a row's id cannot come\n * out differently in two places — the same reason `resolveColumnWidths` runs\n * once ahead of the header and the body.\n *\n * An array rather than a map keyed by id: two rows given the same id is a\n * caller's mistake, and one that should render twice and look wrong rather\n * than silently lose a row.\n */\n const rows = useMemo<readonly ResolvedRow<Row>[]>(\n () =>\n dataSource?.map((row, rowIndex) => ({\n rowId: resolveRowId(row, rowIndex, getRowId),\n row,\n rowIndex,\n datasetIndex: rowIndex,\n })) ?? [],\n [dataSource, getRowId],\n );\n\n const definedColumns = useMemo<readonly ColumnDefinition<Row>[]>(() => {\n if (columns && columns.length !== 0) return columns;\n if (dataSource && dataSource.length > 0)\n return defineColumnsFromRows(dataSource);\n return [];\n }, [columns, dataSource]);\n\n /**\n * Ahead of sizing, so everything downstream reads one already-ordered list\n * and no part of the grid has to know a reorder happened.\n */\n const orderedColumns = useMemo(\n () => applyColumnOrder(definedColumns, order),\n [definedColumns, order],\n );\n\n /**\n * Auto-fit is a derivation rather than a write back into `sizing`, so that a\n * `width` set in a column definition is never overwritten and the effect\n * cannot chase its own output. `\"fixed\"` is then simply the absence of it.\n */\n const resolved = useMemo(() => {\n const widths = resolveColumnWidths(orderedColumns, sizing, {\n sizes: columnSizeDefaults,\n resizable: resizableColumns,\n reorderable: reorderableColumns,\n groupByDraggable: groupByDraggableColumns,\n });\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults)\n : widths;\n }, [\n orderedColumns,\n sizing,\n resizeMode,\n viewportWidth,\n columnSizeDefaults,\n resizableColumns,\n reorderableColumns,\n groupByDraggableColumns,\n ]);\n\n /**\n * `rows`, filtered then sorted — needs `resolved` for each column's\n * `field` and `type`, so it runs after sizing rather than alongside\n * `rows` itself. Everything downstream that renders or interacts with row\n * order and membership reads this rather than `rows`, so what the user\n * sees, filters, sorts, and clicks all agree.\n */\n const shownRows = useMemo(\n () => resolveShownRows(rows, filter, sort, resolved),\n [rows, filter, sort, resolved],\n );\n\n /**\n * `shownRows` regrouped into `groupBy` — group headers interleaved with\n * data rows, in render order. `GridBody` renders this rather than\n * `shownRows` directly, grouped or not: `groupRows` returns `shownRows`\n * itself, untouched, when `groupBy` is empty, so an ungrouped grid pays\n * only the cost of that check.\n */\n const displayRows = useMemo(\n () => groupRows(shownRows, groupBy, expansion, resolved),\n [shownRows, groupBy, expansion, resolved],\n );\n\n const activeAggregates = aggregates ?? (NO_AGGREGATES as AggregateState<Row>);\n\n /**\n * `displayRows` with each group header's `aggregates` field set — always\n * ahead of pagination, so a subtotal is computed over a group's full\n * dataset-wide leaf set rather than only the rows a page happens to show.\n * `groupAggregateDisplay: \"row\"` additionally inserts a summary row after\n * each group's last visible entry. `withGroupAggregates` returns\n * `displayRows` itself, untouched, when no aggregates are active, so an\n * aggregate-less grid pays only that check.\n */\n const aggregatedRows = useMemo(\n () =>\n withGroupAggregates(\n displayRows,\n shownRows,\n groupBy,\n activeAggregates,\n resolved,\n groupAggregateDisplay,\n ),\n [\n displayRows,\n shownRows,\n groupBy,\n activeAggregates,\n resolved,\n groupAggregateDisplay,\n ],\n );\n\n /**\n * The grand total: every aggregate over the whole filtered/sorted dataset,\n * ungrouped — independent of `aggregatedRows`, which only ever attaches\n * results to group headers. Recomputed from `shownRows` directly rather\n * than derived from any per-group result, for the same reason a nested\n * group's own subtotal is: a non-associative custom aggregate would be\n * wrong if combined from parts instead of the full set.\n */\n const grandTotal = useMemo<AggregateResults>(\n () =>\n computeAggregates(\n shownRows.map((entry) => entry.row),\n activeAggregates,\n resolved,\n ),\n [shownRows, activeAggregates, resolved],\n );\n\n /**\n * `aggregatedRows` windowed to the current page — always last in the\n * pipeline, after grouping and aggregation, so a page never splits a\n * group and a subtotal never changes value depending on which page is\n * showing. `GridBody` renders this rather than `aggregatedRows` directly,\n * paginated or not: when `paginated` is off the grid is a single page\n * over every row, and `pageCount`/`pageIndex` report that (`1`/`0`)\n * rather than the possibly-stale values a consumer's own `pagination`\n * prop state might otherwise carry.\n */\n const paginatedRows = useMemo(\n () =>\n paginated\n ? paginateRows(aggregatedRows, pagination)\n : { rows: aggregatedRows, pageCount: 1, pageIndex: 0 },\n [paginated, aggregatedRows, pagination],\n );\n\n /**\n * Cached rather than built fresh on every `getPagination()` call: a\n * `useSyncExternalStore`-based hook's `getSnapshot` must return a\n * referentially stable value when nothing changed, or React warns/loops.\n */\n const paginationSnapshot = useMemo<PaginationState>(\n () => ({\n pageIndex: paginatedRows.pageIndex,\n pageSize: pagination.pageSize,\n }),\n [paginatedRows.pageIndex, pagination.pageSize],\n );\n\n /**\n * `paginatedRows.rows` narrowed back to its data rows, in the same\n * (possibly regrouped, possibly paginated) order — what row/cell selection\n * anchors its range-select against, so that a Shift-click spans the rows\n * actually adjacent on screen rather than their pre-grouping,\n * pre-pagination order. A group collapsed at selection time, or a row on a\n * different page, contributes no rows here at all, so a range spanning its\n * position includes only what was visible when the range was drawn.\n */\n const displayDataRows = useMemo(\n () =>\n groupBy.length === 0 && !paginated\n ? shownRows\n : paginatedRows.rows.filter(\n (entry): entry is ResolvedRow<Row> => !(\"kind\" in entry),\n ),\n [paginatedRows, groupBy.length, paginated, shownRows],\n );\n\n /**\n * What a column is called in an announcement. `label` carries whatever a\n * `headerTemplate` returned, which need not be text at all, so the field\n * path stands in whenever it is not.\n */\n function columnName(columnId: string): string {\n const entry = resolved.find((candidate) => candidate.id === columnId);\n if (entry === undefined) {\n return columnId;\n }\n return typeof entry.label === \"string\" ? entry.label : entry.column.field;\n }\n\n /**\n * Reports a change no visual cue can carry to a screen reader. Held as state\n * rather than written to the DOM directly so React owns the one element the\n * live region watches.\n */\n function announce(message: string): void {\n setAnnouncement(message);\n }\n\n /**\n * Wrapped rather than announced from the resize hook, which reports the\n * continuous `\"move\"` phase as well — a live region given every frame of a\n * drag says nothing an assistive technology can keep up with.\n */\n function handleColumnResize(event: ColumnResizeEvent): void {\n onColumnResize?.(event);\n if (event.phase === \"end\") {\n announce(\n `${columnName(event.columnId)}, ${String(Math.round(event.width))} pixels wide`,\n );\n }\n }\n\n const resize = useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize: handleColumnResize,\n });\n\n /** Wrapped the same way `handleColumnResize` is, for its own announcement. */\n function handleGroupByChange(event: GroupByEvent): void {\n onGroupByChange?.(event);\n const entry = event.groupBy.find(\n (candidate) => candidate.columnId === event.columnId,\n );\n if (entry === undefined) {\n announce(`${columnName(event.columnId)}, grouping removed`);\n return;\n }\n announce(\n event.groupBy.length > 1\n ? `Grouped by ${columnName(event.columnId)}, level ${String(event.groupBy.indexOf(entry) + 1)} of ${String(event.groupBy.length)}`\n : `Grouped by ${columnName(event.columnId)}`,\n );\n }\n\n /**\n * `groupId: null` marks `expandAll`/`collapseAll`, which touch every group\n * in one call rather than one at a time — announced as a single summary\n * instead of naming a group that doesn't apply.\n */\n function handleGroupExpansionChange(event: GroupExpansionEvent): void {\n onGroupExpansionChange?.(event);\n if (event.groupId === null) {\n announce(\n event.expansion.length === 0\n ? \"All groups expanded\"\n : \"All groups collapsed\",\n );\n return;\n }\n announce(\n event.expansion.includes(event.groupId)\n ? \"Group collapsed\"\n : \"Group expanded\",\n );\n }\n\n /**\n * Constructed ahead of `handleDrop`/`drag` below (rather than alongside\n * `columnSort`, its closest sibling) because `handleDrop`'s `\"group-by\"`\n * arm calls `grouping.moveGroupBy` directly.\n */\n const grouping = useRowGrouping<Row>({\n groupBy,\n setGroupBy,\n expansion,\n setExpansion,\n onGroupByChange: handleGroupByChange,\n onGroupExpansionChange: handleGroupExpansionChange,\n });\n\n const nav = useGridNavigation({\n tableRef,\n // Group headers are addressable rows too — the whole point of the flat\n // `DisplayRow[]` shape is that they share one position space with data\n // rows, so navigation counts them the same way. Page-relative\n // (`paginatedRows`, not `displayRows`): arrow keys operate on what's\n // actually in the DOM, which is the current page — a different \"page\"\n // concept than `useGridNavigation`'s own Page Up/Down viewport scrolling.\n rowCount: paginatedRows.rows.length,\n columnCount: resolved.length,\n // A group's own summary row (`groupAggregateDisplay: \"row\"`) occupies a\n // real slot in `rowCount` above — its DOM position has to line up with\n // everything else — but is presentational, never a tab stop: arrow-key\n // vertical movement steps over it rather than landing there.\n isSkippableRow: (rowIndex) => {\n const entry = paginatedRows.rows[rowIndex];\n return (\n entry !== undefined && \"kind\" in entry && entry.kind === \"group-summary\"\n );\n },\n });\n\n /**\n * The ids as displayed, which a drop is expressed against — the order state\n * starts empty and may name only some columns, so moving against it directly\n * would have nothing to rearrange.\n */\n const displayedIds = useMemo(\n () => orderedColumns.map((column) => column.id ?? column.field),\n [orderedColumns],\n );\n\n /** Column ids whose header may be dragged into the group-by bar at all. */\n const groupByDraggableIds = useMemo(\n () =>\n new Set(\n resolved\n .filter((entry) => entry.groupByDraggable)\n .map((entry) => entry.id),\n ),\n [resolved],\n );\n\n /**\n * The one place a drop is applied — the two-armed switch on `target.kind`\n * the group-by bar's own second drop zone was always going to need.\n */\n function handleDrop(target: DropTarget, movedId: string): void {\n if (target.kind === \"group-by\") {\n // Already announced: `grouping.moveGroupBy` commits through the same\n // `onGroupByChange` pipeline the header toggle and the bar's own chip\n // drag do, so this needs no announcement or focus-follow of its own —\n // unlike a column-order drop, the moved thing leaves the grid's single\n // tab-stop system entirely for the bar's own independently-focusable\n // chips, which have no shared index to update.\n grouping.moveGroupBy(movedId, target.beforeColumnId);\n return;\n }\n\n const next = moveColumnBefore(displayedIds, movedId, target.beforeId);\n // `moveColumnBefore` hands back the same reference for a move that changes\n // nothing, so a drop in place neither renders nor reports.\n if (next === displayedIds) {\n return;\n }\n const position = next.indexOf(movedId);\n setOrder(next);\n onColumnOrderChange?.({ columnId: movedId, order: next });\n announce(\n `${columnName(movedId)}, column ${String(position + 1)} of ${String(next.length)}`,\n );\n /**\n * The tab stop travels with the column. React reorders the headers by key,\n * so the browser's focus stays on the moved one by itself — without this\n * the stop would be left on whichever column took its index, and the next\n * arrow key would appear to do nothing.\n */\n nav.focusCell(HEADER_ROW, position);\n }\n\n const drag = useColumnDrag<Row>({\n order: displayedIds,\n groupBy,\n groupByDraggableIds,\n onDrop: handleDrop,\n });\n\n /** Whether the header drag currently open (if any) is for a column already in the group-by stack — reordering it is the chip's job, so dragging it back in is never a valid target. */\n const draggedColumnAlreadyGrouped =\n drag.draggedColumnId !== null &&\n groupBy.some((entry) => entry.columnId === drag.draggedColumnId);\n\n /**\n * Whether the drag currently open (if any) could land on the group-by bar\n * — the signal `groupByBarVisibility=\"auto\"` needs to show the bar as a\n * drop target even while `groupBy` is still empty. Depends only on\n * `draggedColumnId` (set once the drag opens), the static\n * `groupByDraggableIds`, and whether that column is already grouped, never\n * the pointer's current position, so the bar mounts for the drag's whole\n * duration rather than flickering in only while directly hovering it.\n */\n const dragEligibleForGroupBy =\n drag.draggedColumnId !== null &&\n groupByDraggableIds.has(drag.draggedColumnId) &&\n !draggedColumnAlreadyGrouped;\n\n const showGroupByBar =\n groupByBarVisibility === \"always\" ||\n (groupByBarVisibility === \"auto\" &&\n (groupBy.length > 0 || dragEligibleForGroupBy));\n\n const headerGroupByDropTarget =\n drag.dropTarget?.kind === \"group-by\" ? drag.dropTarget : null;\n\n /**\n * Wrapped the same way `handleColumnResize`/`handleDrop` are, so a toggle,\n * a stack, or a clear back to \"none\" each get their own announcement.\n */\n function handleColumnSortChange(event: ColumnSortEvent): void {\n onColumnSortChange?.(event);\n const entry = event.sort.find(\n (candidate) => candidate.columnId === event.columnId,\n );\n if (entry === undefined) {\n announce(`${columnName(event.columnId)}, sort cleared`);\n return;\n }\n const direction = entry.direction === \"asc\" ? \"ascending\" : \"descending\";\n announce(\n event.sort.length > 1\n ? `${columnName(event.columnId)} sorted ${direction}, key ${String(event.sort.indexOf(entry) + 1)} of ${String(event.sort.length)}`\n : `${columnName(event.columnId)} sorted ${direction}`,\n );\n }\n\n const columnSort = useColumnSort<Row>({\n sort,\n setSort,\n onColumnSortChange: handleColumnSortChange,\n });\n\n /** Wrapped the same way `handleColumnSortChange` is, for its own announcement. */\n function handlePaginationChange(event: PaginationChangeEvent): void {\n onPaginationChange?.(event);\n announce(\n `Page ${String(event.pagination.pageIndex + 1)} of ${String(event.pageCount)}`,\n );\n }\n\n const paginationApi = usePagination<Row>({\n pagination,\n setPagination,\n rows: displayRows,\n onPaginationChange: handlePaginationChange,\n });\n\n /**\n * A user looking at page 7 of a result that filtering, sorting, or\n * regrouping just shrank to 2 pages must not be silently stranded on an\n * empty page — reset to the first page whenever any of the three change.\n *\n * Adjusted during render (React's own pattern for \"state changed, derive a\n * reset\" — see https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)\n * rather than in a `useEffect`, which would `setState` a render after the\n * change already committed and paint the stale page for one frame. A\n * plain `setPagination` rather than `pager.goToPage(0)`: this is a\n * consequence of another change, not a page navigation of its own, and so\n * reports no `onPaginationChange` of its own either — the filter/sort/\n * group change's own callback already covers it.\n */\n const [previous, setPrevious] = useState({ filter, sort, groupBy });\n if (\n previous.filter !== filter ||\n previous.sort !== sort ||\n previous.groupBy !== groupBy\n ) {\n setPrevious({ filter, sort, groupBy });\n if (pagination.pageIndex !== 0) {\n setPagination({ ...pagination, pageIndex: 0 });\n }\n }\n\n const selection = useGridSelection<Row>({\n rows: displayDataRows,\n columns: resolved,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n columnName,\n });\n\n const multiselectable =\n selection.rowMode === \"multiple\" || selection.columnMode === \"multiple\";\n\n /**\n * Deps list every getter's own backing value, not threaded through each\n * individual `commitIfChanged`/`setState` call site across the various\n * `use*` hooks above. Several of those bypass `commitIfChanged` on\n * purpose (pagination's own filter/sort/group-triggered page reset,\n * `useColumnResize`'s drag-move phase, `useGroupByDrag`/`useColumnDrag`'s\n * transient drag state) or don't use it at all, so threading a `notify()`\n * through each call site individually is real surface area to get wrong\n * and silently miss a spot. Listing every value here instead means any\n * future getter just needs adding to this array, not a new call site.\n *\n * A plain no-deps effect (fire after every render, let each `listener`'s\n * own `useSyncExternalStore` reference-equality check filter out the\n * no-op ones) looks equivalent but isn't: `useSyncExternalStore` schedules\n * a re-render *before* that bail-out check runs, not after, so notifying\n * on a render that changed nothing here still forces the subscribing\n * component to re-render — and if that component also renders this same\n * `DataGridComponent` as a plain (non-memoized) sibling, its own re-render\n * re-runs this very effect, forever, even though no value below ever\n * actually changes. Gating on the dependency array is what breaks that\n * cycle, not the listener-side check.\n */\n useEffect(() => {\n for (const listener of subscribersRef.current) {\n listener();\n }\n }, [\n shownRows,\n aggregatedRows,\n resolved,\n sizing,\n order,\n sort,\n groupBy,\n expansion,\n paginationSnapshot,\n paginatedRows.pageCount,\n grandTotal,\n rowSelection,\n columnSelection,\n cellSelection,\n nav.focus,\n ]);\n\n /**\n * No deps array: `nav`, `selection`, `resize`, and `drag` are all freshly\n * constructed every render (none of those hooks memoize their returned\n * API), so the handle has to be rebuilt every render too or its closures\n * would go stale.\n */\n useImperativeHandle(ref, () => ({\n get element() {\n return viewportRef.current;\n },\n get table() {\n return tableRef.current;\n },\n getRows: () => shownRows,\n // `aggregatedRows`, not the plain `displayRows` it's derived from: the\n // same array shape and content, except every group header's own\n // `aggregates` field is populated — the whole reason `getDisplayRows()`\n // is where a consumer reads a specific group's computed results from.\n getDisplayRows: () => aggregatedRows,\n getColumns: () => resolved,\n getColumnSizing: () => sizing,\n getColumnOrder: () => order,\n getColumnSort: () => sort,\n getGroupBy: () => groupBy,\n getGroupExpansion: () => expansion,\n getPagination: () => paginationSnapshot,\n getPageCount: () => paginatedRows.pageCount,\n getAggregates: () => grandTotal,\n getRowSelection: () => rowSelection,\n getColumnSelection: () => columnSelection,\n getCellSelection: () => cellSelection,\n getFocusedCell: () => nav.focus,\n focusCell: nav.focusCell,\n clearSelection: selection.clear,\n selectAllRows: selection.selectAllRows,\n expandAllGroups: grouping.expandAll,\n collapseAllGroups: () => {\n grouping.collapseAll(displayRows);\n },\n goToPage: paginationApi.goToPage,\n nextPage: paginationApi.nextPage,\n previousPage: paginationApi.previousPage,\n setPageSize: paginationApi.setPageSize,\n scrollToRow: (rowId, options) => {\n // `paginatedRows.rows`, not `displayRows`: a data row's DOM position is\n // its place in the currently rendered page — with grouping active,\n // that's its place in the grouped, flattened output; with pagination\n // also active, that's the page's own slice of it. A row on a different\n // page isn't in the DOM at all, so there is nothing to scroll to.\n const index = paginatedRows.rows.findIndex(\n (entry) => !(\"kind\" in entry) && entry.rowId === rowId,\n );\n if (index === -1) return;\n tableRef.current?.tBodies[0]?.rows[index]?.scrollIntoView(options);\n },\n scrollToColumn: (columnId, options) => {\n const cells = tableRef.current?.querySelectorAll(\"[data-gridkit-column]\");\n const cell = cells\n ? Array.from(cells).find(\n (entry) => entry.getAttribute(\"data-gridkit-column\") === columnId,\n )\n : undefined;\n cell?.scrollIntoView(options);\n },\n subscribe: (listener) => {\n subscribersRef.current.add(listener);\n return () => {\n subscribersRef.current.delete(listener);\n };\n },\n }));\n\n return (\n <div className=\"gridkit-data-grid-viewport\" ref={viewportRef}>\n {showGroupByBar && (\n <GroupByBar<Row>\n columns={resolved}\n grouping={grouping}\n columnName={columnName}\n headerDragEligible={dragEligibleForGroupBy}\n headerDragBlocked={draggedColumnAlreadyGrouped}\n headerDropTarget={headerGroupByDropTarget}\n />\n )}\n <table\n ref={tableRef}\n /*\n * `role=\"grid\"` rather than the table's own semantics: it is what makes\n * the arrow keys a navigation the grid owns, and later what lets a row\n * report whether it is selected. It obliges the single tab stop\n * `useGridNavigation` keeps.\n *\n * Switches to `\"treegrid\"` — the WAI-ARIA pattern for expandable,\n * collapsible rows — whenever `groupBy` is non-empty, rather than\n * committing to it unconditionally. The alternative (always\n * `treegrid`) would change what every existing, ungrouped consumer\n * announces to assistive technology the moment this feature shipped;\n * that regression is certain, while the edge case this trades away —\n * the role flipping mid-session if a consumer removes its last\n * group-by level — is rare and, per the WAI-ARIA grid pattern, still\n * a valid `role` change to make when the row structure itself\n * changes shape. See the \"Scope note\" this mirrors: grouping stays\n * an internal detail for an ungrouped grid, ARIA role included.\n */\n role={groupBy.length > 0 ? \"treegrid\" : \"grid\"}\n // The header is a row too, and counted from one; group headers (and,\n // under `groupAggregateDisplay: \"row\"`, each group's own summary\n // row) count as rows here too, the same way they do in `nav`'s\n // `rowCount`. `aggregatedRows`, not `displayRows`: the latter is\n // pre-aggregation and never carries summary rows at all. Total\n // dataset count, not the current page's — neither array is ever\n // windowed to one page, so this stays the true row count per the\n // WAI-ARIA grid pattern even while paged.\n aria-rowcount={aggregatedRows.length + 1}\n aria-colcount={resolved.length}\n {...ariaAttr(multiselectable, \"aria-multiselectable\", true)}\n {...ariaAttr(labelledBy !== undefined, \"aria-labelledby\", labelledBy)}\n {...ariaAttr(\n labelledBy === undefined && label !== undefined,\n \"aria-label\",\n label,\n )}\n onKeyDown={(event) => {\n /*\n * The two keys that address the grid rather than a cell, and so are\n * caught here where everything bubbles to rather than in each of\n * them.\n */\n if (event.key === \"Escape\") {\n // A gesture in flight has its own use for Escape — cancelling —\n // and gets it first.\n if (drag.draggedColumnId !== null || resize.activeColumnId !== null)\n return;\n selection.clear();\n return;\n }\n if (\n (event.ctrlKey || event.metaKey) &&\n (event.key === \"a\" || event.key === \"A\")\n ) {\n // Left to the browser unless the grid has something to do with it,\n // so a grid without multiple rows does not swallow select-all.\n if (selection.rowMode !== \"multiple\") return;\n event.preventDefault();\n selection.selectAllRows();\n }\n }}\n // Widths are only honoured exactly when the table is as wide as its\n // columns; at `100%` the fixed layout redistributes the difference.\n style={{ width: totalColumnWidth(resolved) }}\n className={classNames(\n \"gridkit-data-grid\",\n borders ? `borders-${borders}` : \"\",\n // Hover is on by default and selection off, so one set of classes\n // turns styling off and the other turns it on. The polarity differs\n // because the defaults do.\n hoverRows ? \"\" : \"no-hover-rows\",\n hoverColumns ? \"\" : \"no-hover-columns\",\n hoverCells ? \"\" : \"no-hover-cells\",\n selection.rowMode === false ? \"\" : \"selectable-rows\",\n selection.columnMode === false ? \"\" : \"selectable-columns\",\n selection.cellMode === false ? \"\" : \"selectable-cells\",\n )}\n >\n <colgroup>\n {resolved.map((entry) => (\n <col key={entry.id} style={{ width: entry.width }} />\n ))}\n </colgroup>\n <GridHeader<Row>\n columns={resolved}\n resize={resize}\n drag={drag}\n sort={columnSort}\n sortableColumns={sortableColumns}\n grouping={grouping}\n groupableColumns={groupableColumns}\n groupToggleIconColumns={groupToggleIconColumns}\n nav={nav}\n selection={selection}\n />\n <GridBody<Row>\n columns={resolved}\n rows={paginatedRows.rows}\n activeColumnId={resize.activeColumnId}\n nav={nav}\n selection={selection}\n grouping={grouping}\n aggregates={activeAggregates}\n groupAggregateDisplay={groupAggregateDisplay}\n />\n {activeAggregates.length > 0 && (\n <GridFooter<Row>\n columns={resolved}\n aggregates={activeAggregates}\n results={grandTotal}\n rows={shownRows.map((entry) => entry.row)}\n />\n )}\n </table>\n {paginated &&\n (pager?.template ? (\n pager.template({\n pagination: paginationApi.pagination,\n currentPage: paginationApi.currentPage,\n pageCount: paginationApi.pageCount,\n pageSizeOptions: pager.sizeOptions,\n goToPage: paginationApi.goToPage,\n nextPage: paginationApi.nextPage,\n previousPage: paginationApi.previousPage,\n setPageSize: paginationApi.setPageSize,\n })\n ) : (\n <GridPager pager={paginationApi} config={pager} />\n ))}\n {/*\n * Outside the table, which admits no `div`, and polite so it waits for a\n * pause rather than cutting across what the user is already hearing.\n */}\n <div className=\"gridkit-sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </div>\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { buildKeyShortcuts, intentOf, KEYBOARD_STEP } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { ariaAttr } from \"../ariaAttr\";\nimport { classNames } from \"../classNames\";\nimport type { ColumnDragApi } from \"../useColumnDrag\";\nimport type { ColumnResizeApi } from \"../useColumnResize\";\nimport type { ColumnSortApi } from \"../useColumnSort\";\nimport { HEADER_ROW, type GridNavigationApi } from \"../useGridNavigation\";\nimport {\n keyboardSelectIntent,\n type GridSelectionApi,\n} from \"../useGridSelection\";\nimport type { RowGroupingApi } from \"../useRowGrouping\";\n\ninterface GridHeaderProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n resize: ColumnResizeApi<Row>;\n drag: ColumnDragApi<Row>;\n sort: ColumnSortApi<Row>;\n sortableColumns: boolean;\n grouping: RowGroupingApi<Row>;\n groupableColumns: boolean;\n groupToggleIconColumns: boolean;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n}\n\n/** The common attributes behind every icon here — just the `<path>`s differ. */\nfunction Icon({ children }: { children: ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n {children}\n </svg>\n );\n}\n\n/**\n * The two glyphs a sort toggle shows: a neutral hint before a column has a\n * direction, and a single chevron reused for both directions once it does —\n * `theme-tailwind` rotates it 180° for `desc` rather than swapping icons.\n */\nfunction ChevronsUpDownIcon() {\n return (\n <Icon>\n <path d=\"m7 15 5 5 5-5\" />\n <path d=\"m7 9 5-5 5 5\" />\n </Icon>\n );\n}\n\nfunction ChevronUpIcon() {\n return (\n <Icon>\n <path d=\"m18 15-6-6-6 6\" />\n </Icon>\n );\n}\n\n/** Three stacked panes, standing in for \"group by this column\". */\nfunction GroupIcon() {\n return (\n <Icon>\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"8.5\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\" />\n </Icon>\n );\n}\n\nexport default function GridHeader<Row>({\n columns,\n resize,\n drag,\n sort,\n sortableColumns,\n grouping,\n groupableColumns,\n groupToggleIconColumns,\n nav,\n selection,\n}: GridHeaderProps<Row>) {\n // Only meaningful for the \"column-order\" branch — a drop headed for the\n // group-by bar instead (`kind: \"group-by\"`) draws no indicator here at\n // all; `GroupByBar` draws its own from the same `drag.dropTarget`.\n const beforeId =\n drag.dropTarget?.kind === \"column-order\"\n ? drag.dropTarget.beforeId\n : undefined;\n const draggedEntry =\n columns.find((entry) => entry.id === drag.draggedColumnId) ?? null;\n\n return (\n <thead>\n <tr className=\"grid-header\" role=\"row\" aria-rowindex={1}>\n {columns.map((entry, index) => {\n const { column } = entry;\n const resizing = resize.activeColumnId === entry.id;\n const dragging = drag.draggedColumnId === entry.id;\n\n /**\n * Drawn on the gap's own edge, so the one gap between two columns is\n * marked once. No guard against the dragged column: the hook reports\n * only gaps that would move it.\n */\n const dropBefore = beforeId !== undefined && beforeId === entry.id;\n const dropAfter = beforeId === null && index === columns.length - 1;\n const selected = selection.selectedColumnIds.has(entry.id);\n const sortable = column.sortable ?? sortableColumns;\n const sortDirection = sort.directionFor(entry.id);\n const sortPriority = sort.priorityFor(entry.id);\n const groupable = column.groupable ?? groupableColumns;\n // Purely a rendering choice — see the prop's own doc comment. Never\n // gates `groupable` itself, `aria-keyshortcuts`, or `Alt+ArrowDown`.\n const showGroupToggleIcon =\n column.groupToggleIcon ?? groupToggleIconColumns;\n const isGrouped = grouping.groupBy.some(\n (level) => level.columnId === entry.id,\n );\n\n const shortcuts = buildKeyShortcuts({\n reorderable: entry.reorderable,\n resizable: entry.resizable,\n sortable,\n groupable,\n });\n\n return (\n <th\n key={entry.id}\n scope=\"col\"\n // Explicit, matching `GridRow.tsx`'s `role=\"gridcell\"` on the\n // body `<td>`: both sit inside a `<table role=\"grid\">`, and\n // mixing that non-native ancestor role with descendants that\n // rely on implicit native role mapping is inconsistently\n // resolved across browser/AT combinations.\n role=\"columnheader\"\n data-gridkit-column={entry.id}\n aria-colindex={index + 1}\n tabIndex={nav.tabIndexFor(HEADER_ROW, index)}\n {...ariaAttr(\n selection.columnMode !== false,\n \"aria-selected\",\n selected,\n )}\n onFocus={() => {\n nav.focusCell(HEADER_ROW, index);\n }}\n onClick={(event) => {\n /*\n * A drag ends in a click on the header it started from, and a\n * resize in one on the handle inside it. Neither is the press\n * that selects a column, so both are shown the door here —\n * the drag by the distance it travelled, the resize by where\n * it began.\n */\n if (drag.justDragged()) {\n return;\n }\n if (\n event.target instanceof Element &&\n (event.target.closest(\".header-resize-handle\") !== null ||\n event.target.closest(\".header-sort-toggle\") !== null ||\n event.target.closest(\".header-group-toggle\") !== null)\n ) {\n return;\n }\n selection.selectColumn(entry.id, intentOf(event));\n }}\n onKeyDown={(event) => {\n const horizontal =\n event.key === \"ArrowLeft\" || event.key === \"ArrowRight\";\n const direction = event.key === \"ArrowLeft\" ? -1 : 1;\n\n if (horizontal && event.ctrlKey && entry.reorderable) {\n event.preventDefault();\n drag.moveByKeyboard(entry, direction);\n return;\n }\n if (horizontal && event.altKey && entry.resizable) {\n event.preventDefault();\n resize.nudge(entry, direction * KEYBOARD_STEP);\n return;\n }\n // The keyboard equivalent of double-clicking the resize\n // handle, which auto-fits the column to its content.\n if (event.key === \"Enter\" && event.altKey && entry.resizable) {\n event.preventDefault();\n resize.sizeToContent(entry);\n return;\n }\n if (event.key === \"ArrowUp\" && event.altKey && sortable) {\n event.preventDefault();\n sort.toggle(entry, { shiftKey: event.shiftKey });\n return;\n }\n if (event.key === \"ArrowDown\" && event.altKey && groupable) {\n event.preventDefault();\n grouping.toggleGroupBy(entry.id);\n return;\n }\n // Space builds a selection up and Enter replaces it, as in the\n // body. Taken either way, or Space scrolls the grid away.\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n selection.selectColumn(\n entry.id,\n intentOf(keyboardSelectIntent(event)),\n );\n return;\n }\n nav.onKeyDown(event);\n }}\n className={classNames(\n \"header-cell\",\n // The grab affordance a header showing either drag\n // destination shares — a column dragged only for grouping\n // (`groupByDraggable` without `reorderable`) grabs the same\n // way one dragged only for reordering does.\n entry.reorderable || entry.groupByDraggable\n ? \"is-reorderable\"\n : \"\",\n selected ? \"is-selected\" : \"\",\n resizing ? \"is-resizing\" : \"\",\n dragging ? \"is-dragging\" : \"\",\n dropBefore ? \"is-drop-before\" : \"\",\n dropAfter ? \"is-drop-after\" : \"\",\n column.wrap?.header ? \"is-wrapped\" : \"\",\n column.headerClassName ?? \"\",\n )}\n {...ariaAttr(shortcuts !== \"\", \"aria-keyshortcuts\", shortcuts)}\n {...ariaAttr<\"aria-sort\", \"ascending\" | \"descending\">(\n sortable && sortDirection !== null,\n \"aria-sort\",\n sortDirection === \"asc\" ? \"ascending\" : \"descending\",\n )}\n {...((entry.reorderable || entry.groupByDraggable) && {\n onPointerDown: (event) => {\n drag.startDrag(entry, event);\n },\n })}\n >\n {groupable && showGroupToggleIcon && (\n /*\n * Inline, before the label, rather than absolutely\n * positioned like the sort toggle and resize handle: those\n * two already share the header's right edge, and a third\n * overlay there would need its own carve-out. Sitting in\n * normal flow costs nothing but a few pixels of label width.\n * A pointer affordance only, same as the other two — the\n * keyboard equivalent is Alt+ArrowDown on the header itself.\n */\n <span\n className={classNames(\n \"header-group-toggle\",\n isGrouped ? \"is-grouped\" : \"\",\n )}\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n // See the sort toggle's own note: otherwise a\n // reorderable header's drag would swallow this click.\n event.stopPropagation();\n }}\n onClick={(event) => {\n event.stopPropagation();\n grouping.toggleGroupBy(entry.id);\n }}\n >\n <GroupIcon />\n </span>\n )}\n {entry.label}\n {sortable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology like the resize handle: the keyboard equivalent\n * lives on the header itself, under Alt+ArrowUp (plain) /\n * Alt+Shift+ArrowUp (stacking).\n */\n <span\n className={classNames(\n \"header-sort-toggle\",\n sortDirection !== null ? `is-sorted-${sortDirection}` : \"\",\n )}\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n /*\n * Otherwise a reorderable header's own `onPointerDown`\n * sees this bubble up and starts a column drag, whose\n * `setPointerCapture` then redirects the click that\n * follows to the `th` — the same reason `startResize`\n * stops it for the resize handle.\n */\n event.stopPropagation();\n }}\n onClick={(event) => {\n sort.toggle(entry, { shiftKey: event.shiftKey });\n }}\n >\n {sortDirection === null ? (\n <ChevronsUpDownIcon />\n ) : (\n <ChevronUpIcon />\n )}\n {sortPriority !== null && sortPriority > 1 && (\n <span className=\"header-sort-priority\">{sortPriority}</span>\n )}\n </span>\n )}\n {entry.resizable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology accordingly: a focusable handle per column would\n * put N tab stops inside a widget that is meant to have one.\n * The keyboard resizes from the header itself, under Alt.\n */\n <span\n className=\"header-resize-handle\"\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n resize.startResize(entry, event);\n }}\n onDoubleClick={() => {\n resize.sizeToContent(entry);\n }}\n />\n )}\n </th>\n );\n })}\n </tr>\n {/*\n * Portalled to the body, and not only because a `div` cannot sit in a\n * `tr`: inside the viewport the overflow that makes the grid scroll\n * would clip it.\n */}\n {draggedEntry !== null &&\n drag.ghostTransform !== null &&\n createPortal(\n <div\n className=\"gridkit-data-grid header-cell drag-ghost\"\n style={{\n width: draggedEntry.width,\n transform: drag.ghostTransform,\n }}\n aria-hidden=\"true\"\n >\n {draggedEntry.label}\n </div>,\n document.body,\n )}\n </thead>\n );\n}\n","/**\n * Collapses the `{...(condition && { \"aria-foo\": value })}` idiom for\n * conditionally including a single ARIA attribute in a JSX spread.\n */\nexport function ariaAttr<K extends string, V>(\n condition: boolean,\n key: K,\n value: V,\n): Record<K, V> | Record<string, never> {\n return condition ? ({ [key]: value } as Record<K, V>) : {};\n}\n","export function classNames(\n ...values: (string | false | null | undefined)[]\n): string {\n return values.filter(Boolean).join(\" \");\n}\n","import {\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\nimport {\n clampFocus,\n nextFocusForKey,\n HEADER_ROW,\n type GridFocus,\n} from \"@gridkitjs/core\";\n\nexport { HEADER_ROW, type GridFocus };\n\n/** Rows a page key moves when the viewport cannot be measured. */\nconst FALLBACK_PAGE = 10;\n\ninterface UseGridNavigationOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n rowCount: number;\n columnCount: number;\n /**\n * Rows the vertical navigation keys step over rather than land a tab stop\n * on — a group's own summary row (`groupAggregateDisplay: \"row\"`), which\n * still occupies a real row slot for `rowCount` purposes but is\n * presentational, not a stop of its own. Left unset (skips nothing) for a\n * grid with no such rows.\n */\n isSkippableRow?: ((rowIndex: number) => boolean) | undefined;\n}\n\nexport interface GridNavigationApi {\n focus: GridFocus;\n /**\n * `0` for the focused cell and `-1` for every other. A grid is one tab stop:\n * tabbing reaches it, and the arrow keys move within it.\n */\n tabIndexFor: (rowIndex: number, columnIndex: number) => 0 | -1;\n /** Moves the tab stop, and the browser's focus with it. */\n focusCell: (rowIndex: number, columnIndex: number) => void;\n /** Handles the navigation keys, leaving every other key to bubble. */\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n}\n\n/**\n * `0` for the column holding the tab stop and `-1` for every other.\n * Standalone rather than reached only through the hook's own `tabIndexFor`,\n * because `GridRow` is `memo()`-wrapped and cannot take the whole `nav`\n * object as a prop without defeating that boundary. Takes the row's own\n * already-narrowed `focusedColumnIndex` (`null` when focus sits on a\n * different row) rather than a `rowIndex`/`GridFocus` pair, since that\n * narrowing — done once per row in `GridBody` — is what keeps a focus move\n * from re-rendering every row instead of the two it actually touches.\n */\nexport function tabIndexFor(\n columnIndex: number,\n focusedColumnIndex: number | null,\n): 0 | -1 {\n return columnIndex === focusedColumnIndex ? 0 : -1;\n}\n\n/**\n * The cell at a coordinate, found through the table's own row and cell\n * collections rather than a selector.\n *\n * Ids can hold anything a consumer's data holds, and an attribute selector\n * built from one would have to escape it; positions need no quoting.\n *\n * `columnIndex` is clamped to the row's own last cell rather than read\n * directly: a group-header row renders one `<td colSpan>` regardless of\n * `columnCount`, so a focus arriving from a data row further right (or a\n * `columnIndex` a keyboard `End` left behind) would otherwise address a cell\n * that row doesn't have.\n */\nfunction cellAt(table: HTMLTableElement, focus: GridFocus): HTMLElement | null {\n const row =\n focus.rowIndex === HEADER_ROW\n ? (table.tHead?.rows[0] ?? null)\n : (table.tBodies[0]?.rows[focus.rowIndex] ?? null);\n if (row === null) {\n return null;\n }\n const columnIndex = Math.min(focus.columnIndex, row.cells.length - 1);\n return row.cells[columnIndex] ?? null;\n}\n\n/**\n * Moves one tab stop around the grid, which is what `role=\"grid\"` obliges:\n * arrow keys travel cell to cell and Tab passes the whole grid by.\n *\n * Separate from selection because focus and selection are different states — a\n * cell is focused while travelling before anything is selected, and every cell\n * of a range is selected without being focused. Navigation also has to work\n * with selection turned off entirely, so it cannot depend on it.\n */\nexport default function useGridNavigation({\n tableRef,\n rowCount,\n columnCount,\n isSkippableRow,\n}: UseGridNavigationOptions): GridNavigationApi {\n const [stored, setStored] = useState<GridFocus>({\n rowIndex: HEADER_ROW,\n columnIndex: 0,\n });\n\n /**\n * Clamped on the way out rather than written back, so that a coordinate\n * pushed out of range by a change to the data is restored when the data\n * comes back — and so the effect below cannot chase its own output.\n * Memoized on the individual coordinates rather than recomputed on every\n * render: `clampFocus` always returns a fresh object, and `getFocusedCell`\n * on `DataGridApi` hands this same value to `useSyncExternalStore`-based\n * hooks, which need a referentially stable snapshot when nothing changed.\n */\n const focus = useMemo(\n () => clampFocus(stored, rowCount, columnCount),\n [stored, rowCount, columnCount],\n );\n\n /**\n * Whether the browser's focus still has to be moved to match. Without it\n * every render would pull focus into the grid, including the first.\n */\n const pending = useRef(false);\n\n useEffect(() => {\n if (!pending.current) {\n return;\n }\n pending.current = false;\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n cellAt(table, { rowIndex: focus.rowIndex, columnIndex: focus.columnIndex })\n // Focusing the cell the browser already sits on is a no-op, which is what\n // makes one method serve both a key press and a cell reporting a click.\n ?.focus();\n }, [tableRef, focus.rowIndex, focus.columnIndex]);\n\n /** How many rows fit the viewport, which is what a page key should move. */\n function pageSize(): number {\n const table = tableRef.current;\n const firstRow = table?.tBodies[0]?.rows[0];\n const viewport = table?.parentElement;\n if (\n firstRow === undefined ||\n viewport === null ||\n viewport === undefined ||\n firstRow.offsetHeight === 0\n ) {\n return FALLBACK_PAGE;\n }\n return Math.max(\n 1,\n Math.floor(viewport.clientHeight / firstRow.offsetHeight),\n );\n }\n\n function focusCell(rowIndex: number, columnIndex: number): void {\n const next = clampFocus({ rowIndex, columnIndex }, rowCount, columnCount);\n if (\n next.rowIndex === focus.rowIndex &&\n next.columnIndex === focus.columnIndex\n ) {\n return;\n }\n pending.current = true;\n setStored(next);\n }\n\n function onKeyDown(event: ReactKeyboardEvent<HTMLElement>): void {\n const next = nextFocusForKey(\n event.key,\n {\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n altKey: event.altKey,\n shiftKey: event.shiftKey,\n },\n focus,\n rowCount,\n columnCount,\n pageSize(),\n isSkippableRow,\n );\n if (next === null) {\n return;\n }\n\n // Taken even when the move lands nowhere: an arrow at the last row would\n // otherwise scroll the page out from under the grid.\n event.preventDefault();\n focusCell(next.rowIndex, next.columnIndex);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the focus they move from.\n return {\n focus,\n tabIndexFor: (rowIndex, columnIndex) =>\n tabIndexFor(\n columnIndex,\n rowIndex === focus.rowIndex ? focus.columnIndex : null,\n ),\n focusCell,\n onKeyDown,\n };\n}\n","import {\n useMemo,\n useRef,\n type Dispatch,\n type KeyboardEvent as ReactKeyboardEvent,\n type SetStateAction,\n} from \"react\";\nimport {\n applySelectionIntent,\n clearSelection,\n diffSelection,\n resolveCell,\n resolveColumns,\n resolveRows,\n selectAll,\n selectCell,\n toggleCellSelection,\n type CellSelectionMode,\n type CellSelectionState,\n type ResolvedRow,\n type SelectableConfig,\n type SelectedCellRef,\n type SelectIntent,\n type SelectionMode,\n type SelectionState,\n type RowSelectEvent,\n type RowSelectionChangeEvent,\n type RowsSelectEvent,\n} from \"@gridkitjs/core\";\nimport type {\n CellSelectEvent,\n CellSelectionChangeEvent,\n ColumnSelectEvent,\n ColumnSelectionChangeEvent,\n ColumnsSelectEvent,\n ResolvedColumn,\n} from \"./DataGrid\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\n/**\n * The modifiers a Space or Enter keydown carries, for a caller that means to\n * hand them to `intentOf` as a click's modifiers would be. Space builds a\n * selection up and Enter replaces it, as in the body — so Space is mapped to\n * act like Ctrl, matching Ctrl-click and the plain click they stand in for.\n */\nexport function keyboardSelectIntent(event: ReactKeyboardEvent): {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n} {\n return {\n ctrlKey: event.key === \" \" || event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n };\n}\n\n/**\n * Reported as the user selects. Every one of these is fanned out from a single\n * diff of the transition it describes, so no two can disagree about what one\n * interaction did.\n */\nexport interface SelectionCallbacks<Row> {\n /** Called once per row newly selected. The last call names the last row. */\n onRowSelect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n /** Called once with every row one interaction selected. */\n onRowsSelect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n onRowDeselect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n onRowsDeselect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n /**\n * Called once per change with what it added, what it removed and everything\n * selected after it — the one to persist from.\n */\n onRowSelectionChange?:\n ((event: RowSelectionChangeEvent<Row>) => void) | undefined;\n onColumnSelect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsSelect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnDeselect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsDeselect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnSelectionChange?:\n ((event: ColumnSelectionChangeEvent<Row>) => void) | undefined;\n onCellSelect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellDeselect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellSelectionChange?:\n ((event: CellSelectionChangeEvent<Row>) => void) | undefined;\n}\n\ninterface UseGridSelectionOptions<Row> {\n rows: readonly ResolvedRow<Row>[];\n columns: readonly ResolvedColumn<Row>[];\n selectable: SelectableConfig | undefined;\n rowSelection: SelectionState;\n setRowSelection: Dispatch<SetStateAction<SelectionState>>;\n columnSelection: SelectionState;\n setColumnSelection: Dispatch<SetStateAction<SelectionState>>;\n cellSelection: CellSelectionState;\n setCellSelection: Dispatch<SetStateAction<CellSelectionState>>;\n callbacks: SelectionCallbacks<Row>;\n announce: (message: string) => void;\n /** What a column is called in an announcement — see `DataGrid.tsx`. */\n columnName: (columnId: string) => string;\n}\n\nexport interface GridSelectionApi {\n rowMode: SelectionMode;\n columnMode: SelectionMode;\n cellMode: CellSelectionMode;\n /**\n * Lookups for the render pass. The state itself stays an ordered list, which\n * is what makes the most recent selection its last entry.\n */\n selectedRowIds: ReadonlySet<string>;\n selectedColumnIds: ReadonlySet<string>;\n selectedCell: CellSelectionState;\n selectRow: (rowId: string, intent: SelectIntent) => void;\n selectColumn: (columnId: string, intent: SelectIntent) => void;\n selectCell: (cell: SelectedCellRef, intent: SelectIntent) => void;\n selectAllRows: () => void;\n /** Lets go of every selection at once, as Escape does. */\n clear: () => void;\n}\n\nfunction countMessage(count: number, noun: string): string {\n if (count === 0) {\n return `No ${noun}s selected`;\n }\n return count === 1\n ? `1 ${noun} selected`\n : `${String(count)} ${noun}s selected`;\n}\n\n/** A `Set` re-derived only when `values` changes. */\nfunction useAsSet<T>(values: readonly T[]): ReadonlySet<T> {\n return useMemo(() => new Set(values), [values]);\n}\n\n/**\n * A `Map` keying `values` by their `key` property, re-derived only when\n * `values` changes. Takes the key as a property name rather than an\n * extractor function so that it stays a stable dependency across\n * renders — an inline extractor handed in fresh each render would otherwise\n * force a recompute on every render regardless of whether `values` changed.\n */\nfunction useIndexedBy<T, K extends keyof T>(\n values: readonly T[],\n key: K,\n): ReadonlyMap<T[K], T> {\n return useMemo(\n () => new Map(values.map((value) => [value[key], value])),\n [values, key],\n );\n}\n\n/** `values.map((value) => value[key])`, re-derived only when `values` changes. */\nfunction useMappedArray<T, K extends keyof T>(\n values: readonly T[],\n key: K,\n): readonly T[K][] {\n return useMemo(() => values.map((value) => value[key]), [values, key]);\n}\n\n/**\n * Turns an intent against a row, column or cell into the selection it implies,\n * and reports what changed.\n *\n * Holds no state of its own: the three selections live in `DataGrid` beside\n * the sizing and the order, so that a ref exposing them later, or a feature\n * reading them, finds them in one place.\n */\nexport default function useGridSelection<Row>({\n rows,\n columns,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n columnName,\n}: UseGridSelectionOptions<Row>): GridSelectionApi {\n const rowMode = selectable?.rows ?? false;\n const columnMode = selectable?.columns ?? false;\n const cellMode = selectable?.cells ?? false;\n\n const rowsById = useIndexedBy(rows, \"rowId\");\n const rowIds = useMappedArray(rows, \"rowId\");\n const columnIds = useMappedArray(columns, \"id\");\n\n const selectedRowIds = useAsSet(rowSelection);\n const selectedColumnIds = useAsSet(columnSelection);\n\n /**\n * Where a range is measured from: the last row or column selected by\n * anything but a range, so that repeated Shift-clicks re-draw one span\n * instead of walking the anchor along with them.\n */\n const rowAnchor = useRef<string | null>(null);\n const columnAnchor = useRef<string | null>(null);\n\n /**\n * Announced only for a change touching more than one member. A single\n * selection is already carried by the focused row's own `aria-selected`, and\n * repeating it here would talk over that.\n */\n function announceCount(changed: number, total: number, noun: string): void {\n if (changed > 1) {\n announce(countMessage(total, noun));\n }\n }\n\n function commitRows(next: SelectionState): void {\n // The unchanged-reference contract the core transforms keep: a click that\n // selects what was already selected neither renders nor reports.\n commitIfChanged(rowSelection, next, setRowSelection, (committed) => {\n const { added, removed } = diffSelection(rowSelection, committed);\n const addedRows = resolveRows(rowsById, added);\n const removedRows = resolveRows(rowsById, removed);\n\n for (const row of addedRows) {\n callbacks.onRowSelect?.({ row, selection: committed });\n }\n if (addedRows.length > 0) {\n callbacks.onRowsSelect?.({ rows: addedRows, selection: committed });\n }\n for (const row of removedRows) {\n callbacks.onRowDeselect?.({ row, selection: committed });\n }\n if (removedRows.length > 0) {\n callbacks.onRowsDeselect?.({ rows: removedRows, selection: committed });\n }\n callbacks.onRowSelectionChange?.({\n added: addedRows,\n removed: removedRows,\n selected: resolveRows(rowsById, committed),\n selection: committed,\n });\n announceCount(added.length + removed.length, committed.length, \"row\");\n });\n }\n\n function commitColumns(next: SelectionState): void {\n commitIfChanged(columnSelection, next, setColumnSelection, (committed) => {\n const { added, removed } = diffSelection(columnSelection, committed);\n const addedColumns = resolveColumns(columns, added);\n const removedColumns = resolveColumns(columns, removed);\n\n for (const column of addedColumns) {\n callbacks.onColumnSelect?.({ column, selection: committed });\n }\n if (addedColumns.length > 0) {\n callbacks.onColumnsSelect?.({\n columns: addedColumns,\n selection: committed,\n });\n }\n for (const column of removedColumns) {\n callbacks.onColumnDeselect?.({ column, selection: committed });\n }\n if (removedColumns.length > 0) {\n callbacks.onColumnsDeselect?.({\n columns: removedColumns,\n selection: committed,\n });\n }\n callbacks.onColumnSelectionChange?.({\n added: addedColumns,\n removed: removedColumns,\n selected: resolveColumns(columns, committed),\n selection: committed,\n });\n announceCount(added.length + removed.length, committed.length, \"column\");\n });\n }\n\n function commitCell(next: CellSelectionState): void {\n commitIfChanged(cellSelection, next, setCellSelection, (committed) => {\n // Resolved before and after in one place, so that moving between two\n // cells reports the leaving and the arriving as one change.\n const selected = resolveCell(rowsById, columns, committed);\n const deselected = resolveCell(rowsById, columns, cellSelection);\n\n if (deselected !== null) {\n callbacks.onCellDeselect?.({ cell: deselected, selection: committed });\n }\n if (selected !== null) {\n callbacks.onCellSelect?.({ cell: selected, selection: committed });\n }\n callbacks.onCellSelectionChange?.({\n selected,\n deselected,\n selection: committed,\n });\n // Unlike rows and columns, a cell selection is always exactly one cell\n // — there is no multi-cell range — so it never crosses\n // `announceCount`'s >1 threshold and the focused cell's own\n // `aria-selected` is the only feedback a screen-reader user would\n // otherwise get. Announced unconditionally here instead, on every\n // commit that lands on a cell.\n if (selected !== null) {\n announce(\n `${columnName(selected.columnId)}, row ${String(selected.rowIndex + 1)}, selected`,\n );\n }\n });\n }\n\n function selectRow(rowId: string, intent: SelectIntent): void {\n const next = applySelectionIntent(\n rowSelection,\n rowIds,\n rowAnchor.current,\n rowId,\n intent,\n rowMode,\n );\n if (intent !== \"range\") {\n rowAnchor.current = rowId;\n }\n commitRows(next);\n }\n\n function selectColumn(columnId: string, intent: SelectIntent): void {\n const next = applySelectionIntent(\n columnSelection,\n columnIds,\n columnAnchor.current,\n columnId,\n intent,\n columnMode,\n );\n if (intent !== \"range\") {\n columnAnchor.current = columnId;\n }\n commitColumns(next);\n }\n\n function selectCellAt(cell: SelectedCellRef, intent: SelectIntent): void {\n // A cell holds one value, so a range over cells has nothing to span and\n // reads as the plain click it looks like.\n commitCell(\n intent === \"toggle\"\n ? toggleCellSelection(cellSelection, cell, cellMode)\n : selectCell(cellSelection, cell, cellMode),\n );\n }\n\n function selectAllRows(): void {\n commitRows(selectAll(rowSelection, rowIds, rowMode));\n }\n\n function clear(): void {\n commitRows(clearSelection(rowSelection));\n commitColumns(clearSelection(columnSelection));\n commitCell(null);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the selections they transform.\n return {\n rowMode,\n columnMode,\n cellMode,\n selectedRowIds,\n selectedColumnIds,\n selectedCell: cellSelection,\n selectRow,\n selectColumn,\n selectCell: selectCellAt,\n selectAllRows,\n clear,\n };\n}\n","/**\n * The shape behind a click or keypress that changes sort, resize, or\n * selection state: compute the next value, bail out if it's reference-equal\n * to the current one, persist it, then report it. Returns whether it\n * actually committed, for a caller with more to do only when it did.\n */\nexport function commitIfChanged<T>(\n current: T,\n next: T,\n setState: (value: T) => void,\n onCommit?: (next: T) => void,\n): boolean {\n if (next === current) {\n return false;\n }\n setState(next);\n onCommit?.(next);\n return true;\n}\n","import { useMemo } from \"react\";\nimport {\n groupRowId,\n intentOf,\n type AggregateState,\n type DisplayRow,\n type GroupAggregateDisplay,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { GridNavigationApi } from \"../useGridNavigation\";\nimport type { RowGroupingApi } from \"../useRowGrouping\";\nimport {\n keyboardSelectIntent,\n type GridSelectionApi,\n} from \"../useGridSelection\";\nimport GridGroupRow from \"./GridGroupRow\";\nimport GridGroupSummaryRow from \"./GridGroupSummaryRow\";\nimport GridRow from \"./GridRow\";\n\ninterface GridBodyProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rows: readonly DisplayRow<Row>[];\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n grouping: RowGroupingApi<Row>;\n /** Active aggregates. Empty when none are active. */\n aggregates: AggregateState<Row>;\n /** Where a group's aggregates render — inline in its header, or as its own summary row. */\n groupAggregateDisplay: GroupAggregateDisplay;\n}\n\n/** Where a cell sits, read off the table's own indices rather than an attribute. */\ninterface CellPosition {\n rowIndex: number;\n columnIndex: number;\n columnId: string;\n}\n\n/**\n * The cell an event happened in. `closest` is what makes the whole cell the\n * target: a click on a template's own markup resolves to the cell holding it.\n *\n * Never matches inside a group-header row: that row's single `<td>` carries\n * no `data-gridkit-column` (it spans every column at once, so no one column\n * id applies), which is what keeps this function — and everything built on\n * it — data-row-only without an explicit `\"kind\"` check of its own.\n */\nfunction cellFrom(target: EventTarget): CellPosition | null {\n if (!(target instanceof Element)) {\n return null;\n }\n const cell = target.closest(\"td[data-gridkit-column]\");\n const row = cell?.parentElement;\n const columnId = cell?.getAttribute(\"data-gridkit-column\");\n if (\n !(cell instanceof HTMLTableCellElement) ||\n !(row instanceof HTMLTableRowElement) ||\n columnId === null ||\n columnId === undefined\n ) {\n return null;\n }\n return {\n rowIndex: row.sectionRowIndex,\n columnIndex: cell.cellIndex,\n columnId,\n };\n}\n\n/** The group-header row an event happened in, if any. */\nfunction groupRowFrom(\n target: EventTarget,\n): { rowIndex: number; groupId: string } | null {\n if (!(target instanceof Element)) {\n return null;\n }\n const row = target.closest(\"tr[data-gridkit-group]\");\n const groupId = row?.getAttribute(\"data-gridkit-group\");\n if (\n !(row instanceof HTMLTableRowElement) ||\n groupId === null ||\n groupId === undefined\n ) {\n return null;\n }\n return { rowIndex: row.sectionRowIndex, groupId };\n}\n\ninterface GroupAriaMeta {\n posinset: number;\n setsize: number;\n}\n\n/**\n * `aria-posinset`/`aria-setsize` per group header: its 1-based position\n * among, and count of, the group headers sharing its level and immediate\n * parent. Depth-first order (see `groupRows`) keeps siblings contiguous, so\n * one pass tallies each parent's total and a second assigns each header's\n * position within it.\n */\nfunction groupAriaMeta<Row>(\n rows: readonly DisplayRow<Row>[],\n): ReadonlyMap<string, GroupAriaMeta> {\n const totals = new Map<string, number>();\n for (const entry of rows) {\n if (!(\"kind\" in entry) || entry.kind !== \"group\") continue;\n const parentKey = groupRowId(entry.path.slice(0, -1));\n totals.set(parentKey, (totals.get(parentKey) ?? 0) + 1);\n }\n\n const seen = new Map<string, number>();\n const meta = new Map<string, GroupAriaMeta>();\n for (const entry of rows) {\n if (!(\"kind\" in entry) || entry.kind !== \"group\") continue;\n const parentKey = groupRowId(entry.path.slice(0, -1));\n const posinset = (seen.get(parentKey) ?? 0) + 1;\n seen.set(parentKey, posinset);\n meta.set(entry.groupId, {\n posinset,\n setsize: totals.get(parentKey) ?? posinset,\n });\n }\n return meta;\n}\n\n/**\n * Events are delegated to the body rather than bound per cell, which is what\n * lets `GridRow` be memoised: a handler rebuilt each render is a prop that\n * changes each render, and one reaching every row would defeat the boundary\n * entirely.\n */\nexport default function GridBody<Row>({\n columns,\n rows,\n activeColumnId,\n nav,\n selection,\n grouping,\n aggregates,\n groupAggregateDisplay,\n}: GridBodyProps<Row>) {\n const { selectedCell, rowMode, cellMode } = selection;\n const ariaMeta = useMemo(() => groupAriaMeta(rows), [rows]);\n\n /** The row and cell an event addresses, resolved once for every handler. */\n function targetOf(\n target: EventTarget,\n ): { position: CellPosition; rowId: string } | null {\n const position = cellFrom(target);\n const entry = position === null ? undefined : rows[position.rowIndex];\n if (position === null || entry === undefined || \"kind\" in entry) {\n return null;\n }\n return { position, rowId: entry.rowId };\n }\n\n function select(\n rowId: string,\n columnId: string,\n modifiers: { ctrlKey: boolean; metaKey: boolean; shiftKey: boolean },\n ): void {\n const intent = intentOf(modifiers);\n // Independent of each other: selecting a cell says nothing about its row,\n // so a grid with both on reports both.\n if (rowMode !== false) {\n selection.selectRow(rowId, intent);\n }\n if (cellMode !== false) {\n selection.selectCell({ rowId, columnId }, intent);\n }\n }\n\n return (\n <tbody\n className=\"grid-body\"\n onFocus={(event) => {\n const group = groupRowFrom(event.target);\n if (group !== null) {\n // One cell for the whole row — see the note on `focused` below.\n nav.focusCell(group.rowIndex, 0);\n return;\n }\n const found = targetOf(event.target);\n if (found === null) return;\n nav.focusCell(found.position.rowIndex, found.position.columnIndex);\n }}\n onClick={(event) => {\n const group = groupRowFrom(event.target);\n if (group !== null) {\n grouping.toggleExpansion(group.groupId);\n return;\n }\n const found = targetOf(event.target);\n if (found === null) return;\n select(found.rowId, found.position.columnId, event);\n }}\n onKeyDown={(event) => {\n const group = groupRowFrom(event.target);\n if (group !== null) {\n // One cell spans every column, so there is nothing to move within —\n // left/right stay a no-op rather than silently moving `nav`'s\n // stored column index off of a cell this row doesn't have.\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n event.preventDefault();\n return;\n }\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n grouping.toggleExpansion(group.groupId);\n return;\n }\n nav.onKeyDown(event);\n return;\n }\n\n // Space builds a selection up and Enter replaces it, matching the\n // Ctrl-click and the plain click they stand in for.\n if (event.key === \" \" || event.key === \"Enter\") {\n const found = targetOf(event.target);\n if (found === null) return;\n // Taken whether or not anything is selectable: Space would otherwise\n // scroll the grid out from under the focused cell.\n event.preventDefault();\n select(\n found.rowId,\n found.position.columnId,\n keyboardSelectIntent(event),\n );\n return;\n }\n nav.onKeyDown(event);\n }}\n >\n {rows.map((entry) => {\n if (!(\"kind\" in entry)) {\n return (\n <GridRow<Row>\n key={entry.rowId}\n columns={columns}\n rowId={entry.rowId}\n row={entry.row}\n rowIndex={entry.rowIndex}\n datasetIndex={entry.datasetIndex}\n activeColumnId={activeColumnId}\n selectedColumnIds={selection.selectedColumnIds}\n selected={selection.selectedRowIds.has(entry.rowId)}\n /*\n * Narrowed to this row before it crosses the boundary, so\n * that moving the selected cell re-renders the two rows it\n * moved between rather than all of them.\n */\n selectedColumnId={\n selectedCell?.rowId === entry.rowId\n ? selectedCell.columnId\n : null\n }\n focusedColumnIndex={\n nav.focus.rowIndex === entry.rowIndex\n ? nav.focus.columnIndex\n : null\n }\n rowsSelectable={rowMode !== false}\n cellsSelectable={cellMode !== false}\n />\n );\n }\n\n if (entry.kind === \"group-summary\") {\n return (\n <GridGroupSummaryRow<Row>\n key={`${entry.groupId}-summary`}\n groupId={entry.groupId}\n level={entry.level}\n datasetIndex={entry.datasetIndex}\n results={entry.aggregates}\n aggregates={aggregates}\n columns={columns}\n />\n );\n }\n\n return (\n <GridGroupRow\n key={entry.groupId}\n columnCount={columns.length}\n groupId={entry.groupId}\n level={entry.level}\n columnLabel={\n columns.find((column) => column.id === entry.columnId)?.label ??\n entry.columnId\n }\n value={entry.value}\n expanded={entry.expanded}\n count={entry.count}\n datasetIndex={entry.datasetIndex}\n posinset={ariaMeta.get(entry.groupId)?.posinset ?? 1}\n setsize={ariaMeta.get(entry.groupId)?.setsize ?? 1}\n // Inline rendering only under \"inline\" display — under \"row\",\n // the group's own summary row (above) already shows these, and\n // showing them twice would be redundant.\n aggregates={groupAggregateDisplay === \"inline\" ? aggregates : []}\n results={entry.aggregates}\n columns={columns}\n // Ignores `nav.focus.columnIndex`: with only one cell in this\n // row, whether it holds the tab stop depends on `rowIndex`\n // alone.\n focused={nav.focus.rowIndex === entry.rowIndex}\n />\n );\n })}\n </tbody>\n );\n}\n","import { memo, type ReactNode } from \"react\";\nimport type { AggregateResults, AggregateState } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { classNames } from \"../classNames\";\nimport { formatAggregateValue } from \"./formatAggregateValue\";\n\ninterface GridGroupRowProps<Row> {\n /** How many columns this group's header spans, matching the grid's own count. */\n columnCount: number;\n groupId: string;\n /** Nesting depth, 0 for a top-level group — indents the header and feeds `aria-level`. */\n level: number;\n /** The grouped column's own label, whatever its `headerTemplate` returns. */\n columnLabel: ReactNode;\n /** This group's own value — the last entry of its `path`. */\n value: unknown;\n expanded: boolean;\n /** Leaf row count under this group, regardless of collapse state. */\n count: number;\n /** This header's absolute position in the whole dataset, unaffected by which page is showing — see `ResolvedGroupRow.datasetIndex`. */\n datasetIndex: number;\n /** This group's 1-based position among its own siblings, for `aria-posinset`. */\n posinset: number;\n /** How many siblings this group has, for `aria-setsize`. */\n setsize: number;\n /** Whether this row currently holds the grid's single tab stop. */\n focused: boolean;\n /** Active aggregates — empty when none are active, in which case no subtotal renders. */\n aggregates: AggregateState<Row>;\n /** This group's own computed results, keyed the same way `aggregates` resolves each spec's key. */\n results: AggregateResults;\n columns: readonly ResolvedColumn<Row>[];\n}\n\n/**\n * How a group's own value renders in its header — blank rather than the\n * literal word \"null\"/\"undefined\", and never `Object`'s own\n * `[object Object]` for a value `String()` can't stringify meaningfully.\n */\nfunction formatGroupValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"(blank)\";\n }\n if (value instanceof Date) {\n return value.toLocaleString();\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return String(value);\n case \"function\":\n return \"(function)\";\n default:\n // Arrays, and anything else a grouped column's value could still be.\n return JSON.stringify(value);\n }\n}\n\nfunction GridGroupRowComponent<Row>({\n columnCount,\n groupId,\n level,\n columnLabel,\n value,\n expanded,\n count,\n datasetIndex,\n posinset,\n setsize,\n focused,\n aggregates,\n results,\n columns,\n}: GridGroupRowProps<Row>) {\n const byId = new Map(columns.map((entry) => [entry.id, entry]));\n\n return (\n <tr\n role=\"row\"\n // Two past the index: rows are counted from one, and the header is the\n // first of them — the same convention `GridRow` uses. Built from\n // `datasetIndex`, not the page-relative `rowIndex`, matching `GridRow`.\n aria-rowindex={datasetIndex + 2}\n // 1-based, per the WAI-ARIA treegrid pattern.\n aria-level={level + 1}\n aria-expanded={expanded}\n aria-setsize={setsize}\n aria-posinset={posinset}\n data-gridkit-group={groupId}\n className={classNames(\n \"grid-group-row\",\n `is-group-level-${String(level)}`,\n )}\n >\n <td\n role=\"gridcell\"\n colSpan={columnCount}\n tabIndex={focused ? 0 : -1}\n aria-keyshortcuts=\"Space Enter\"\n className=\"grid-group-cell\"\n >\n {/*\n * The flex layout lives on this inner `div`, not the `<td>` itself:\n * a `display` other than `table-cell` on the cell element changes\n * its box type entirely, and the browser fixes that up by wrapping\n * it in an anonymous table-cell — which throws off the cell's own\n * hit-testing (a click landing where the row's bounding box says\n * the cell is can miss it and hit the table underneath instead).\n */}\n <div\n className=\"grid-group-cell-content\"\n style={{ paddingInlineStart: `${String(level * 1.25 + 0.5)}rem` }}\n >\n <span\n className={classNames(\n \"group-toggle\",\n expanded ? \"is-expanded\" : \"is-collapsed\",\n )}\n aria-hidden=\"true\"\n />\n <span className=\"group-label\">\n {columnLabel}: {formatGroupValue(value)}\n </span>\n <span className=\"group-count\">({count})</span>\n {aggregates.length > 0 && (\n <span className=\"group-aggregates\">\n {aggregates.map((spec) => {\n const key = spec.id ?? spec.columnId;\n const aggregateValue = results.get(key);\n const column = byId.get(spec.columnId);\n const rendered = column?.column.footerTemplate\n ? column.column.footerTemplate({\n value: aggregateValue,\n rows: [],\n })\n : formatAggregateValue(aggregateValue);\n // An explicit `id` disambiguates two specs on the same\n // column (e.g. both `sum` and `avg` of Amount) — when given,\n // it's the caller's own label for this result, so it takes\n // priority over the column's shared label.\n const aggregateLabel =\n spec.id ?? column?.label ?? spec.columnId;\n return (\n <span key={key} className=\"group-aggregate\">\n {aggregateLabel}: {rendered}\n </span>\n );\n })}\n </span>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\n/**\n * `memo()`-wrapped for the same reason `GridRow` is: every prop here is a\n * scalar or an already-narrowed value, and no handler reaches this component\n * directly — `GridBody` delegates group-header clicks and keydowns the same\n * way it does for data rows.\n */\nconst GridGroupRow = memo(\n GridGroupRowComponent,\n) as typeof GridGroupRowComponent;\n\nexport default GridGroupRow;\n","/**\n * A computed aggregate result rendered as plain text — used by both\n * `GridGroupRow` (a group's inline subtotal) and `GridFooter` (the grand\n * total) as the fallback when a column defines no `footerTemplate` of its\n * own. Numbers get locale grouping since a raw `sum`/`count` easily runs\n * into the thousands in an ERP-sized dataset; everything else mirrors\n * `GridGroupRow`'s own `formatGroupValue` so a value renders consistently\n * whether it's a group's own value or one of its aggregates.\n */\nexport function formatAggregateValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"—\";\n }\n if (value instanceof Date) {\n return value.toLocaleString();\n }\n switch (typeof value) {\n case \"string\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return String(value);\n case \"number\":\n return value.toLocaleString();\n case \"function\":\n return \"(function)\";\n default:\n return JSON.stringify(value);\n }\n}\n","import { memo } from \"react\";\nimport type { AggregateResults, AggregateState } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { classNames } from \"../classNames\";\nimport { formatAggregateValue } from \"./formatAggregateValue\";\n\ninterface GridGroupSummaryRowProps<Row> {\n groupId: string;\n /** Nesting depth, matching the group's own level — indents the row the same amount `GridGroupRow` does. */\n level: number;\n /** This row's absolute position in the whole dataset, unaffected by which page is showing — see `ResolvedGroupSummaryRow.datasetIndex`. */\n datasetIndex: number;\n /** The group's own computed results — identical to its header's `aggregates`. */\n results: AggregateResults;\n aggregates: AggregateState<Row>;\n columns: readonly ResolvedColumn<Row>[];\n}\n\n/**\n * A group's own aggregate results, one real `<td>` per column rather than\n * text inside the header's single spanning cell — the `groupAggregateDisplay:\n * \"row\"` alternative to `GridGroupRow`'s own inline rendering. Structurally\n * mirrors `GridFooter`'s grand-total row, scoped to one group's `results`\n * instead of the dataset-wide total, and indented the same amount its own\n * `GridGroupRow` is.\n *\n * Presentational: it occupies a real row slot (counted in `rowCount`/\n * `aria-rowindex`, since it is a genuine `<tr>` inside `<tbody>`) but is\n * never a keyboard tab stop — `DataGrid.tsx`'s `isSkippableRow` steps over\n * it during arrow-key navigation the same way this component itself takes\n * no `tabIndex`, `role=\"row\"`/`\"gridcell\"` only, no interactive attributes.\n *\n * Each cell's alignment follows the same rule `GridFooter`'s own cells do:\n * the first matching spec's `AggregateSpec.alignment` override, falling\n * back to the column's own `alignment` when neither is set.\n */\nfunction GridGroupSummaryRowComponent<Row>({\n groupId,\n level,\n datasetIndex,\n results,\n aggregates,\n columns,\n}: GridGroupSummaryRowProps<Row>) {\n return (\n <tr\n role=\"row\"\n aria-rowindex={datasetIndex + 2}\n data-gridkit-group-summary={groupId}\n className={classNames(\n \"grid-group-summary-row\",\n `is-group-level-${String(level)}`,\n )}\n >\n {columns.map((entry) => {\n const specs = aggregates.filter(\n (candidate) => candidate.columnId === entry.id,\n );\n const { column } = entry;\n\n return (\n <td\n key={entry.id}\n role=\"gridcell\"\n data-gridkit-column={entry.id}\n className=\"grid-group-summary-cell\"\n style={{ textAlign: specs[0]?.alignment ?? entry.alignment }}\n >\n {entry.id === columns[0]?.id && (\n <span\n className=\"grid-group-summary-indent\"\n style={{ width: `${String(level * 1.25 + 0.5)}rem` }}\n aria-hidden=\"true\"\n />\n )}\n {specs\n .map((spec) => {\n const value = results.get(spec.id ?? spec.columnId);\n return column.footerTemplate\n ? column.footerTemplate({ value, rows: [] })\n : formatAggregateValue(value);\n })\n .flatMap((rendered, index) =>\n index === 0 ? [rendered] : [\", \", rendered],\n )}\n </td>\n );\n })}\n </tr>\n );\n}\n\n/**\n * `memo()`-wrapped for the same reason `GridGroupRow`/`GridRow` are: every\n * prop here is a scalar or an already-narrowed value.\n */\nconst GridGroupSummaryRow = memo(\n GridGroupSummaryRowComponent,\n) as typeof GridGroupSummaryRowComponent;\n\nexport default GridGroupSummaryRow;\n","import { accessDotted } from \"@gridkitjs/core\";\nimport { memo, type ReactNode } from \"react\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { ariaAttr } from \"../ariaAttr\";\nimport { classNames } from \"../classNames\";\nimport { tabIndexFor } from \"../useGridNavigation\";\n\ninterface GridRowProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rowId: string;\n row: Row;\n rowIndex: number;\n /** This row's absolute position in the whole dataset, unaffected by which page is showing — see `CellTemplateContext.datasetIndex`. */\n datasetIndex: number;\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n selectedColumnIds: ReadonlySet<string>;\n selected: boolean;\n /** Which of this row's cells is the selected one, if any. */\n selectedColumnId: string | null;\n /** Which of this row's cells holds the grid's tab stop, if any. */\n focusedColumnIndex: number | null;\n rowsSelectable: boolean;\n cellsSelectable: boolean;\n}\n\nfunction GridRowComponent<Row>({\n columns,\n rowId,\n row,\n rowIndex,\n datasetIndex,\n activeColumnId,\n selectedColumnIds,\n selected,\n selectedColumnId,\n focusedColumnIndex,\n rowsSelectable,\n cellsSelectable,\n}: GridRowProps<Row>) {\n return (\n <tr\n role=\"row\"\n // Two past the index: rows are counted from one, and the header is the\n // first of them. Built from `datasetIndex` rather than the\n // page-relative `rowIndex`, so a paginated grid still reports each\n // row's true position in the whole dataset — the two only diverge once\n // pagination is on.\n aria-rowindex={datasetIndex + 2}\n // Omitted rather than `false` when rows cannot be selected, which would\n // otherwise have every row announce that it is not.\n {...ariaAttr(rowsSelectable, \"aria-selected\", selected)}\n className={classNames(\"grid-row\", selected ? \"is-selected\" : \"\")}\n >\n {columns.map(({ id, column, alignment }, columnIndex) => {\n // Resolved either way, so a template that only formats the value never\n // has to walk the field path a second time.\n const value = accessDotted(row, column.field);\n const cellSelected = id === selectedColumnId;\n\n return (\n <td\n key={id}\n role=\"gridcell\"\n data-gridkit-column={id}\n aria-colindex={columnIndex + 1}\n tabIndex={tabIndexFor(columnIndex, focusedColumnIndex)}\n {...ariaAttr(cellsSelectable, \"aria-selected\", cellSelected)}\n {...ariaAttr(cellsSelectable, \"aria-keyshortcuts\", \"Space Enter\")}\n className={classNames(\n \"grid-cell\",\n id === activeColumnId ? \"is-resizing\" : \"\",\n cellSelected || selectedColumnIds.has(id) ? \"is-selected\" : \"\",\n column.wrap?.cells ? \"is-wrapped\" : \"\",\n column.cellClassName ?? \"\",\n )}\n style={{ textAlign: alignment }}\n >\n {column.cellTemplate\n ? column.cellTemplate({\n value,\n row,\n rowIndex,\n datasetIndex,\n rowId,\n selected,\n })\n : (value as ReactNode)}\n </td>\n );\n })}\n </tr>\n );\n}\n\n/**\n * Selection lives at the top of the grid, so any change to it re-renders the\n * whole body — without this boundary a click would rebuild every cell of every\n * row rather than the one or two rows that changed.\n *\n * Every prop above is a scalar or already memoised for that reason, and no\n * handler reaches here at all: the body delegates its events, so a row has\n * nothing to compare that changes each render.\n *\n * `memo` erases the type parameter, and the cast puts it back — the standard\n * price of memoising a generic component.\n */\nconst GridRow = memo(GridRowComponent) as typeof GridRowComponent;\n\nexport default GridRow;\n","import type { AggregateResults, AggregateState } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { formatAggregateValue } from \"./formatAggregateValue\";\n\ninterface GridFooterProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n aggregates: AggregateState<Row>;\n results: AggregateResults;\n /** Every row the grand total was computed over — what a `footerTemplate` receives as `rows`. */\n rows: readonly Row[];\n}\n\n/**\n * The grand-total footer — one `<tfoot>` row, one cell per column, using\n * that column's own `footerTemplate` when it defines one, its own computed\n * value formatted plainly when it doesn't, and a blank cell for a column\n * with no aggregate at all. Structurally mirrors `GridHeader`, minus\n * everything interactive: a footer cell is not resizable, sortable, or\n * selectable.\n *\n * A column named by more than one spec (e.g. both `sum` and `avg` of the\n * same column, disambiguated by `id`) renders every matching spec's result\n * in its one cell, comma-separated — the cell grid stays one-per-column,\n * but no result is dropped the way picking only the first match would. The\n * cell's own alignment follows the first matching spec's `AggregateSpec.\n * alignment` override, falling back to the column's own `alignment` when\n * neither is set — one `<td>` can only take one `text-align`, so a second\n * spec's own override (if it disagrees) applies only to its value, not the\n * cell.\n *\n * Sits outside `<tbody>`'s row count on purpose — a `<tfoot>` is not part\n * of `aria-rowcount`/`aria-rowindex`/keyboard navigation's `rowCount`, the\n * same way `<thead>`'s header row is counted separately from data rows.\n */\nexport default function GridFooter<Row>({\n columns,\n aggregates,\n results,\n rows,\n}: GridFooterProps<Row>) {\n return (\n <tfoot>\n <tr className=\"grid-footer\" role=\"row\">\n {columns.map((entry) => {\n const specs = aggregates.filter(\n (candidate) => candidate.columnId === entry.id,\n );\n const { column } = entry;\n\n return (\n <td\n key={entry.id}\n role=\"gridcell\"\n data-gridkit-column={entry.id}\n className=\"grid-footer-cell\"\n style={{ textAlign: specs[0]?.alignment ?? entry.alignment }}\n >\n {specs\n .map((spec) => {\n const value = results.get(spec.id ?? spec.columnId);\n return column.footerTemplate\n ? column.footerTemplate({ value, rows })\n : formatAggregateValue(value);\n })\n // Two values in one cell need a visible separator; a single\n // one (the common case) renders exactly as before.\n .flatMap((rendered, index) =>\n index === 0 ? [rendered] : [\", \", rendered],\n )}\n </td>\n );\n })}\n </tr>\n </tfoot>\n );\n}\n","import { paginationWindow } from \"@gridkitjs/core\";\nimport type { PagerConfig } from \"../DataGrid\";\nimport type { PaginationApi } from \"../usePagination\";\n\ninterface GridPagerProps {\n pager: PaginationApi;\n /** Presentation options for the pager. `undefined` renders the `\"compact\"` default with no page-size control. */\n config: PagerConfig | undefined;\n}\n\n/**\n * A minimal, semantically-classed pager: previous/next, a page-index\n * display (or, under `config.variant === \"numbered\"`, a row of page\n * buttons), and — when `config.sizeOptions` is given — a page-size\n * `<select>`. Rendered as a sibling below the table, not a row inside it,\n * the same reasoning `GroupByBar` gives for its own placement: a control\n * surface, not grid content.\n *\n * Whether this mounts at all is `DataGrid.tsx`'s call (`paginated`), not\n * this component's own.\n */\nexport default function GridPager({ pager, config }: GridPagerProps) {\n const { pagination, pageCount, currentPage } = pager;\n const variant = config?.variant ?? \"compact\";\n const sizeOptions = config?.sizeOptions;\n\n return (\n <div className=\"gridkit-grid-pager\" role=\"group\" aria-label=\"Pagination\">\n <button\n type=\"button\"\n className=\"grid-pager-button\"\n disabled={pagination.pageIndex <= 0}\n onClick={() => {\n pager.previousPage();\n }}\n >\n Previous\n </button>\n {variant === \"numbered\" ? (\n paginationWindow(currentPage, pageCount, {\n boundaryCount: config?.boundaryCount,\n siblingCount: config?.siblingCount,\n }).map((entry, index) =>\n entry === \"ellipsis\" ? (\n <span\n key={`ellipsis-${String(index)}`}\n className=\"grid-pager-ellipsis\"\n aria-hidden=\"true\"\n >\n …\n </span>\n ) : (\n <button\n key={entry}\n type=\"button\"\n className=\"grid-pager-button\"\n aria-label={`Page ${String(entry)}`}\n aria-current={entry === currentPage ? \"page\" : undefined}\n onClick={() => {\n pager.goToPage(entry - 1);\n }}\n >\n {entry}\n </button>\n ),\n )\n ) : (\n <span className=\"grid-pager-status\">\n Page {pageCount === 0 ? 0 : currentPage} of {pageCount}\n </span>\n )}\n <button\n type=\"button\"\n className=\"grid-pager-button\"\n disabled={pagination.pageIndex >= pageCount - 1}\n onClick={() => {\n pager.nextPage();\n }}\n >\n Next\n </button>\n {sizeOptions !== undefined && sizeOptions.length > 0 && (\n <label className=\"grid-pager-page-size\">\n Rows per page\n <select\n value={pagination.pageSize}\n onChange={(event) => {\n pager.setPageSize(Number(event.target.value));\n }}\n >\n {sizeOptions.map((size) => (\n <option key={size} value={size}>\n {size}\n </option>\n ))}\n </select>\n </label>\n )}\n </div>\n );\n}\n","import { createPortal } from \"react-dom\";\nimport { resolveKeyboardDropTarget } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport { classNames } from \"../classNames\";\nimport type { GroupByDropTarget } from \"../groupByDropTarget\";\nimport useGroupByDrag from \"../useGroupByDrag\";\nimport type { RowGroupingApi } from \"../useRowGrouping\";\n\ninterface GroupByBarProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n grouping: RowGroupingApi<Row>;\n /** A column's accessible name — see `DataGrid.tsx`'s own `columnName`. */\n columnName: (columnId: string) => string;\n /** Whether the header drag currently open (if any) could drop into this bar. */\n headerDragEligible: boolean;\n /**\n * Whether the header drag currently open (if any) is for a column already\n * in the group-by stack — a drag this bar rejects outright, since\n * repositioning a grouped column is the chip's job, not the header's.\n */\n headerDragBlocked: boolean;\n /** That header drag's own target within this bar, or `null`. */\n headerDropTarget: GroupByDropTarget | null;\n}\n\n/**\n * The active group-by stack, outer to inner, as removable, reorderable\n * chips — and the drop target for a header dragged in from outside it.\n * Each column's own header already carries a group toggle (a pointer\n * affordance, plus `Alt+ArrowDown`) for adding or removing a level without\n * dragging at all; this bar shows the resulting stack, lets a level be\n * removed from it directly, lets a chip be dragged to reorder the stack (or\n * moved via `Ctrl+ArrowLeft`/`Ctrl+ArrowRight` on a focused one), and — for\n * a column whose header sets `groupByDraggable` and isn't grouped yet —\n * accepts a header dropped onto it, at whatever position among the existing\n * chips it's released. A header for a column already in the stack is\n * rejected outright (`is-drag-blocked`, `cursor: not-allowed`): the header\n * only ever adds, and repositioning an existing level is the chip's job.\n *\n * Whether this component mounts at all is `DataGrid.tsx`'s call\n * (`groupByBarVisibility`), not this component's own — it never bails out\n * on its own initiative once rendered.\n *\n * Chips sit outside the grid's own single-roving-tabstop model: there is no\n * shared index to keep in sync the way a row or a header cell has, so each\n * chip (and its own remove button) is simply, always `tabIndex={0}` — plain\n * DOM tab order, no roving-focus bookkeeping.\n */\nexport default function GroupByBar<Row>({\n columns,\n grouping,\n columnName,\n headerDragEligible,\n headerDragBlocked,\n headerDropTarget,\n}: GroupByBarProps<Row>) {\n const { groupBy } = grouping;\n const groupByIds = groupBy.map((entry) => entry.columnId);\n\n const chipDrag = useGroupByDrag({\n groupBy,\n onDrop: (movedId, beforeColumnId) => {\n grouping.moveGroupBy(movedId, beforeColumnId);\n },\n });\n\n // Mutually exclusive by construction — one pointer, so at most one of \"a\n // chip dragged within this bar\" and \"a header dragged in from outside it\"\n // is ever active at once.\n const activeDropTarget = chipDrag.dropTarget ?? headerDropTarget;\n const isDragTarget = chipDrag.draggedColumnId !== null || headerDragEligible;\n const showPlaceholder =\n groupBy.length === 0 && columns.some((entry) => entry.groupByDraggable);\n\n function labelFor(columnId: string) {\n return columns.find((entry) => entry.id === columnId)?.label ?? columnId;\n }\n\n function moveByKeyboard(columnId: string, direction: -1 | 1): void {\n const beforeColumnId = resolveKeyboardDropTarget(\n groupByIds,\n columnId,\n direction,\n );\n if (beforeColumnId === undefined) {\n return;\n }\n grouping.moveGroupBy(columnId, beforeColumnId);\n }\n\n return (\n <div\n className={classNames(\n \"gridkit-group-by-bar\",\n isDragTarget ? \"is-drag-target\" : \"\",\n headerDragBlocked ? \"is-drag-blocked\" : \"\",\n )}\n data-gridkit-group-by-bar=\"\"\n role=\"group\"\n aria-label=\"Grouped by\"\n >\n {showPlaceholder && (\n <span className=\"group-by-bar-placeholder\">\n Drag a column here to group by it\n </span>\n )}\n {groupBy.map((entry, index) => {\n const dropBefore = activeDropTarget?.beforeColumnId === entry.columnId;\n const dropAfter =\n activeDropTarget?.beforeColumnId === null &&\n index === groupBy.length - 1;\n const dragging = chipDrag.draggedColumnId === entry.columnId;\n\n return (\n <span\n key={entry.columnId}\n className={classNames(\n \"group-by-chip\",\n dragging ? \"is-dragging\" : \"\",\n dropBefore ? \"is-drop-before\" : \"\",\n dropAfter ? \"is-drop-after\" : \"\",\n )}\n data-gridkit-group-chip={entry.columnId}\n tabIndex={0}\n aria-label={\n groupBy.length > 1\n ? `${columnName(entry.columnId)}, level ${String(index + 1)} of ${String(groupBy.length)}`\n : columnName(entry.columnId)\n }\n aria-keyshortcuts=\"Control+ArrowLeft Control+ArrowRight\"\n onPointerDown={(event) => {\n chipDrag.startDrag(entry.columnId, event);\n }}\n onKeyDown={(event) => {\n const horizontal =\n event.key === \"ArrowLeft\" || event.key === \"ArrowRight\";\n if (horizontal && event.ctrlKey) {\n event.preventDefault();\n moveByKeyboard(\n entry.columnId,\n event.key === \"ArrowLeft\" ? -1 : 1,\n );\n }\n }}\n >\n <span className=\"group-by-chip-label\">\n {labelFor(entry.columnId)}\n </span>\n <button\n type=\"button\"\n className=\"group-by-chip-remove\"\n aria-label={`Stop grouping by ${columnName(entry.columnId)}`}\n onPointerDown={(event) => {\n // Otherwise the chip's own `onPointerDown` sees this bubble\n // up and starts a drag — the same reason the header's own\n // sort toggle stops it.\n event.stopPropagation();\n }}\n onClick={() => {\n grouping.toggleGroupBy(entry.columnId);\n }}\n >\n ×\n </button>\n </span>\n );\n })}\n {/*\n * Portalled to the body, the same reason the header's own drag ghost\n * is: inside the viewport the overflow that makes the grid scroll\n * would clip it, and this bar sits right above that viewport.\n */}\n {chipDrag.draggedColumnId !== null &&\n chipDrag.ghostTransform !== null &&\n createPortal(\n <span\n className=\"group-by-chip drag-ghost\"\n style={{ transform: chipDrag.ghostTransform }}\n aria-hidden=\"true\"\n >\n {labelFor(chipDrag.draggedColumnId)}\n </span>,\n document.body,\n )}\n </div>\n );\n}\n","import {\n movesGroupBy,\n resolveDropBefore,\n type GroupByState,\n} from \"@gridkitjs/core\";\nimport { elementAt, sideOf } from \"./useDragReorder\";\n\nexport interface GroupByDropTarget {\n readonly kind: \"group-by\";\n readonly beforeColumnId: string | null;\n}\n\n/**\n * Where a header or chip dropped at `(clientX, clientY)` would land within\n * the group-by bar, or `null` when the pointer isn't over the bar at all, or\n * when the drop would change nothing. Shared by `useColumnDrag` (a header\n * dragged in from outside the bar) and `useGroupByDrag` (a chip dragged\n * within it), so the two can never disagree about where a drop lands.\n */\nexport function resolveGroupByDropTarget(\n clientX: number,\n clientY: number,\n movedId: string,\n groupBy: GroupByState,\n): GroupByDropTarget | null {\n const overBar = elementAt(clientX, clientY, \"[data-gridkit-group-by-bar]\");\n if (overBar === null) {\n return null;\n }\n\n const overChip = elementAt(clientX, clientY, \"[data-gridkit-group-chip]\");\n const chipId = overChip?.getAttribute(\"data-gridkit-group-chip\");\n const beforeColumnId =\n overChip && chipId\n ? resolveDropBefore(\n groupBy.map((entry) => entry.columnId),\n chipId,\n sideOf(overChip, clientX),\n )\n : null; // Over the (possibly empty) bar itself, past every chip: append.\n\n return movesGroupBy(groupBy, movedId, beforeColumnId)\n ? { kind: \"group-by\", beforeColumnId }\n : null;\n}\n","import {\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport type { DropSide } from \"@gridkitjs/core\";\nimport { startPointerGesture } from \"./pointerGesture\";\n\n/**\n * How far the pointer travels before a press becomes a drag. Below it the\n * gesture is still a click, which is what leaves the pressed element free to\n * take one — shared by every drag-to-reorder gesture in the grid.\n */\nconst DRAG_THRESHOLD = 4;\n\n/**\n * The closest ancestor of (or the element itself at) `(x, y)` matching\n * `selector`. `closest` is what makes the whole matched element the target:\n * a hit on a descendant (a header's label, a chip's remove button) resolves\n * to it.\n */\nexport function elementAt(\n x: number,\n y: number,\n selector: string,\n): Element | null {\n return document.elementFromPoint(x, y)?.closest(selector) ?? null;\n}\n\n/** Which half of `element` `x` falls in. */\nexport function sideOf(element: Element, x: number): DropSide {\n const rect = element.getBoundingClientRect();\n return x < rect.left + rect.width / 2 ? \"before\" : \"after\";\n}\n\ninterface UseDragReorderOptions<Target> {\n /**\n * Where a drop at `(clientX, clientY)` would land, or `null` for nowhere\n * valid — including a gap `id` already occupies, the same \"promises only\n * moves that happen\" contract every reorder here keeps. Called on every\n * pointer move once the drag has opened; in full control of its own\n * hit-testing, against one destination or several.\n */\n resolveTarget: (\n clientX: number,\n clientY: number,\n id: string,\n ) => Target | null;\n onDrop: (target: Target, id: string) => void;\n}\n\nexport interface DragReorderApi<Target> {\n /** The item being dragged, for as long as the drag lasts. */\n draggedId: string | null;\n /** Where it would land if released now. */\n dropTarget: Target | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (\n id: string,\n grabElement: HTMLElement,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n /**\n * Whether the gesture that just ended was a drag rather than a click, for\n * a press that has something of its own to do with a click.\n *\n * Reading it clears it, so that a press which never opened a drag at all\n * does not see the last one's answer.\n */\n justDragged: () => boolean;\n}\n\n/**\n * The pointer mechanics behind every drag-to-reorder gesture in the grid —\n * capture, the drag threshold, the trailing ghost, and the click/drag\n * disambiguation `justDragged` reports — extracted so a column header drag\n * and a group-by chip drag (`useColumnDrag`, `useGroupByDrag`) share one\n * implementation and can only ever drift apart in their own hit-testing\n * (`resolveTarget`), not in how a pointer becomes a drag.\n *\n * Pointer events rather than HTML5 drag-and-drop, for the same reason\n * `useColumnDrag` originally chose them: `dragenter`/`dragleave` fire per\n * descendant, so a dragged item's own inner markup would each report the\n * target leaving and re-entering as the pointer crossed them.\n */\nexport default function useDragReorder<Target>({\n resolveTarget,\n onDrop,\n}: UseDragReorderOptions<Target>): DragReorderApi<Target> {\n const [draggedId, setDraggedId] = useState<string | null>(null);\n const [dropTarget, setDropTarget] = useState<Target | null>(null);\n const [ghostTransform, setGhostTransform] = useState<string | null>(null);\n const dragged = useRef(false);\n\n function justDragged(): boolean {\n const answer = dragged.current;\n dragged.current = false;\n return answer;\n }\n\n function startDrag(\n id: string,\n grabElement: HTMLElement,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const { pointerId, clientX: startX } = event;\n const grabX = startX - grabElement.getBoundingClientRect().left;\n let dragging = false;\n let target: Target | null = null;\n\n /** Keeps the grab offset, so the pointer holds the spot it picked up. */\n function placeGhost(x: number, y: number): void {\n setGhostTransform(`translate(${String(x - grabX)}px, ${String(y)}px)`);\n }\n\n function reset(): void {\n setGhostTransform(null);\n setDraggedId(null);\n setDropTarget(null);\n }\n\n startPointerGesture(grabElement, pointerId, {\n onMove(moveEvent) {\n const { clientX, clientY } = moveEvent;\n\n if (!dragging) {\n if (Math.abs(clientX - startX) < DRAG_THRESHOLD) {\n return;\n }\n dragging = true;\n // Latched for the `click` that follows the release, which is the\n // only thing that can tell a drag apart from a press in the same\n // spot.\n dragged.current = true;\n setDraggedId(id);\n }\n\n placeGhost(clientX, clientY);\n\n target = resolveTarget(clientX, clientY, id);\n setDropTarget(target);\n },\n onEnd() {\n const dropped = target;\n reset();\n if (dragging && dropped !== null) {\n onDrop(dropped, id);\n }\n },\n // Escape and a cancelled pointer both leave the order as it was.\n onCancel() {\n target = null;\n reset();\n },\n });\n }\n\n // A new object each render, as `useColumnDrag`/`useColumnResize` return:\n // the handlers close over `resolveTarget`/`onDrop`, and a stable identity\n // would buy nothing.\n return {\n draggedId,\n dropTarget,\n ghostTransform,\n startDrag,\n justDragged,\n };\n}\n","interface PointerGestureHandlers {\n onMove: (event: PointerEvent) => void;\n onEnd: () => void;\n onCancel: () => void;\n}\n\n/**\n * Wires up a pointer-driven gesture — capture, move tracking, and an\n * Escape-to-cancel — leaving the caller's `onMove`/`onEnd`/`onCancel` to own\n * the gesture's own domain logic (and any state reset that goes with it).\n *\n * A plain function rather than a hook: the caller already owns every piece of\n * state involved via closures, so there is nothing here for React to manage.\n */\nexport function startPointerGesture(\n element: HTMLElement,\n pointerId: number,\n handlers: PointerGestureHandlers,\n): void {\n element.setPointerCapture(pointerId);\n\n function stop(): void {\n element.removeEventListener(\"pointermove\", move);\n element.removeEventListener(\"pointerup\", end);\n element.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (element.hasPointerCapture(pointerId)) {\n element.releasePointerCapture(pointerId);\n }\n }\n\n function move(event: PointerEvent): void {\n handlers.onMove(event);\n }\n\n function end(): void {\n stop();\n handlers.onEnd();\n }\n\n function cancel(): void {\n stop();\n handlers.onCancel();\n }\n\n function onKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n cancel();\n }\n }\n\n element.addEventListener(\"pointermove\", move);\n element.addEventListener(\"pointerup\", end);\n element.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n}\n","import type { PointerEvent as ReactPointerEvent } from \"react\";\nimport type { GroupByState } from \"@gridkitjs/core\";\nimport {\n resolveGroupByDropTarget,\n type GroupByDropTarget,\n} from \"./groupByDropTarget\";\nimport useDragReorder from \"./useDragReorder\";\n\ninterface UseGroupByDragOptions {\n groupBy: GroupByState;\n onDrop: (movedColumnId: string, beforeColumnId: string | null) => void;\n}\n\nexport interface GroupByDragApi {\n /** The chip being dragged, for as long as the drag lasts. */\n draggedColumnId: string | null;\n /** Where it would land if released now. */\n dropTarget: GroupByDropTarget | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (columnId: string, event: ReactPointerEvent<HTMLElement>) => void;\n /** Whether the gesture that just ended was a drag rather than a click. */\n justDragged: () => boolean;\n}\n\n/**\n * Drag-to-reorder for chips inside the group-by bar, built on the same\n * `useDragReorder` mechanics `useColumnDrag` uses for headers — only the\n * hit-testing (`resolveGroupByDropTarget`, shared with a header dropped in\n * from outside the bar) differs.\n */\nexport default function useGroupByDrag({\n groupBy,\n onDrop,\n}: UseGroupByDragOptions): GroupByDragApi {\n const drag = useDragReorder<GroupByDropTarget>({\n resolveTarget: (clientX, clientY, movedId) =>\n resolveGroupByDropTarget(clientX, clientY, movedId, groupBy),\n onDrop: (target, movedId) => {\n onDrop(movedId, target.beforeColumnId);\n },\n });\n\n return {\n draggedColumnId: drag.draggedId,\n dropTarget: drag.dropTarget,\n ghostTransform: drag.ghostTransform,\n startDrag: (columnId, event) => {\n drag.startDrag(columnId, event.currentTarget, event);\n },\n justDragged: drag.justDragged,\n };\n}\n","import type { PointerEvent as ReactPointerEvent } from \"react\";\nimport {\n movesColumn,\n resolveDropBefore,\n resolveKeyboardDropTarget,\n type ColumnOrderState,\n type GroupByState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport {\n resolveGroupByDropTarget,\n type GroupByDropTarget,\n} from \"./groupByDropTarget\";\nimport useDragReorder, { elementAt, sideOf } from \"./useDragReorder\";\n\n/**\n * Where a drop would land. A second drop zone — the group-by bar — is a\n * second member here rather than a reshaping of this state, exactly as\n * originally planned: a header dragged past every other header and onto the\n * bar produces `\"group-by\"` instead of `\"column-order\"`, and `handleDrop`\n * switches on `kind`.\n */\nexport type DropTarget =\n { kind: \"column-order\"; beforeId: string | null } | GroupByDropTarget;\n\ninterface UseColumnDragOptions {\n order: ColumnOrderState;\n /** What a drop onto the group-by bar is resolved against. */\n groupBy: GroupByState;\n /** Column ids whose header may be dragged into the group-by bar at all. */\n groupByDraggableIds: ReadonlySet<string>;\n onDrop: (target: DropTarget, movedId: string) => void;\n}\n\nexport interface ColumnDragApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n draggedColumnId: string | null;\n /** Where it would land if released now. */\n dropTarget: DropTarget | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n /** Moves a column one place left (`-1`) or right (`1`). */\n moveByKeyboard: (entry: ResolvedColumn<Row>, direction: -1 | 1) => void;\n /**\n * Whether the gesture that just ended was a drag rather than a click, for a\n * header that has something of its own to do with a click.\n *\n * Reading it clears it, so that a press which never opened a drag at all —\n * on a column that cannot be reordered — does not see the last one's answer.\n */\n justDragged: () => boolean;\n}\n\n/**\n * Turns a pointer drag over the header into a drop target, leaving `onDrop` to\n * apply it. Built on `useDragReorder`'s shared pointer mechanics — this hook\n * supplies only the hit-testing: another header (reorder among columns) or\n * the group-by bar (add this column to the grouping), tried in that order.\n */\nexport default function useColumnDrag<Row>({\n order,\n groupBy,\n groupByDraggableIds,\n onDrop,\n}: UseColumnDragOptions): ColumnDragApi<Row> {\n const drag = useDragReorder<DropTarget>({\n resolveTarget(clientX, clientY, movedId) {\n // Hit-tested rather than read from the event's target, which pointer\n // capture pins to the header the drag opened on.\n const over = elementAt(clientX, clientY, \"th[data-gridkit-column]\");\n const overId = over?.getAttribute(\"data-gridkit-column\");\n\n // The rect is read fresh each move, so a width changed mid-drag\n // cannot leave the midpoint stale.\n const beforeId =\n over && overId\n ? resolveDropBefore(order, overId, sideOf(over, clientX))\n : undefined;\n\n if (beforeId !== undefined) {\n // A gap the column already sits in would promise a move that\n // `moveColumnBefore` then declines to make.\n return movesColumn(order, movedId, beforeId)\n ? { kind: \"column-order\", beforeId }\n : null;\n }\n\n // Already grouped: reordering it is the chip's job, not the header's —\n // dragging it back into the bar is never a valid target.\n const alreadyGrouped = groupBy.some(\n (entry) => entry.columnId === movedId,\n );\n\n return groupByDraggableIds.has(movedId) && !alreadyGrouped\n ? resolveGroupByDropTarget(clientX, clientY, movedId, groupBy)\n : null;\n },\n onDrop,\n });\n\n function startDrag(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n drag.startDrag(entry.id, event.currentTarget, event);\n }\n\n function moveByKeyboard(entry: ResolvedColumn<Row>, direction: -1 | 1): void {\n const beforeId = resolveKeyboardDropTarget(order, entry.id, direction);\n if (beforeId === undefined) {\n return;\n }\n onDrop({ kind: \"column-order\", beforeId }, entry.id);\n }\n\n // A new object each render, as `useColumnResize` returns: the handlers close\n // over `order`/`groupBy`, and a stable identity would buy nothing.\n return {\n draggedColumnId: drag.draggedId,\n dropTarget: drag.dropTarget,\n ghostTransform: drag.ghostTransform,\n startDrag,\n moveByKeyboard,\n justDragged: drag.justDragged,\n };\n}\n","import {\n useState,\n type Dispatch,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n type SetStateAction,\n} from \"react\";\nimport {\n applyColumnResize,\n beginColumnResize,\n clampColumnWidth,\n resolveColumnConstraints,\n revertColumnSize,\n sizeColumnToContent,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport measureColumnContent from \"./measureColumnContent\";\nimport { startPointerGesture } from \"./pointerGesture\";\n\ninterface UseColumnResizeOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n sizing: ColumnSizingState;\n setSizing: Dispatch<SetStateAction<ColumnSizingState>>;\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport interface ColumnResizeApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n activeColumnId: string | null;\n startResize: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n sizeToContent: (entry: ResolvedColumn<Row>) => void;\n nudge: (entry: ResolvedColumn<Row>, delta: number) => void;\n}\n\n/**\n * Turns pointer and keyboard input into column widths. Every width it produces\n * comes from `@gridkitjs/core`; this hook only supplies the coordinates.\n */\nexport default function useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n}: UseColumnResizeOptions): ColumnResizeApi<Row> {\n const [activeColumnId, setActiveColumnId] = useState<string | null>(null);\n\n /**\n * Deliberately not built on `commitIfChanged`: its \"move\" phase is called\n * on every pointer move, including ones pinned against a min/max clamp\n * where the resulting width doesn't change, and it intentionally fires\n * `onColumnResize` anyway rather than adopting the bail-if-unchanged guard\n * every other commit-style call site has.\n */\n function commit(\n base: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n const next = { ...base, [columnId]: width };\n setSizing(next);\n onColumnResize?.({ columnId, width, sizing: next, phase });\n }\n\n function startResize(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const handle = event.currentTarget;\n const { pointerId } = event;\n const session = beginColumnResize(\n entry.column,\n entry.width,\n event.clientX,\n columnSizeDefaults,\n );\n /**\n * Only the dragged column can change while the drag lasts, so the state as\n * it was when the drag opened stays a correct base to merge into — no ref\n * mirror is needed to dodge a stale closure.\n */\n const base = sizing;\n let width = session.startWidth;\n\n // Otherwise the drag selects the header text it started on.\n event.preventDefault();\n event.stopPropagation();\n setActiveColumnId(session.columnId);\n\n startPointerGesture(handle, pointerId, {\n onMove(moveEvent) {\n width = applyColumnResize(session, moveEvent.clientX);\n commit(base, session.columnId, width, \"move\");\n },\n onEnd() {\n setActiveColumnId(null);\n // A click with no intervening `move` — as every double-click's two\n // constituent clicks are — leaves `width` at `startWidth`. Committing\n // that anyway would fire a spurious onColumnResize on every click.\n if (width !== session.startWidth) {\n commit(base, session.columnId, width, \"end\");\n }\n },\n /**\n * Escape puts back only the dragged column's pre-drag width, merged\n * into whatever the sizing state is *now* — not the `base` snapshot\n * taken at drag-start — so a different column resized via keyboard\n * while this drag was still open keeps its change instead of being\n * clobbered by a stale restore.\n */\n onCancel() {\n setActiveColumnId(null);\n setSizing((current) => {\n const next = revertColumnSize(current, base, session.columnId);\n onColumnResize?.({\n columnId: session.columnId,\n width: session.startWidth,\n sizing: next,\n phase: \"end\",\n });\n return next;\n });\n },\n });\n }\n\n function sizeToContent(entry: ResolvedColumn<Row>): void {\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n\n const measured = measureColumnContent(table, entry.id);\n if (measured === null) {\n return;\n }\n\n commit(\n sizing,\n entry.id,\n sizeColumnToContent(\n measured,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n function nudge(entry: ResolvedColumn<Row>, delta: number): void {\n commit(\n sizing,\n entry.id,\n clampColumnWidth(\n entry.width + delta,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n // Deliberately a new object each render: the handlers close over `sizing` to\n // merge into, and a stable identity would need either `sizing` in a\n // `useCallback` dep list (no gain) or the ref mirror avoided above.\n return { activeColumnId, startResize, sizeToContent, nudge };\n}\n","/**\n * The width the widest cell in `columnId` needs to show its content in full,\n * or `null` when the column has no cells.\n *\n * Measured with a `Range` over each cell's contents rather than the cell's own\n * `scrollWidth`. A range shrink-wraps what is actually laid out, so a column\n * far wider than its content reports the content width and can be sized *down*;\n * `scrollWidth` never reports less than the cell it is read from and so can\n * only ever grow a column.\n *\n * Only rendered rows are measured — once paging or virtualisation lands, that\n * means the visible ones.\n */\nexport default function measureColumnContent(\n table: HTMLTableElement,\n columnId: string,\n): number | null {\n const cells = table.querySelectorAll<HTMLElement>(\n `td[data-gridkit-column=\"${CSS.escape(columnId)}\"]`,\n );\n const range = document.createRange();\n let widest: number | null = null;\n\n for (const cell of cells) {\n range.selectNodeContents(cell);\n const style = getComputedStyle(cell);\n // The range covers the content box only, so the cell's own spacing has to\n // be added back or the column would clip by exactly its padding.\n const width =\n range.getBoundingClientRect().width +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth);\n\n if (widest === null || width > widest) {\n widest = width;\n }\n }\n\n return widest;\n}\n","import type { Dispatch, SetStateAction } from \"react\";\nimport {\n sortDirectionFor,\n sortPriorityFor,\n toggleColumnSort,\n type ColumnSortEvent,\n type ColumnSortState,\n type SortDirection,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\ninterface UseColumnSortOptions {\n sort: ColumnSortState;\n setSort: Dispatch<SetStateAction<ColumnSortState>>;\n onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;\n}\n\nexport interface ColumnSortApi<Row> {\n sort: ColumnSortState;\n /** This column's direction, or `null` if it takes no part in the sort. */\n directionFor: (columnId: string) => SortDirection | null;\n /**\n * This column's 1-based place in the stack, or `null` outside it. Only\n * meaningful once two or more columns are stacked.\n */\n priorityFor: (columnId: string) => number | null;\n /** Cycles `entry`'s sort. A `shiftKey` stacks it; its absence replaces the stack. */\n toggle: (entry: ResolvedColumn<Row>, event: { shiftKey: boolean }) => void;\n}\n\n/**\n * Turns a click or keypress into a sort. Every transition it produces comes\n * from `@gridkitjs/core`; this hook only supplies the state to transform and\n * reports the result.\n */\nexport default function useColumnSort<Row>({\n sort,\n setSort,\n onColumnSortChange,\n}: UseColumnSortOptions): ColumnSortApi<Row> {\n function toggle(\n entry: ResolvedColumn<Row>,\n event: { shiftKey: boolean },\n ): void {\n const next = toggleColumnSort(sort, entry.id, { stack: event.shiftKey });\n commitIfChanged(sort, next, setSort, (committed) => {\n onColumnSortChange?.({ columnId: entry.id, sort: committed });\n });\n }\n\n // A new object each render, as the other hooks here return.\n return {\n sort,\n directionFor: (columnId) => sortDirectionFor(sort, columnId),\n priorityFor: (columnId) => sortPriorityFor(sort, columnId),\n toggle,\n };\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * The inner width of `ref`'s element, tracked as it changes.\n *\n * A layout effect rather than an effect so the first measurement lands before\n * paint — otherwise columns show at their natural width for a frame and then\n * visibly jump once auto-fit runs. Server rendering would want the usual\n * isomorphic-layout-effect shim here.\n *\n * Reads `clientWidth` rather than the observer entry's `contentRect` so the\n * first measurement and every later one come from the same, already-rounded,\n * source.\n *\n * @param enabled Whether to observe at all. A caller that does not read the\n * width passes `false` rather than paying a re-render of the whole grid on\n * every frame of a window resize.\n */\nexport default function useElementWidth(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean,\n): number | null {\n const [width, setWidth] = useState<number | null>(null);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (element === null || !enabled) {\n return undefined;\n }\n\n setWidth(element.clientWidth);\n\n const observer = new ResizeObserver(() => {\n setWidth(element.clientWidth);\n });\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref, enabled]);\n\n return width;\n}\n","import type { Dispatch, SetStateAction } from \"react\";\nimport {\n paginateRows,\n type DisplayRow,\n type PaginationChangeEvent,\n type PaginationState,\n} from \"@gridkitjs/core\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\ninterface UsePaginationOptions<Row> {\n pagination: PaginationState;\n setPagination: Dispatch<SetStateAction<PaginationState>>;\n /** The rows pagination slices — needed to clamp `goToPage`/`setPageSize` against the current `pageCount`. */\n rows: readonly DisplayRow<Row>[];\n onPaginationChange?: ((event: PaginationChangeEvent) => void) | undefined;\n}\n\nexport interface PaginationApi {\n pagination: PaginationState;\n pageCount: number;\n /** `pagination.pageIndex + 1`, clamped to `pageCount` — the display-ready page number. */\n currentPage: number;\n goToPage: (pageIndex: number) => void;\n nextPage: () => void;\n previousPage: () => void;\n setPageSize: (pageSize: number) => void;\n}\n\n/**\n * Turns a page-index or page-size change into the next `PaginationState`,\n * committing through `commitIfChanged` exactly as `useColumnSort` does, so a\n * no-op neither re-renders nor fires `onPaginationChange`.\n *\n * `goToPage`/`setPageSize` route every candidate value back through\n * `paginateRows` itself rather than clamping by hand, so this hook can never\n * drift out of step with the clamping `paginateRows` already does for\n * `DataGrid.tsx`'s own render pass.\n */\nexport default function usePagination<Row>({\n pagination,\n setPagination,\n rows,\n onPaginationChange,\n}: UsePaginationOptions<Row>): PaginationApi {\n const { pageCount, pageIndex } = paginateRows(rows, pagination);\n\n function commit(next: PaginationState): void {\n commitIfChanged(pagination, next, setPagination, (committed) => {\n const { pageCount: committedPageCount } = paginateRows(rows, committed);\n onPaginationChange?.({\n pagination: committed,\n pageCount: committedPageCount,\n });\n });\n }\n\n function goToPage(nextPageIndex: number): void {\n const { pageIndex: clamped } = paginateRows(rows, {\n ...pagination,\n pageIndex: nextPageIndex,\n });\n commit({ ...pagination, pageIndex: clamped });\n }\n\n return {\n pagination,\n pageCount,\n currentPage: Math.min(pagination.pageIndex + 1, pageCount),\n goToPage,\n nextPage: () => {\n goToPage(pageIndex + 1);\n },\n previousPage: () => {\n goToPage(pageIndex - 1);\n },\n setPageSize: (pageSize) => {\n // A page-size change resets to the first page: the current pageIndex\n // was measured against the old size and has no meaningful equivalent\n // under the new one.\n const next = { pageIndex: 0, pageSize };\n const { pageIndex: clamped } = paginateRows(rows, next);\n commit({ ...next, pageIndex: clamped });\n },\n };\n}\n","import type { Dispatch, SetStateAction } from \"react\";\nimport {\n collapseAllGroups,\n expandAllGroups,\n moveGroupByBefore,\n toggleGroupExpansion,\n type DisplayRow,\n type GroupByEvent,\n type GroupByState,\n type GroupExpansionEvent,\n type GroupExpansionState,\n} from \"@gridkitjs/core\";\nimport { commitIfChanged } from \"./commitIfChanged\";\n\ninterface UseRowGroupingOptions {\n groupBy: GroupByState;\n setGroupBy: Dispatch<SetStateAction<GroupByState>>;\n expansion: GroupExpansionState;\n setExpansion: Dispatch<SetStateAction<GroupExpansionState>>;\n onGroupByChange?: ((event: GroupByEvent) => void) | undefined;\n onGroupExpansionChange?: ((event: GroupExpansionEvent) => void) | undefined;\n}\n\nexport interface RowGroupingApi<Row> {\n groupBy: GroupByState;\n expansion: GroupExpansionState;\n isExpanded: (groupId: string) => boolean;\n toggleExpansion: (groupId: string) => void;\n expandAll: () => void;\n collapseAll: (rows: readonly DisplayRow<Row>[]) => void;\n /** Appends or removes columnId from the group-by stack — the state change a group-bar drop or a \"group by this column\" header action produces. */\n toggleGroupBy: (columnId: string) => void;\n /**\n * Adds `columnId` to the group-by stack at a position, or repositions it\n * if it's already there — what dragging a header into the bar, dragging a\n * chip within it, or `Ctrl+ArrowLeft`/`Ctrl+ArrowRight` on a focused chip\n * all produce.\n */\n moveGroupBy: (columnId: string, beforeColumnId: string | null) => void;\n}\n\n/**\n * Turns a group-header click, a \"group by this column\" action, or a\n * group-bar rearrange into the next `GroupByState`/`GroupExpansionState`,\n * committing through `commitIfChanged` exactly as `useColumnSort` does, so a\n * no-op neither re-renders nor fires its `onChange`.\n */\nexport default function useRowGrouping<Row>({\n groupBy,\n setGroupBy,\n expansion,\n setExpansion,\n onGroupByChange,\n onGroupExpansionChange,\n}: UseRowGroupingOptions): RowGroupingApi<Row> {\n function commitExpansion(\n next: GroupExpansionState,\n groupId: string | null,\n ): void {\n commitIfChanged(expansion, next, setExpansion, (committed) => {\n onGroupExpansionChange?.({ groupId, expansion: committed });\n });\n }\n\n function commitGroupBy(next: GroupByState, columnId: string): void {\n commitIfChanged(groupBy, next, setGroupBy, (committed) => {\n onGroupByChange?.({ columnId, groupBy: committed });\n });\n }\n\n function toggleGroupBy(columnId: string): void {\n const isGrouped = groupBy.some((entry) => entry.columnId === columnId);\n const next = isGrouped\n ? groupBy.filter((entry) => entry.columnId !== columnId)\n : [...groupBy, { columnId }];\n commitGroupBy(next, columnId);\n }\n\n function moveGroupBy(columnId: string, beforeColumnId: string | null): void {\n commitGroupBy(\n moveGroupByBefore(groupBy, columnId, beforeColumnId),\n columnId,\n );\n }\n\n return {\n groupBy,\n expansion,\n isExpanded: (groupId) => !expansion.includes(groupId),\n toggleExpansion: (groupId) => {\n commitExpansion(toggleGroupExpansion(expansion, groupId), groupId);\n },\n expandAll: () => {\n commitExpansion(expandAllGroups(expansion), null);\n },\n collapseAll: (rows) => {\n commitExpansion(collapseAllGroups(rows), null);\n },\n toggleGroupBy,\n moveGroupBy,\n };\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { PaginationState } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_PAGINATION: PaginationState = { pageIndex: 0, pageSize: 0 };\n\nexport interface PaginationStateApi {\n pagination: PaginationState;\n pageCount: number;\n goToPage: (pageIndex: number) => void;\n nextPage: () => void;\n previousPage: () => void;\n setPageSize: (pageSize: number) => void;\n}\n\n/**\n * Reactive pagination state read off a mounted `DataGridComponent`'s `ref`,\n * for building a pager entirely outside the grid's own DOM — a toolbar or\n * sidebar `pager.template` can't reach. Updates on every pagination change,\n * including the silent page-0 reset a filter/sort/group change triggers,\n * which carries no `onPaginationChange` of its own.\n *\n * Before the grid mounts, `pagination` reads `{ pageIndex: 0, pageSize: 0 }`\n * and `pageCount` reads `0`; the actions are no-ops until then.\n */\nexport default function usePaginationState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): PaginationStateApi {\n const pagination = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getPagination(), []),\n FALLBACK_PAGINATION,\n );\n const pageCount = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getPageCount(), []),\n 0,\n );\n\n return {\n pagination,\n pageCount,\n goToPage: (pageIndex) => {\n gridRef.current?.goToPage(pageIndex);\n },\n nextPage: () => {\n gridRef.current?.nextPage();\n },\n previousPage: () => {\n gridRef.current?.previousPage();\n },\n setPageSize: (pageSize) => {\n gridRef.current?.setPageSize(pageSize);\n },\n };\n}\n","import { useCallback, useSyncExternalStore, type RefObject } from \"react\";\nimport type { DataGridApi } from \"../DataGrid\";\n\n/**\n * Shared `useSyncExternalStore` wiring behind every public `use*State` hook\n * in this folder. Not exported — `gridRef.current` is `null` until the grid\n * mounts, so subscribing has to tolerate that, and falls back to `fallback`\n * for the same reason `getSnapshot` has to until then.\n */\nexport default function useGridSnapshot<Row, T>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n getSnapshot: (api: DataGridApi<Row>) => T,\n fallback: T,\n): T {\n const subscribe = useCallback(\n (listener: () => void) => {\n const api = gridRef.current;\n if (api === null) {\n return () => {\n // Nothing was subscribed — `subscribe` itself already handles\n // that below by re-running on every render until the ref mounts.\n };\n }\n return api.subscribe(listener);\n },\n [gridRef],\n );\n\n return useSyncExternalStore(subscribe, () => {\n const api = gridRef.current;\n return api === null ? fallback : getSnapshot(api);\n });\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { GroupByState, GroupExpansionState } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_GROUP_BY: GroupByState = [];\nconst FALLBACK_EXPANSION: GroupExpansionState = [];\n\nexport interface GroupByStateApi {\n groupBy: GroupByState;\n groupExpansion: GroupExpansionState;\n expandAllGroups: () => void;\n collapseAllGroups: () => void;\n}\n\n/**\n * Reactive group-by and group-expansion state read off a mounted\n * `DataGridComponent`'s `ref`, for a group-by bar or summary sidebar living\n * outside the grid's own DOM.\n *\n * `DataGridApi` has no per-group toggle action today, only\n * `expandAllGroups`/`collapseAllGroups` — a custom group-by UI needing to\n * toggle a single group has no imperative action to call yet. A specific\n * group's own computed aggregates are read off `getDisplayRows()`'s\n * per-header `aggregates` field instead of a getter here — see\n * `useAggregateState` for the grand-total equivalent.\n *\n * Before the grid mounts, both fields read as empty and the actions are\n * no-ops.\n */\nexport default function useGroupByState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): GroupByStateApi {\n const groupBy = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getGroupBy(), []),\n FALLBACK_GROUP_BY,\n );\n const groupExpansion = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getGroupExpansion(), []),\n FALLBACK_EXPANSION,\n );\n\n return {\n groupBy,\n groupExpansion,\n expandAllGroups: () => {\n gridRef.current?.expandAllGroups();\n },\n collapseAllGroups: () => {\n gridRef.current?.collapseAllGroups();\n },\n };\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { ColumnSortState } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_SORT: ColumnSortState = [];\n\n/**\n * Reactive column-sort state read off a mounted `DataGridComponent`'s `ref`,\n * for a sort indicator living outside the grid's own DOM.\n *\n * `DataGridApi` has no sort-mutating action today — sort stays uncontrolled\n * via `defaultColumnSort`/the grid's own header UI, the same gap\n * `useGroupByState` has for group-by. Reads only.\n *\n * Before the grid mounts, reads as an empty array.\n */\nexport default function useColumnSortState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): ColumnSortState {\n return useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getColumnSort(), []),\n FALLBACK_SORT,\n );\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { CellSelectionState, SelectionState } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_SELECTION: SelectionState = [];\nconst FALLBACK_CELL_SELECTION: CellSelectionState = null;\n\nexport interface SelectionStateApi {\n rowSelection: SelectionState;\n columnSelection: SelectionState;\n cellSelection: CellSelectionState;\n clearSelection: () => void;\n selectAllRows: () => void;\n}\n\n/**\n * Reactive row/column/cell selection state read off a mounted\n * `DataGridComponent`'s `ref`, for a \"N rows selected\" toolbar living\n * outside the grid's own DOM. One combined hook rather than three, matching\n * how `useGridSelection` already treats all three as one concern\n * internally.\n *\n * Before the grid mounts, the row/column fields read as empty arrays and\n * the cell field reads `null`; the actions are no-ops.\n */\nexport default function useSelectionState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): SelectionStateApi {\n const rowSelection = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getRowSelection(), []),\n FALLBACK_SELECTION,\n );\n const columnSelection = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getColumnSelection(), []),\n FALLBACK_SELECTION,\n );\n const cellSelection = useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getCellSelection(), []),\n FALLBACK_CELL_SELECTION,\n );\n\n return {\n rowSelection,\n columnSelection,\n cellSelection,\n clearSelection: () => {\n gridRef.current?.clearSelection();\n },\n selectAllRows: () => {\n gridRef.current?.selectAllRows();\n },\n };\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { AggregateResults } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_AGGREGATES: AggregateResults = new Map();\n\n/**\n * Reactive grand-total aggregate results read off a mounted\n * `DataGridComponent`'s `ref`, for a summary footer or bar living outside\n * the grid's own DOM — mirroring the built-in one the grid renders itself.\n *\n * Read-only: `getAggregates` is already read-only on `DataGridApi`, computed\n * over the whole filtered/sorted dataset rather than driven by any action.\n * A specific group's own subtotal is read off `getDisplayRows()`'s\n * per-header `aggregates` field instead — see `useGroupByState`.\n *\n * Before the grid mounts, reads as an empty map.\n */\nexport default function useAggregateState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): AggregateResults {\n return useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getAggregates(), []),\n FALLBACK_AGGREGATES,\n );\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { ColumnSizingState } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_SIZING: ColumnSizingState = {};\n\n/**\n * Reactive column-sizing state read off a mounted `DataGridComponent`'s\n * `ref`. Read-only — sizing stays uncontrolled via `defaultColumnSizing`/the\n * grid's own resize handles, the same gap `useColumnSortState` has for sort.\n *\n * Before the grid mounts, reads as an empty object.\n */\nexport default function useColumnSizingState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): ColumnSizingState {\n return useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getColumnSizing(), []),\n FALLBACK_SIZING,\n );\n}\n","import { useCallback, type RefObject } from \"react\";\nimport type { ColumnOrderState } from \"@gridkitjs/core\";\nimport type { DataGridApi } from \"../DataGrid\";\nimport useGridSnapshot from \"./useGridSnapshot\";\n\nconst FALLBACK_ORDER: ColumnOrderState = [];\n\n/**\n * Reactive column-order state read off a mounted `DataGridComponent`'s\n * `ref`. Read-only — order stays uncontrolled via `defaultColumnOrder`/the\n * grid's own header drag, the same gap `useColumnSortState` has for sort.\n *\n * Before the grid mounts, reads as an empty array.\n */\nexport default function useColumnOrderState<Row>(\n gridRef: RefObject<DataGridApi<Row> | null>,\n): ColumnOrderState {\n return useGridSnapshot(\n gridRef,\n useCallback((api: DataGridApi<Row>) => api.getColumnOrder(), []),\n FALLBACK_ORDER,\n );\n}\n"],"mappings":"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","names":["useEffect","useMemo","useRef","useState","paginateRows","useMemo","useRef","useMemo","useRef","useMemo","intentOf","jsx","jsxs","memo","jsx","jsxs","memo","memo","jsx","memo","jsx","useMemo","intentOf","jsx","jsx","jsxs","createPortal","useRef","useState","useState","useRef","jsx","jsxs","createPortal","resolveDropBefore","resolveKeyboardDropTarget","resolveDropBefore","resolveKeyboardDropTarget","useState","useState","useState","jsx","jsxs","useRef","useState","useMemo","paginateRows","useEffect","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback"]}