@gridkitjs/core 0.7.0 → 0.9.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.d.ts CHANGED
@@ -35,16 +35,27 @@ interface CellTemplateContext<Row> {
35
35
  value: unknown;
36
36
  /** The whole row, for a template that needs a sibling field. */
37
37
  row: Row;
38
- /**
39
- * Position among the rows as rendered. Once paging exists this is the index
40
- * within the page; an index into the whole dataset would be a second field.
41
- */
38
+ /** Position among the rows as rendered — the index within the current page once paging is on. */
42
39
  rowIndex: number;
40
+ /** This row's absolute position in the whole filtered/sorted/grouped dataset, unaffected by which page is showing. */
41
+ datasetIndex: number;
43
42
  /** This row's id, as `resolveRowId` settled it. */
44
43
  rowId: string;
45
44
  /** Whether this row is selected, so a template can style itself to match. */
46
45
  selected: boolean;
47
46
  }
47
+ /**
48
+ * What a column's `footerTemplate` receives. Mirrors `CellTemplateContext`'s
49
+ * shape where it applies — `value`, `rows` — minus everything scoped to one
50
+ * rendered row (`rowIndex`, `rowId`, `selected`), since a footer addresses
51
+ * every row an aggregate was computed over at once, not a single one.
52
+ */
53
+ interface FooterTemplateContext<Row> {
54
+ /** This column's aggregate result, as `computeAggregates` produced it. */
55
+ value: unknown;
56
+ /** Every row the aggregate was computed over — the grand total's full dataset, or one group's full leaf descendants. */
57
+ rows: readonly Row[];
58
+ }
48
59
  /**
49
60
  * @typeParam Node - What a header or cell renders to. This package is
50
61
  * framework-agnostic so it defaults to `string`; `@gridkitjs/react` binds it to
@@ -71,6 +82,13 @@ interface ColumnDefinition<Row, Node = string> {
71
82
  * it never repeats the field path.
72
83
  */
73
84
  cellTemplate?: ((context: CellTemplateContext<Row>) => Node) | undefined;
85
+ /**
86
+ * Renders this column's own aggregate result in a group footer or the
87
+ * grand-total footer, in place of the raw computed value. Absent for a
88
+ * column with no aggregate: nothing is shown, the same way a column
89
+ * missing from `AggregateState` contributes no cell to either footer.
90
+ */
91
+ footerTemplate?: ((context: FooterTemplateContext<Row>) => Node) | undefined;
74
92
  /**
75
93
  * The value type of this column's cells. This package is framework-agnostic so it
76
94
  * defaults to `string`;
@@ -99,6 +117,24 @@ interface ColumnDefinition<Row, Node = string> {
99
117
  reorderable?: boolean;
100
118
  /** Whether this column can be sorted, overriding the grid-level default. */
101
119
  sortable?: boolean;
120
+ /** Whether this column can be grouped by, overriding the grid-level default. */
121
+ groupable?: boolean;
122
+ /**
123
+ * Whether this column's header shows its group-toggle icon, overriding
124
+ * the grid-level default. Purely a rendering choice — it does not affect
125
+ * whether the column can be grouped by (`groupable`) or the
126
+ * `Alt+ArrowDown` shortcut, which keeps working with the icon hidden, the
127
+ * same way the resize handle stays `aria-hidden` while `Alt+ArrowLeft`/
128
+ * `ArrowRight` still resize.
129
+ */
130
+ groupToggleIcon?: boolean;
131
+ /**
132
+ * Whether this column's header may be dragged into the group-by bar to
133
+ * add it to the active grouping, overriding the grid-level default.
134
+ * Distinct from `groupable`: a column can be groupable via its header's
135
+ * click/`Alt+ArrowDown` toggle, via this drag, both, or neither.
136
+ */
137
+ groupByDraggable?: boolean;
102
138
  /**
103
139
  * Lets this column's header and/or cell text wrap onto multiple lines
104
140
  * instead of the grid's default single line with an ellipsis. Off by
@@ -132,6 +168,16 @@ interface ColumnWrapConfig {
132
168
  * still takes effect, and resetting is discarding the state.
133
169
  */
134
170
  type ColumnSizingState = Readonly<Record<string, number>>;
171
+ /** The active page, and how many rows/units make one up. */
172
+ interface PaginationState {
173
+ readonly pageIndex: number;
174
+ readonly pageSize: number;
175
+ }
176
+ /** Reports a user page/page-size change whole — the one to persist from, mirroring ColumnSortEvent. */
177
+ interface PaginationChangeEvent {
178
+ readonly pagination: PaginationState;
179
+ readonly pageCount: number;
180
+ }
135
181
  /** Sizes used for a column that does not specify its own. */
136
182
  interface ColumnSizeDefaults {
137
183
  width: number;
@@ -153,6 +199,8 @@ interface ColumnResolveOptions {
153
199
  resizable?: boolean | undefined;
154
200
  /** Whether columns are reorderable, unless a column says otherwise. */
155
201
  reorderable?: boolean | undefined;
202
+ /** Whether columns may be dragged into the group-by bar, unless a column says otherwise. */
203
+ groupByDraggable?: boolean | undefined;
156
204
  }
157
205
  /**
158
206
  * A column paired with everything it takes to render it. Each field is a
@@ -179,6 +227,8 @@ interface ResolvedColumn<Row, Node = string> {
179
227
  resizable: boolean;
180
228
  /** Whether this column can be dragged, after the grid-level default. */
181
229
  reorderable: boolean;
230
+ /** Whether this column's header may be dragged into the group-by bar, after the grid-level default. */
231
+ groupByDraggable: boolean;
182
232
  /** How this column's cells align, after falling back to its type. */
183
233
  alignment: ColumnAlignment;
184
234
  }
@@ -242,6 +292,150 @@ interface ColumnSortEvent {
242
292
  readonly columnId: string;
243
293
  readonly sort: ColumnSortState;
244
294
  }
295
+ /** One level of a stacked group-by, outer to inner. Mirrors ColumnSortEntry. */
296
+ interface GroupByEntry {
297
+ readonly columnId: string;
298
+ /** Order of this level's own group values (not row order within a group). Defaults to "asc". */
299
+ readonly direction?: SortDirection;
300
+ }
301
+ /**
302
+ * The active grouping, outer to inner: index 0 groups first, each
303
+ * subsequent index nests inside it. Empty for an ungrouped grid, mirroring
304
+ * ColumnSortState's empty array for "no sort".
305
+ */
306
+ type GroupByState = readonly GroupByEntry[];
307
+ /**
308
+ * Reports a user group-by change whole — the stack to persist from. Mirrors
309
+ * ColumnSortEvent's `{columnId, sort}` shape.
310
+ */
311
+ interface GroupByEvent {
312
+ readonly columnId: string;
313
+ readonly groupBy: GroupByState;
314
+ }
315
+ /**
316
+ * Group keys collapsed by the user — holding only the exceptions, the same
317
+ * way ColumnSizingState holds only resized widths. A key absent from this
318
+ * set is expanded; there is no separate "collapsed by default" concept.
319
+ */
320
+ type GroupExpansionState = readonly string[];
321
+ /**
322
+ * Reports a user expansion change. `groupId` is the group toggled, or `null`
323
+ * for expandAllGroups/collapseAllGroups, which touch every group in one call
324
+ * rather than one at a time.
325
+ */
326
+ interface GroupExpansionEvent {
327
+ readonly groupId: string | null;
328
+ readonly expansion: GroupExpansionState;
329
+ }
330
+ /**
331
+ * One group header in a grouped result. `path` is every ancestor value
332
+ * down to and including this group's own, outermost first — what a header
333
+ * template needs to render "West / Enterprise", not just "Enterprise".
334
+ *
335
+ * Not parameterized by `Row`: nothing here holds a `Row`-typed value today —
336
+ * `aggregates` holds computed `unknown` results, not rows themselves.
337
+ */
338
+ interface ResolvedGroupRow {
339
+ readonly kind: "group";
340
+ /** Stable id for this node: this plan's join of `path`, used as the React key and the GroupExpansionState entry. Opaque — build it with `groupRowId`, never construct one by hand. */
341
+ readonly groupId: string;
342
+ /** Nesting depth, 0 for a top-level group. */
343
+ readonly level: number;
344
+ readonly columnId: string;
345
+ /** This level's own value — the last entry of `path`. */
346
+ readonly value: unknown;
347
+ readonly path: readonly unknown[];
348
+ readonly expanded: boolean;
349
+ /** Leaf row count under this group, regardless of collapse state. */
350
+ readonly count: number;
351
+ /** Position among the display rows as rendered — same invariant ResolvedRow.rowIndex keeps. */
352
+ readonly rowIndex: number;
353
+ /** This header's absolute position in the whole filtered/sorted/grouped dataset, matching ResolvedRow.datasetIndex. */
354
+ readonly datasetIndex: number;
355
+ /**
356
+ * This group's own aggregate results, computed over its full leaf-row
357
+ * descendants regardless of collapse state — see `withGroupAggregates`.
358
+ * Empty when no `AggregateState` is active.
359
+ */
360
+ readonly aggregates: AggregateResults;
361
+ }
362
+ /**
363
+ * A group's own aggregate results, rendered as a row of its own rather than
364
+ * inline in its header — see `groupAggregateDisplay: "row"`. Emitted by
365
+ * `withGroupAggregates` immediately after a group's last visible
366
+ * descendant (its last nested group or data row, or immediately after its
367
+ * own header when collapsed), at that same group's `level`, one per group
368
+ * with `AggregateState` active — mirroring `ResolvedGroupRow` closely
369
+ * enough that the two are meant to be read side by side.
370
+ */
371
+ interface ResolvedGroupSummaryRow {
372
+ readonly kind: "group-summary";
373
+ /** The group this summary belongs to — shared with that group's own `ResolvedGroupRow.groupId`, not a new id of its own. */
374
+ readonly groupId: string;
375
+ /** Nesting depth, matching the group's own `level`. */
376
+ readonly level: number;
377
+ /** Position among the display rows as rendered — same invariant every other DisplayRow's `rowIndex` keeps. */
378
+ readonly rowIndex: number;
379
+ /** This row's absolute position in the whole filtered/sorted/grouped dataset, matching ResolvedRow.datasetIndex. */
380
+ readonly datasetIndex: number;
381
+ /** This group's own aggregate results — identical to its `ResolvedGroupRow.aggregates`, computed once and shared rather than recomputed. */
382
+ readonly aggregates: AggregateResults;
383
+ }
384
+ /**
385
+ * One entry of a grouped result: an ordinary data row (no `kind` field at
386
+ * all — ResolvedRow is unchanged, so every existing consumer of plain
387
+ * ResolvedRow[] keeps compiling), a group header, or — only when
388
+ * `groupAggregateDisplay: "row"` is active — that group's own summary row.
389
+ * Discriminate with `"kind" in entry`, then `entry.kind`.
390
+ */
391
+ type DisplayRow<Row> = ResolvedRow<Row> | ResolvedGroupRow | ResolvedGroupSummaryRow;
392
+ /** A reducer this package computes without a custom `AggregateFn`. */
393
+ type BuiltInAggregate = "sum" | "avg" | "min" | "max" | "count" | "countDistinct";
394
+ /**
395
+ * Called with every raw row in scope — always the full leaf set, never a
396
+ * partial reduction combined from child groups, so a non-associative
397
+ * aggregate (median, distinct count) is never computed from
398
+ * already-aggregated values. Mirrors `FilterPredicate`'s shape, minus the
399
+ * per-row `value` since an aggregate reduces across rows rather than
400
+ * testing one.
401
+ */
402
+ type AggregateFn<Row> = (rows: readonly Row[]) => unknown;
403
+ /** One aggregate to compute against a column — a built-in reducer, or custom logic via `fn`. */
404
+ interface AggregateSpec<Row> {
405
+ readonly columnId: string;
406
+ readonly fn: BuiltInAggregate | AggregateFn<Row>;
407
+ /** Distinguishes two aggregates on the same column (e.g. both sum and avg of Amount). Defaults to columnId, mirroring ColumnDefinition.id defaulting to field. */
408
+ readonly id?: string;
409
+ /**
410
+ * Overrides this aggregate's own cell alignment, in the grand-total
411
+ * footer and a group's own summary row (`groupAggregateDisplay: "row"`)
412
+ * — inline rendering (`"inline"`) is text, not a cell, so this has no
413
+ * effect there. Falls back to the column's own `alignment` when omitted.
414
+ * When two specs share a column and disagree, the first one in
415
+ * `AggregateState` wins for that shared cell, since one `<td>` can only
416
+ * take one `text-align`.
417
+ */
418
+ readonly alignment?: ColumnAlignment;
419
+ }
420
+ /**
421
+ * The active aggregates to compute. Empty for a grid with none, mirroring
422
+ * `FilterState`'s empty array for "no filter". A fully controlled prop —
423
+ * unlike `sort`/`filter`/`groupBy`/`pagination`, there is no built-in UI
424
+ * affordance for a user to add or remove an aggregate interactively.
425
+ */
426
+ type AggregateState<Row> = readonly AggregateSpec<Row>[];
427
+ /** One computed aggregate result, keyed by `spec.id ?? spec.columnId`. */
428
+ type AggregateResults = ReadonlyMap<string, unknown>;
429
+ /**
430
+ * Where a group's own aggregate results render. `"inline"` (the default)
431
+ * keeps them as text in the group header itself, next to its leaf-row
432
+ * count. `"row"` instead emits a `ResolvedGroupSummaryRow` immediately
433
+ * after that group's last visible descendant, with each aggregate's value
434
+ * in the `<td>` for its own column — the same alignment a grand-total
435
+ * footer cell has to its column, just scoped to one group instead of the
436
+ * whole dataset.
437
+ */
438
+ type GroupAggregateDisplay = "inline" | "row";
245
439
  interface FilterEntryBase<Row> {
246
440
  readonly columnId?: FieldPath<Row> | (string & {});
247
441
  }
@@ -363,6 +557,8 @@ interface ResolvedRow<Row> {
363
557
  readonly row: Row;
364
558
  /** Position among the rows as rendered, matching `CellTemplateContext`. */
365
559
  readonly rowIndex: number;
560
+ /** This row's absolute position in the whole filtered/sorted/grouped dataset, matching `CellTemplateContext`. */
561
+ readonly datasetIndex: number;
366
562
  }
367
563
  /**
368
564
  * A selected column. Carries the resolved column rather than the bare
@@ -487,6 +683,7 @@ interface KeyShortcutCapabilities {
487
683
  reorderable: boolean;
488
684
  resizable: boolean;
489
685
  sortable: boolean;
686
+ groupable: boolean;
490
687
  }
491
688
  /**
492
689
  * The `aria-keyshortcuts` string for a column header, naming only the keys
@@ -534,8 +731,16 @@ declare function clampFocus(focus: GridFocus, rowCount: number, columnCount: num
534
731
  * `pageSize` is a pre-measured row count rather than a callback: this
535
732
  * function takes plain data only, so a caller measures the viewport once and
536
733
  * hands over the number.
537
- */
538
- declare function nextFocusForKey(key: string, modifiers: NavigationModifiers, focus: GridFocus, rowCount: number, columnCount: number, pageSize: number): GridFocus | null;
734
+ *
735
+ * `isSkippableRow` names rows the vertical moves (`ArrowUp`/`ArrowDown`/
736
+ * `PageUp`/`PageDown`/`Ctrl+End`) never land a tab stop on — a group's own
737
+ * summary row (`groupAggregateDisplay: "row"`), which still occupies a real
738
+ * row slot for `rowCount`/`aria-rowindex` purposes but is presentational,
739
+ * not a stop of its own. Left/right and plain `Home`/`End` stay row-scoped
740
+ * and so never consult it. Defaults to skipping nothing, so every existing
741
+ * caller (and every horizontal move) is unaffected.
742
+ */
743
+ declare function nextFocusForKey(key: string, modifiers: NavigationModifiers, focus: GridFocus, rowCount: number, columnCount: number, pageSize: number, isSkippableRow?: (rowIndex: number) => boolean): GridFocus | null;
539
744
 
540
745
  /**
541
746
  * Puts `columns` in the order `order` gives. Ids it lists come first, in that
@@ -819,6 +1024,82 @@ declare function clearAllFilters<Row>(filter: FilterState<Row>): FilterState<Row
819
1024
  */
820
1025
  declare function filterRows<Row>(rows: readonly ResolvedRow<Row>[], filter: FilterState<Row>, columns: readonly ResolvedColumn<Row, unknown>[]): readonly ResolvedRow<Row>[];
821
1026
 
1027
+ /**
1028
+ * This group's id, from its path. Every group-id producer/consumer in this
1029
+ * package goes through this — never join `path` by hand elsewhere.
1030
+ *
1031
+ * `JSON.stringify` rather than a delimiter join: a delimiter would have to be
1032
+ * escaped in every segment to stay collision-free against a value that
1033
+ * legitimately contains it, and `JSON.stringify` already draws that
1034
+ * boundary between array entries for free.
1035
+ */
1036
+ declare function groupRowId(path: readonly unknown[]): string;
1037
+ /**
1038
+ * `rows`, regrouped into `groupBy`'s stacked levels — a group header per
1039
+ * distinct value at each level, ordered by `compareValues` per that level's
1040
+ * own `direction`, followed depth-first by its nested groups and/or data
1041
+ * rows. A collapsed group (its `groupId` present in `expansion`) contributes
1042
+ * only its own header, nothing beneath it — but its `count` still reports
1043
+ * the group's full leaf-row count either way.
1044
+ *
1045
+ * Filter and sort are expected to have already run (see `resolveShownRows`):
1046
+ * this only reshapes their output, and never changes which rows appear or
1047
+ * their relative order within a group.
1048
+ *
1049
+ * `rowIndex` is renumbered across the whole flattened output, header rows
1050
+ * included — the same invariant `sortRows`/`filterRows` keep for
1051
+ * `ResolvedRow.rowIndex`, extended to `ResolvedGroupRow.rowIndex` since
1052
+ * `GridBody` addresses both kinds by the same flat position.
1053
+ *
1054
+ * Returns `rows` itself, untouched, when `groupBy` is empty or names only
1055
+ * columns absent from `columns` — a stored grouping tolerates a column
1056
+ * removed from the definition the same way a stored `ColumnSortState` does.
1057
+ */
1058
+ declare function groupRows<Row>(rows: readonly ResolvedRow<Row>[], groupBy: GroupByState, expansion: GroupExpansionState, columns: readonly ResolvedColumn<Row, unknown>[]): readonly DisplayRow<Row>[];
1059
+ /**
1060
+ * The expansion with `groupId` collapsed if it was expanded, or expanded if
1061
+ * it was collapsed.
1062
+ */
1063
+ declare function toggleGroupExpansion(expansion: GroupExpansionState, groupId: string): GroupExpansionState;
1064
+ /** `expansion` reduced to empty — every group expanded. Mirrors `clearAllFilters`. */
1065
+ declare function expandAllGroups(expansion: GroupExpansionState): GroupExpansionState;
1066
+ /**
1067
+ * Every group id present in `rows` — for collapsing every group currently
1068
+ * shown in one call. Operates on the already-grouped display, not the raw
1069
+ * grouping, so a group hidden beneath an already-collapsed ancestor (and so
1070
+ * absent from `rows`) keeps whatever expansion it already had rather than
1071
+ * being forced closed too; expanding that ancestor again reveals it exactly
1072
+ * as it was left.
1073
+ */
1074
+ declare function collapseAllGroups<Row>(rows: readonly DisplayRow<Row>[]): GroupExpansionState;
1075
+ /**
1076
+ * `groupBy` with `columnId` positioned in front of `beforeColumnId` — or at
1077
+ * the end when that is `null` — inserting a fresh entry if `columnId` isn't
1078
+ * already part of the stack, or lifting its existing entry out and back in
1079
+ * if it is. The one function both a header dropped on the group-by bar and
1080
+ * a chip dragged within it need: the former's `columnId` is usually new to
1081
+ * the stack, the latter's never is, and this doesn't need to be told which.
1082
+ *
1083
+ * An existing entry keeps its own object (and so its own `direction`)
1084
+ * rather than being rebuilt, so a level merely repositioned stays
1085
+ * reference-equal at its new index — the same reason `moveColumnBefore`
1086
+ * moves ids rather than rebuilding them.
1087
+ *
1088
+ * Returns `groupBy` itself, untouched, when the move changes nothing: a
1089
+ * drop on the entry's own id, or back into the gap it already occupies, or
1090
+ * naming a `beforeColumnId` absent from the stack. Inserting a column not
1091
+ * yet in the stack is never a no-op.
1092
+ */
1093
+ declare function moveGroupByBefore(groupBy: GroupByState, columnId: string, beforeColumnId: string | null): GroupByState;
1094
+ /**
1095
+ * Whether moving `columnId` in front of `beforeColumnId` would change
1096
+ * `groupBy` at all, so that a drop indicator promises exactly the move that
1097
+ * happens. Defined against `moveGroupByBefore` rather than restating its
1098
+ * conditions, the same relationship `movesColumn` keeps with
1099
+ * `moveColumnBefore`.
1100
+ */
1101
+ declare function movesGroupBy(groupBy: GroupByState, columnId: string, beforeColumnId: string | null): boolean;
1102
+
822
1103
  /**
823
1104
  * `rows`, filtered then sorted — the one function `DataGrid.tsx` (and any
824
1105
  * future framework binding) calls instead of composing `filterRows`/
@@ -852,4 +1133,61 @@ declare function resolveColumns<Row, Node>(columns: readonly ResolvedColumn<Row,
852
1133
  */
853
1134
  declare function resolveCell<Row, Node>(rowsById: ReadonlyMap<string, ResolvedRow<Row>>, columns: readonly ResolvedColumn<Row, Node>[], cell: SelectedCellRef | null): SelectedCell<Row, Node> | null;
854
1135
 
855
- export { type CellSelectEvent, type CellSelectionChangeEvent, type CellSelectionMode, type CellSelectionState, type CellTemplateContext, type ColumnAlignment, type ColumnConstraints, type ColumnDefinition, type ColumnOrderEvent, type ColumnOrderState, type ColumnResizeEvent, type ColumnResizeSession, type ColumnResolveOptions, type ColumnSelectEvent, type ColumnSelectionChangeEvent, type ColumnSizeDefaults, type ColumnSizingState, type ColumnSortEntry, type ColumnSortEvent, type ColumnSortState, type ColumnType, type ColumnWrapConfig, type ColumnsSelectEvent, DEFAULT_COLUMN_SIZES, type DropSide, type FieldPath, type FilterEntry, type FilterPredicate, type FilterState, type GridFocus, type GroupFilterEntry, HEADER_ROW, KEYBOARD_STEP, type KeyShortcutCapabilities, type NavigationModifiers, type PredicateFilterEntry, type ResolvedColumn, type ResolvedRow, type RowSelectEvent, type RowSelectionChangeEvent, type RowsSelectEvent, type SelectIntent, type SelectableConfig, type SelectedCell, type SelectedCellRef, type SelectedColumn, type SelectionDiff, type SelectionMode, type SelectionState, type SortDirection, type TextFilterEntry, type ValueFilterEntry, accessDotted, alignmentForType, applyColumnOrder, applyColumnResize, applySelectionIntent, beginColumnResize, buildKeyShortcuts, clampColumnWidth, clampFocus, clearAllFilters, clearSelection, compareValues, defineColumnsFromRows, diffSelection, filterQueryFor, filterRows, fitColumnsToWidth, getColumnId, intentOf, isSameCell, matchesQuery, moveColumnBefore, movesColumn, nextFocusForKey, resolveCell, resolveColumnConstraints, resolveColumnLabel, resolveColumnWidths, resolveColumns, resolveDropBefore, resolveKeyboardDropTarget, resolveRowId, resolveRows, resolveShownRows, revertColumnSize, selectAll, selectCell, selectOnly, selectRange, setColumnFilter, sizeColumnToContent, sortDirectionFor, sortPriorityFor, sortRows, toggleCellSelection, toggleColumnSort, toggleSelection, totalColumnWidth };
1136
+ interface PaginatedRows<Row> {
1137
+ readonly rows: readonly DisplayRow<Row>[];
1138
+ readonly pageCount: number;
1139
+ /**
1140
+ * `pagination.pageIndex` clamped into `[0, pageCount - 1]` (or `0` when
1141
+ * `pageCount` is `0`) — read this back rather than trusting the input
1142
+ * verbatim, the same way `sortRows`/`filterRows` tolerate a stale stored
1143
+ * state.
1144
+ */
1145
+ readonly pageIndex: number;
1146
+ }
1147
+ /**
1148
+ * `rows` sliced into pages of `pagination.pageSize` units — see `unitsOf`
1149
+ * for what a unit is. `pageIndex` is clamped into range, `pageSize <= 0` is
1150
+ * clamped to `1` (this codebase's general tolerance for stale/odd stored
1151
+ * state, matching `sortRows`/`filterRows`), and the returned page's
1152
+ * `rowIndex` is renumbered to be page-relative — 0-based from the top of the
1153
+ * page, header rows included, mirroring `groupRows`'s own renumbering
1154
+ * invariant. `datasetIndex` is left untouched: it is assigned once, ahead of
1155
+ * filter/sort/group/paginate, and reports each row's position in the whole
1156
+ * dataset regardless of which page is showing.
1157
+ */
1158
+ declare function paginateRows<Row>(rows: readonly DisplayRow<Row>[], pagination: PaginationState): PaginatedRows<Row>;
1159
+
1160
+ type PaginationWindowEntry = number | "ellipsis";
1161
+ /**
1162
+ * Which page numbers a numbered pager should show for `currentPage` of
1163
+ * `pageCount`, collapsing any gap wider than one page into a single
1164
+ * `"ellipsis"` entry — the boundary + sibling windowing MUI's
1165
+ * `usePagination` and antd's `Pagination` both use. Always includes the
1166
+ * first/last `boundaryCount` pages and `currentPage`'s `siblingCount`
1167
+ * neighbors on each side; a gap of exactly one page is filled in rather than
1168
+ * collapsed, since an ellipsis standing in for a single page saves no space.
1169
+ */
1170
+ declare function paginationWindow(currentPage: number, pageCount: number, options?: {
1171
+ boundaryCount?: number | undefined;
1172
+ siblingCount?: number | undefined;
1173
+ }): readonly PaginationWindowEntry[];
1174
+
1175
+ /**
1176
+ * `rows` reduced through every spec in `specs`, keyed by `spec.id ??
1177
+ * spec.columnId`. A custom `fn` (a plain function, not a `BuiltInAggregate`
1178
+ * name) is called once with the raw `rows` — no wrapping, no
1179
+ * pre-processing, so it sees exactly the same leaf set a built-in reducer
1180
+ * does.
1181
+ *
1182
+ * Two specs resolving to the same key: the later one wins, matching
1183
+ * `setColumnFilter`'s own silent-replace precedent for a key collision
1184
+ * rather than throwing.
1185
+ *
1186
+ * Returns a fresh empty `Map` for empty `rows` or empty `specs` — never a
1187
+ * shared singleton — matching this codebase's general avoidance of shared
1188
+ * mutable module state.
1189
+ */
1190
+ declare function computeAggregates<Row>(rows: readonly Row[], specs: AggregateState<Row>, columns: readonly ResolvedColumn<Row, unknown>[]): AggregateResults;
1191
+ declare function withGroupAggregates<Row>(displayRows: readonly DisplayRow<Row>[], flatRows: readonly ResolvedRow<Row>[], groupBy: GroupByState, specs: AggregateState<Row>, columns: readonly ResolvedColumn<Row, unknown>[], display?: GroupAggregateDisplay): readonly DisplayRow<Row>[];
1192
+
1193
+ export { type AggregateFn, type AggregateResults, type AggregateSpec, type AggregateState, type BuiltInAggregate, type CellSelectEvent, type CellSelectionChangeEvent, type CellSelectionMode, type CellSelectionState, type CellTemplateContext, type ColumnAlignment, type ColumnConstraints, type ColumnDefinition, type ColumnOrderEvent, type ColumnOrderState, type ColumnResizeEvent, type ColumnResizeSession, type ColumnResolveOptions, type ColumnSelectEvent, type ColumnSelectionChangeEvent, type ColumnSizeDefaults, type ColumnSizingState, type ColumnSortEntry, type ColumnSortEvent, type ColumnSortState, type ColumnType, type ColumnWrapConfig, type ColumnsSelectEvent, DEFAULT_COLUMN_SIZES, type DisplayRow, type DropSide, type FieldPath, type FilterEntry, type FilterPredicate, type FilterState, type FooterTemplateContext, type GridFocus, type GroupAggregateDisplay, type GroupByEntry, type GroupByEvent, type GroupByState, type GroupExpansionEvent, type GroupExpansionState, type GroupFilterEntry, HEADER_ROW, KEYBOARD_STEP, type KeyShortcutCapabilities, type NavigationModifiers, type PaginatedRows, type PaginationChangeEvent, type PaginationState, type PaginationWindowEntry, type PredicateFilterEntry, type ResolvedColumn, type ResolvedGroupRow, type ResolvedGroupSummaryRow, type ResolvedRow, type RowSelectEvent, type RowSelectionChangeEvent, type RowsSelectEvent, type SelectIntent, type SelectableConfig, type SelectedCell, type SelectedCellRef, type SelectedColumn, type SelectionDiff, type SelectionMode, type SelectionState, type SortDirection, type TextFilterEntry, type ValueFilterEntry, accessDotted, alignmentForType, applyColumnOrder, applyColumnResize, applySelectionIntent, beginColumnResize, buildKeyShortcuts, clampColumnWidth, clampFocus, clearAllFilters, clearSelection, collapseAllGroups, compareValues, computeAggregates, defineColumnsFromRows, diffSelection, expandAllGroups, filterQueryFor, filterRows, fitColumnsToWidth, getColumnId, groupRowId, groupRows, intentOf, isSameCell, matchesQuery, moveColumnBefore, moveGroupByBefore, movesColumn, movesGroupBy, nextFocusForKey, paginateRows, paginationWindow, resolveCell, resolveColumnConstraints, resolveColumnLabel, resolveColumnWidths, resolveColumns, resolveDropBefore, resolveKeyboardDropTarget, resolveRowId, resolveRows, resolveShownRows, revertColumnSize, selectAll, selectCell, selectOnly, selectRange, setColumnFilter, sizeColumnToContent, sortDirectionFor, sortPriorityFor, sortRows, toggleCellSelection, toggleColumnSort, toggleGroupExpansion, toggleSelection, totalColumnWidth, withGroupAggregates };