@jielga/tmdatagrid 0.1.0 → 0.2.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.
Files changed (39) hide show
  1. package/README.md +35 -2
  2. package/dist/index.d.ts +442 -337
  3. package/dist/index.js +811 -694
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/package.json +15 -7
  7. package/skills/columns/SKILL.md +8 -7
  8. package/skills/features/SKILL.md +104 -16
  9. package/skills/getting-started/SKILL.md +39 -16
  10. package/skills/options/SKILL.md +12 -7
  11. package/skills/server-side/SKILL.md +5 -2
  12. package/src/tmdatagrid/TMDataGridContext.ts +1 -1
  13. package/src/tmdatagrid/components/TMDataGrid.module.css +63 -0
  14. package/src/tmdatagrid/{TMDataGrid.tsx → components/TMDataGrid.tsx} +9 -4
  15. package/src/tmdatagrid/components/TMDataGridColumnsPanel.module.css +25 -0
  16. package/src/tmdatagrid/{TMDataGridColumnsPanel.tsx → components/TMDataGridColumnsPanel.tsx} +3 -3
  17. package/src/tmdatagrid/components/TMDataGridFilterPanel.module.css +20 -0
  18. package/src/tmdatagrid/{TMDataGridFilterPanel.tsx → components/TMDataGridFilterPanel.tsx} +4 -4
  19. package/src/tmdatagrid/components/TMDataGridFooter.module.css +10 -0
  20. package/src/tmdatagrid/components/TMDataGridFooter.tsx +143 -0
  21. package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +153 -0
  22. package/src/tmdatagrid/{TMDataGridHeaderCell.tsx → components/TMDataGridHeaderCell.tsx} +22 -13
  23. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +100 -0
  24. package/src/tmdatagrid/components/TMDataGridTable.module.css +103 -0
  25. package/src/tmdatagrid/{TMDataGridTable.tsx → components/TMDataGridTable.tsx} +79 -20
  26. package/src/tmdatagrid/components/TMDataGridToolbar.module.css +12 -0
  27. package/src/tmdatagrid/{TMDataGridToolbar.tsx → components/TMDataGridToolbar.tsx} +5 -5
  28. package/src/tmdatagrid/components/sticky.module.css +45 -0
  29. package/src/tmdatagrid/{capabilities.ts → core/capabilities.ts} +30 -2
  30. package/src/tmdatagrid/{columnOrdering.ts → core/columnOrdering.ts} +2 -2
  31. package/src/tmdatagrid/{columnUtils.ts → core/columnUtils.ts} +1 -1
  32. package/src/tmdatagrid/{persistence.ts → core/persistence.ts} +80 -2
  33. package/src/tmdatagrid/index.ts +15 -9
  34. package/src/tmdatagrid/useTMDataGrid.tsx +102 -55
  35. package/src/tmdatagrid/TMDataGrid.module.css +0 -410
  36. package/src/tmdatagrid/TMDataGridFooter.tsx +0 -74
  37. /package/src/tmdatagrid/{icons.ts → components/icons.ts} +0 -0
  38. /package/src/tmdatagrid/{filterOperators.ts → core/filterOperators.ts} +0 -0
  39. /package/src/tmdatagrid/{sizes.ts → core/sizes.ts} +0 -0
@@ -7,14 +7,15 @@ import {
7
7
  } from "@tanstack/react-table";
8
8
  import { useSelector } from "@tanstack/react-store";
9
9
  import { useVirtualizer } from "@tanstack/react-virtual";
10
- import { useCallback, useRef } from "react";
11
- import classes from "./TMDataGrid.module.css";
12
- import { type TMDataGridRowData, useTMDataGridContext } from "./TMDataGridContext";
10
+ import { useCallback, useEffect, useRef } from "react";
11
+ import classes from "./TMDataGridTable.module.css";
12
+ import sticky from "./sticky.module.css";
13
+ import { type TMDataGridRowData, useTMDataGridContext } from "../TMDataGridContext";
13
14
  import { TMDataGridFilterPanel } from "./TMDataGridFilterPanel";
14
15
  import { TMDataGridHeaderCell } from "./TMDataGridHeaderCell";
15
- import { getColumnAlign } from "./columnUtils";
16
+ import { getColumnAlign } from "../core/columnUtils";
16
17
  import { SearchIcon } from "./icons";
17
- import type { TMDataGridFeatures } from "./useTMDataGrid";
18
+ import type { TMDataGridFeatures } from "../useTMDataGrid";
18
19
 
19
20
  /** Where a column sits relative to the pinned regions, resolved once per render. */
20
21
  export type TMDataGridColumnLayout = {
@@ -46,9 +47,9 @@ function TMDataGridBodyCell({
46
47
  data-align={getColumnAlign(cell.column)}
47
48
  className={[
48
49
  classes.bodyCell,
49
- layout.isBoundary && layout.pinnedAt === "left" ? classes.stickyLeft : "",
50
+ layout.isBoundary && layout.pinnedAt === "left" ? sticky.stickyLeft : "",
50
51
  layout.isBoundary && layout.pinnedAt === "right"
51
- ? classes.stickyRight
52
+ ? sticky.stickyRight
52
53
  : "",
53
54
  ]
54
55
  .filter(Boolean)
@@ -69,18 +70,23 @@ function TMDataGridBodyCell({
69
70
  }
70
71
 
71
72
  export type TMDataGridTableProps<TData extends RowData> = {
72
- /** Called when a body row is clicked. */
73
+ /**
74
+ * Called when a body row is clicked. Runs in addition to row selection under
75
+ * `rowSelectionMode: "row"`, not instead of it.
76
+ */
73
77
  onRowClick?: (row: Row<TMDataGridFeatures, TData>) => void;
74
78
  };
75
79
 
76
80
  /**
77
81
  * The scrollable grid surface. Always virtualized: only the rows inside the
78
- * viewport (plus overscan) are mounted, regardless of page size.
82
+ * viewport (plus overscan) are mounted — which is what makes the default
83
+ * no-pagination mode viable at any row count. Pagination is opt-in via
84
+ * `enablePagination` (or implied by `manualPagination`).
79
85
  */
80
86
  export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
81
87
  onRowClick,
82
88
  }: TMDataGridTableProps<TData>) {
83
- const { table, rowHeight, controlSize } = useTMDataGridContext();
89
+ const { table, features, rowHeight, controlSize } = useTMDataGridContext();
84
90
 
85
91
  // The body depends on every state slice (sorting, filters, paging, sizing,
86
92
  // visibility, selection), so it subscribes to the whole table store.
@@ -90,8 +96,23 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
90
96
  table.options.meta ?? {};
91
97
 
92
98
  const scrollContainerRef = useRef<HTMLDivElement>(null);
93
- // Respects `manualPagination`: server-paged grids get the rows as delivered.
94
- const rows = table.getPaginatedRowModel().rows;
99
+ // Pagination off (the default): every filtered+sorted row, virtualized.
100
+ // Pagination on: the current page; under `manualPagination` TanStack returns
101
+ // the rows as delivered, so the same branch serves server paging.
102
+ const rows = features.pagination
103
+ ? table.getPaginatedRowModel().rows
104
+ : table.getPrePaginatedRowModel().rows;
105
+
106
+ // A persisted pageIndex can outlive the data that produced it; TanStack only
107
+ // auto-resets on live filter/sort/data changes, not on restored state. The
108
+ // guard makes the dependency-free effect idempotent.
109
+ useEffect(() => {
110
+ if (!features.pagination) return;
111
+ const pageCount = table.getPageCount();
112
+ if (pageCount > 0 && table.store.state.pagination.pageIndex >= pageCount) {
113
+ table.setPageIndex(pageCount - 1);
114
+ }
115
+ });
95
116
 
96
117
  const virtualizer = useVirtualizer({
97
118
  count: rows.length,
@@ -200,17 +221,38 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
200
221
 
201
222
  const isEmpty = rows.length === 0;
202
223
 
224
+ // "row" mode: the row itself is the selection control — clicking it toggles
225
+ // that row and leaves the rest of the selection alone.
226
+ const selectsOnRowClick =
227
+ features.rowSelection && features.rowSelectionMode === "row";
228
+ const rowIsInteractive = selectsOnRowClick || onRowClick !== undefined;
229
+
230
+ const handleRowActivate = (row: Row<TMDataGridFeatures, TMDataGridRowData>) => {
231
+ if (selectsOnRowClick && row.getCanSelect()) row.toggleSelected();
232
+ onRowClick?.(row as unknown as Row<TMDataGridFeatures, TData>);
233
+ };
234
+
203
235
  return (
204
236
  <div className={classes.tableWrapper}>
205
237
  <div ref={scrollContainerRef} className={classes.scrollContainer}>
206
238
  <div
207
239
  role="table"
208
240
  className={classes.grid}
241
+ // Virtualization means most rows are not in the DOM, so the counts
242
+ // have to be stated rather than inferred from what is rendered. Every
243
+ // row carries its aria-rowindex for the same reason.
244
+ aria-rowcount={rows.length + headerGroups.length}
245
+ aria-colcount={orderedColumns.length}
209
246
  style={{ gridTemplateColumns, minWidth: gridMinWidth }}
210
247
  >
211
248
  <div role="rowgroup" style={{ display: "contents" }}>
212
- {headerGroups.map((headerGroup) => (
213
- <div key={headerGroup.id} role="row" className={classes.headerRow}>
249
+ {headerGroups.map((headerGroup, groupIndex) => (
250
+ <div
251
+ key={headerGroup.id}
252
+ role="row"
253
+ aria-rowindex={groupIndex + 1}
254
+ className={classes.headerRow}
255
+ >
214
256
  {headerGroup.headers.map((header) => (
215
257
  <TMDataGridHeaderCell
216
258
  key={header.id}
@@ -234,19 +276,36 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
234
276
  <div
235
277
  key={virtualItem.key}
236
278
  role="row"
279
+ aria-rowindex={virtualItem.index + headerGroups.length + 1}
237
280
  data-testid={`dg-row-${row.id}`}
238
281
  data-selected={row.getIsSelected()}
282
+ // Selection is state; the highlight is a display choice, so
283
+ // the two are separate attributes.
284
+ data-highlighted={
285
+ features.highlightSelectedRows && row.getIsSelected()
286
+ }
287
+ data-selects-on-click={selectsOnRowClick}
288
+ aria-selected={
289
+ features.rowSelection ? row.getIsSelected() : undefined
290
+ }
239
291
  className={classes.bodyRow}
240
292
  style={{
241
293
  minHeight: rowHeight,
242
- cursor: onRowClick ? "pointer" : undefined,
294
+ cursor: rowIsInteractive ? "pointer" : undefined,
243
295
  }}
296
+ // Keyboard parity with the checkbox the row replaces.
297
+ tabIndex={selectsOnRowClick ? 0 : undefined}
244
298
  onClick={
245
- onRowClick
246
- ? () =>
247
- onRowClick(
248
- row as unknown as Row<TMDataGridFeatures, TData>,
249
- )
299
+ rowIsInteractive ? () => handleRowActivate(row) : undefined
300
+ }
301
+ onKeyDown={
302
+ selectsOnRowClick
303
+ ? (event) => {
304
+ if (event.key !== " " && event.key !== "Enter") return;
305
+ if (event.target !== event.currentTarget) return;
306
+ event.preventDefault();
307
+ handleRowActivate(row);
308
+ }
250
309
  : undefined
251
310
  }
252
311
  >
@@ -0,0 +1,12 @@
1
+ .toolbar {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: var(--mantine-spacing-xs);
5
+ padding: 6px var(--mantine-spacing-xs);
6
+ min-height: 42px;
7
+ flex-shrink: 0;
8
+ }
9
+
10
+ .toolbarSpacer {
11
+ flex: 1;
12
+ }
@@ -1,13 +1,13 @@
1
1
  import { ActionIcon, Popover, Text, Tooltip } from "@mantine/core";
2
2
  import { useSelector } from "@tanstack/react-store";
3
3
  import type { ReactNode } from "react";
4
- import classes from "./TMDataGrid.module.css";
4
+ import classes from "./TMDataGridToolbar.module.css";
5
5
  import { TMDataGridColumnsPanel } from "./TMDataGridColumnsPanel";
6
- import { useTMDataGridContext } from "./TMDataGridContext";
7
- import { getGridCapabilities } from "./capabilities";
8
- import { isFilterActive } from "./filterOperators";
6
+ import { useTMDataGridContext } from "../TMDataGridContext";
7
+ import { getGridCapabilities } from "../core/capabilities";
8
+ import { isFilterActive } from "../core/filterOperators";
9
9
  import { BurgerIcon, FilterIcon } from "./icons";
10
- import { openColumnFilter } from "./useTMDataGrid";
10
+ import { openColumnFilter } from "../useTMDataGrid";
11
11
 
12
12
  /** Row above the grid. Compose it from the pieces below, or anything else. */
13
13
  export function TMDataGridToolbar({ children }: { children?: ReactNode }) {
@@ -0,0 +1,45 @@
1
+ /* Boundary of a pinned column group. Shared, because the edge is cast by both
2
+ the header cell and every body cell in the same column — the two have to
3
+ draw an identical band or the seam shows at the header.
4
+
5
+ A box-shadow is drawn per cell, and its blur fades in at each cell's own top
6
+ and bottom edge — stacked down a column that reads as banding at every row
7
+ seam. Instead: a crisp 1px border for the hard edge, plus a gradient pseudo
8
+ element pinned to `top: 0; bottom: 0` so consecutive cells butt together into
9
+ one unbroken band. Mantine sets `color-scheme` on the root, so light-dark()
10
+ resolves without a second selector. */
11
+ .stickyLeft {
12
+ border-right: 1px solid var(--mantine-color-default-border);
13
+ }
14
+
15
+ .stickyRight {
16
+ border-left: 1px solid var(--mantine-color-default-border);
17
+ }
18
+
19
+ .stickyLeft::after,
20
+ .stickyRight::after {
21
+ content: "";
22
+ position: absolute;
23
+ top: 0;
24
+ bottom: 0;
25
+ width: 4px;
26
+ pointer-events: none;
27
+ }
28
+
29
+ .stickyLeft::after {
30
+ left: 100%;
31
+ background: linear-gradient(
32
+ to right,
33
+ light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.28)),
34
+ transparent
35
+ );
36
+ }
37
+
38
+ .stickyRight::after {
39
+ right: 100%;
40
+ background: linear-gradient(
41
+ to left,
42
+ light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.28)),
43
+ transparent
44
+ );
45
+ }
@@ -1,11 +1,11 @@
1
1
  import type { Column, RowData } from "@tanstack/react-table";
2
- import type { TMDataGridRowData } from "./TMDataGridContext";
2
+ import type { TMDataGridRowData } from "../TMDataGridContext";
3
3
  import { isColumnReorderable } from "./columnUtils";
4
4
  import type {
5
5
  TMDataGridFeatures,
6
6
  TMDataGridTable,
7
7
  UseTMDataGridOptions,
8
- } from "./useTMDataGrid";
8
+ } from "../useTMDataGrid";
9
9
 
10
10
  /**
11
11
  * Table-level feature switches, read straight off the options object.
@@ -19,6 +19,11 @@ import type {
19
19
  * TanStack still decides: these flags are combined with `getCanX()`, which is
20
20
  * what applies the per-column overrides.
21
21
  */
22
+ /**
23
+ * How rows are selected — see `rowSelectionMode` on {@link UseTMDataGridOptions}.
24
+ */
25
+ export type TMDataGridRowSelectionMode = "checkbox" | "row";
26
+
22
27
  export type TMDataGridFeatureFlags = {
23
28
  sorting: boolean;
24
29
  filtering: boolean;
@@ -27,6 +32,16 @@ export type TMDataGridFeatureFlags = {
27
32
  resizing: boolean;
28
33
  ordering: boolean;
29
34
  rowSelection: boolean;
35
+ /** Only meaningful while `rowSelection` is on. Defaults to `"checkbox"`. */
36
+ rowSelectionMode: TMDataGridRowSelectionMode;
37
+ /** Whether a selected row takes the highlight colour. Follows the mode. */
38
+ highlightSelectedRows: boolean;
39
+ /**
40
+ * The one default-off flag: pagination must be asked for, either with the
41
+ * grid's `enablePagination` or implicitly by declaring `manualPagination`.
42
+ * Off, the grid renders every filtered row and relies on virtualization.
43
+ */
44
+ pagination: boolean;
30
45
  };
31
46
 
32
47
  export function readFeatureFlags<TData extends RowData>(
@@ -39,6 +54,10 @@ export function readFeatureFlags<TData extends RowData>(
39
54
  | "enableColumnResizing"
40
55
  | "enableColumnOrdering"
41
56
  | "enableRowSelection"
57
+ | "rowSelectionMode"
58
+ | "highlightSelectedRows"
59
+ | "enablePagination"
60
+ | "manualPagination"
42
61
  >,
43
62
  ): TMDataGridFeatureFlags {
44
63
  return {
@@ -49,6 +68,13 @@ export function readFeatureFlags<TData extends RowData>(
49
68
  resizing: options.enableColumnResizing !== false,
50
69
  ordering: options.enableColumnOrdering !== false,
51
70
  rowSelection: options.enableRowSelection !== false,
71
+ rowSelectionMode: options.rowSelectionMode ?? "checkbox",
72
+ // In "row" mode the highlight *is* the feedback for a click, so it is on.
73
+ // With checkboxes the box already says it, so it is off unless asked for.
74
+ highlightSelectedRows:
75
+ options.highlightSelectedRows ?? options.rowSelectionMode === "row",
76
+ pagination:
77
+ options.enablePagination === true || options.manualPagination === true,
52
78
  };
53
79
  }
54
80
 
@@ -96,6 +122,7 @@ export type TMDataGridCapabilities = {
96
122
  canPinAny: boolean;
97
123
  canReorderAny: boolean;
98
124
  canSelectRows: boolean;
125
+ canPaginate: boolean;
99
126
  };
100
127
 
101
128
  export function getGridCapabilities(
@@ -113,5 +140,6 @@ export function getGridCapabilities(
113
140
  canPinAny: any((c) => c.canPin),
114
141
  canReorderAny: any((c) => c.canReorder),
115
142
  canSelectRows: features.rowSelection,
143
+ canPaginate: features.pagination,
116
144
  };
117
145
  }
@@ -1,7 +1,7 @@
1
1
  import type { Column, ColumnPinningState } from "@tanstack/react-table";
2
- import type { TMDataGridRowData } from "./TMDataGridContext";
2
+ import type { TMDataGridRowData } from "../TMDataGridContext";
3
3
  import { isColumnReorderable } from "./columnUtils";
4
- import type { TMDataGridFeatures, TMDataGridTable } from "./useTMDataGrid";
4
+ import type { TMDataGridFeatures, TMDataGridTable } from "../useTMDataGrid";
5
5
 
6
6
  type GridColumn = Column<TMDataGridFeatures, TMDataGridRowData, unknown>;
7
7
  type GridTable = TMDataGridTable<TMDataGridRowData>;
@@ -1,5 +1,5 @@
1
1
  import type { TMDataGridColumnType } from "./filterOperators";
2
- import type { TMDataGridColumnMeta } from "./useTMDataGrid";
2
+ import type { TMDataGridColumnMeta } from "../useTMDataGrid";
3
3
 
4
4
  /**
5
5
  * Structural shape of the column bits the chrome reads. Kept minimal so these
@@ -1,5 +1,5 @@
1
1
  import type { TableState } from "@tanstack/react-table";
2
- import type { TMDataGridFeatures } from "./useTMDataGrid";
2
+ import type { TMDataGridFeatures } from "../useTMDataGrid";
3
3
 
4
4
  type GridState = TableState<TMDataGridFeatures>;
5
5
 
@@ -100,6 +100,82 @@ function resolveStorage(
100
100
  }
101
101
  }
102
102
 
103
+ /**
104
+ * Shape guards for restored state.
105
+ *
106
+ * A stored payload outlives the code that wrote it: a slice can change shape
107
+ * between releases, and nothing stops anyone from editing storage by hand. The
108
+ * value goes straight into `initialState`, where a wrong shape surfaces as a
109
+ * crash inside TanStack rather than as a bad read here. A slice that fails its
110
+ * guard is dropped; the rest still restore.
111
+ */
112
+ function prop(value: unknown, key: string): unknown {
113
+ return typeof value === "object" && value !== null
114
+ ? (value as Record<string, unknown>)[key]
115
+ : undefined;
116
+ }
117
+
118
+ const isString = (value: unknown): value is string => typeof value === "string";
119
+
120
+ const isFiniteNumber = (value: unknown): value is number =>
121
+ typeof value === "number" && Number.isFinite(value);
122
+
123
+ function isArrayOf(
124
+ value: unknown,
125
+ isItem: (item: unknown) => boolean,
126
+ ): boolean {
127
+ return Array.isArray(value) && value.every(isItem);
128
+ }
129
+
130
+ function isRecordOf(
131
+ value: unknown,
132
+ isItem: (item: unknown) => boolean,
133
+ ): boolean {
134
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
135
+ return false;
136
+ }
137
+ return Object.values(value).every(isItem);
138
+ }
139
+
140
+ const hasStringId = (entry: unknown): boolean => isString(prop(entry, "id"));
141
+
142
+ const SLICE_GUARDS: Record<
143
+ TMDataGridDataSlice | TMDataGridSettingsSlice,
144
+ (value: unknown) => boolean
145
+ > = {
146
+ columnFilters: (value) => isArrayOf(value, hasStringId),
147
+ // TanStack leaves the global filter value untyped — the grid's own default
148
+ // filters on a string, but a consumer may store anything here.
149
+ globalFilter: () => true,
150
+ sorting: (value) =>
151
+ isArrayOf(
152
+ value,
153
+ (entry) => hasStringId(entry) && typeof prop(entry, "desc") === "boolean",
154
+ ),
155
+ pagination: (value) => {
156
+ const pageIndex = prop(value, "pageIndex");
157
+ const pageSize = prop(value, "pageSize");
158
+ return (
159
+ isFiniteNumber(pageIndex) &&
160
+ pageIndex >= 0 &&
161
+ isFiniteNumber(pageSize) &&
162
+ pageSize > 0
163
+ );
164
+ },
165
+ columnVisibility: (value) =>
166
+ isRecordOf(value, (entry) => typeof entry === "boolean"),
167
+ columnSizing: (value) => isRecordOf(value, isFiniteNumber),
168
+ columnOrder: (value) => isArrayOf(value, isString),
169
+ columnPinning: (value) =>
170
+ isArrayOf(prop(value, "left"), isString) &&
171
+ isArrayOf(prop(value, "right"), isString),
172
+ };
173
+
174
+ function isValidSlice(slice: keyof GridState, value: unknown): boolean {
175
+ const guard = SLICE_GUARDS[slice as keyof typeof SLICE_GUARDS];
176
+ return guard === undefined || guard(value);
177
+ }
178
+
103
179
  function readSlices(
104
180
  storage: Storage | null,
105
181
  resolved: ResolvedKey | null,
@@ -117,7 +193,9 @@ function readSlices(
117
193
  // Only copy the selected slices. A payload written before the selection was
118
194
  // narrowed cannot reintroduce slices the caller has since opted out of.
119
195
  for (const slice of resolved.slices) {
120
- if (slice in record) restored[slice] = record[slice];
196
+ if (!(slice in record)) continue;
197
+ if (!isValidSlice(slice, record[slice])) continue;
198
+ restored[slice] = record[slice];
121
199
  }
122
200
  return restored as Partial<GridState>;
123
201
  } catch {
@@ -1,13 +1,13 @@
1
- export { TMDataGrid, type TMDataGridProps } from "./TMDataGrid";
1
+ export { TMDataGrid, type TMDataGridProps } from "./components/TMDataGrid";
2
2
  export {
3
3
  useTMDataGridContext,
4
4
  type TMDataGridContextValue,
5
5
  type TMDataGridRowData,
6
6
  } from "./TMDataGridContext";
7
+ export { SELECT_COLUMN_ID } from "./components/TMDataGridSelectColumn";
7
8
  export {
8
9
  createTMDataGridColumnHelper,
9
10
  openColumnFilter,
10
- SELECT_COLUMN_ID,
11
11
  tmDataGridFeatures,
12
12
  type TMDataGridApi,
13
13
  type TMDataGridColumnMeta,
@@ -26,12 +26,12 @@ export {
26
26
  type TMDataGridFilterValue,
27
27
  FILTER_OPERATOR_LABELS,
28
28
  isFilterActive,
29
- } from "./filterOperators";
29
+ } from "./core/filterOperators";
30
30
  export {
31
31
  getColumnLabel,
32
32
  getColumnType,
33
33
  isColumnReorderable,
34
- } from "./columnUtils";
34
+ } from "./core/columnUtils";
35
35
  export {
36
36
  getColumnRegion,
37
37
  getStepTargetColumn,
@@ -41,7 +41,7 @@ export {
41
41
  type MoveColumnArgs,
42
42
  type TMDataGridColumnRegion,
43
43
  type TMDataGridDropSide,
44
- } from "./columnOrdering";
44
+ } from "./core/columnOrdering";
45
45
  export {
46
46
  getColumnCapabilities,
47
47
  getGridCapabilities,
@@ -49,13 +49,14 @@ export {
49
49
  type TMDataGridCapabilities,
50
50
  type TMDataGridColumnCapabilities,
51
51
  type TMDataGridFeatureFlags,
52
- } from "./capabilities";
52
+ type TMDataGridRowSelectionMode,
53
+ } from "./core/capabilities";
53
54
  export {
54
55
  DEFAULT_TMDATAGRID_SIZE,
55
56
  SIZE_CONTROL_SIZE,
56
57
  SIZE_ROW_HEIGHT,
57
58
  type TMDataGridSize,
58
- } from "./sizes";
59
+ } from "./core/sizes";
59
60
  export {
60
61
  DATA_STATE_SLICES,
61
62
  SETTINGS_STATE_SLICES,
@@ -64,5 +65,10 @@ export {
64
65
  type TMDataGridPersistKey,
65
66
  type TMDataGridSettingsSlice,
66
67
  type TMDataGridStorageMode,
67
- } from "./persistence";
68
- export type { TMDataGridColumnLayout } from "./TMDataGridTable";
68
+ } from "./core/persistence";
69
+ export type { TMDataGridColumnLayout } from "./components/TMDataGridTable";
70
+ export {
71
+ getTMDataGridPaginationApi,
72
+ type TMDataGridFooterProps,
73
+ type TMDataGridPaginationApi,
74
+ } from "./components/TMDataGridFooter";