@jielga/tmdatagrid 1.0.0 → 1.0.2

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 (78) hide show
  1. package/README.md +8 -8
  2. package/dist/index.d.ts +225 -225
  3. package/dist/index.js +58 -50
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/package.json +3 -2
  7. package/skills/appearance/SKILL.md +322 -0
  8. package/skills/cell-selection/SKILL.md +240 -0
  9. package/skills/columns/SKILL.md +261 -86
  10. package/skills/data/SKILL.md +289 -0
  11. package/skills/editing/SKILL.md +492 -0
  12. package/skills/editing/references/editing-api.md +124 -0
  13. package/skills/editing/references/editors-and-validation.md +198 -0
  14. package/skills/filtering/SKILL.md +344 -0
  15. package/skills/getting-started/SKILL.md +48 -27
  16. package/skills/grouping/SKILL.md +264 -0
  17. package/skills/options/SKILL.md +31 -20
  18. package/skills/rows/SKILL.md +369 -0
  19. package/skills/rows/references/rows-api.md +117 -0
  20. package/skills/server-side/SKILL.md +7 -7
  21. package/skills/testing/SKILL.md +12 -12
  22. package/src/tmdatagrid/TMDataGridContext.ts +2 -2
  23. package/src/tmdatagrid/components/TMDataGrid.module.css +2 -2
  24. package/src/tmdatagrid/components/TMDataGrid.tsx +5 -5
  25. package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +4 -4
  26. package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +2 -2
  27. package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +6 -6
  28. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +2 -2
  29. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +4 -4
  30. package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +6 -6
  31. package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +6 -6
  32. package/src/tmdatagrid/components/TMDataGridFilterPills.module.css +2 -2
  33. package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +1 -1
  34. package/src/tmdatagrid/components/TMDataGridFooter.module.css +1 -1
  35. package/src/tmdatagrid/components/TMDataGridFooter.tsx +12 -6
  36. package/src/tmdatagrid/components/TMDataGridGroupColumn.module.css +1 -1
  37. package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +5 -5
  38. package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +8 -8
  39. package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +12 -12
  40. package/src/tmdatagrid/components/TMDataGridRowNumberColumn.tsx +4 -4
  41. package/src/tmdatagrid/components/TMDataGridSearch.tsx +5 -5
  42. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +8 -8
  43. package/src/tmdatagrid/components/TMDataGridTable.module.css +18 -18
  44. package/src/tmdatagrid/components/TMDataGridTable.tsx +116 -116
  45. package/src/tmdatagrid/components/TMDataGridToolbar.tsx +5 -5
  46. package/src/tmdatagrid/components/editors/TMDataGridBooleanEditor.tsx +1 -1
  47. package/src/tmdatagrid/components/editors/TMDataGridDateEditor.tsx +2 -2
  48. package/src/tmdatagrid/components/editors/TMDataGridMultiSelectEditor.tsx +1 -1
  49. package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +1 -1
  50. package/src/tmdatagrid/components/editors/TMDataGridSelectEditor.tsx +2 -2
  51. package/src/tmdatagrid/components/editors/editorShared.ts +3 -3
  52. package/src/tmdatagrid/components/filters/DgDateRangeFilter.tsx +1 -1
  53. package/src/tmdatagrid/components/filters/DgRangeSliderFilter.tsx +1 -1
  54. package/src/tmdatagrid/components/filters/DgTriStateFilter.tsx +1 -1
  55. package/src/tmdatagrid/components/filters/TMDataGridFilterValueInput.tsx +2 -2
  56. package/src/tmdatagrid/components/sticky.module.css +8 -8
  57. package/src/tmdatagrid/core/autosize.ts +4 -4
  58. package/src/tmdatagrid/core/capabilities.ts +17 -17
  59. package/src/tmdatagrid/core/cellExport.ts +13 -13
  60. package/src/tmdatagrid/core/cellNavigation.ts +6 -6
  61. package/src/tmdatagrid/core/cellRange.ts +4 -4
  62. package/src/tmdatagrid/core/columnOptions.ts +2 -2
  63. package/src/tmdatagrid/core/columnOrdering.ts +2 -2
  64. package/src/tmdatagrid/core/columnUtils.ts +3 -3
  65. package/src/tmdatagrid/core/editEngine.ts +49 -49
  66. package/src/tmdatagrid/core/expanding.ts +5 -5
  67. package/src/tmdatagrid/core/filterControls.ts +5 -5
  68. package/src/tmdatagrid/core/filterOperators.ts +14 -14
  69. package/src/tmdatagrid/core/labels.ts +8 -8
  70. package/src/tmdatagrid/core/matchHighlight.ts +4 -4
  71. package/src/tmdatagrid/core/persistence.ts +8 -8
  72. package/src/tmdatagrid/core/quickSearch.ts +8 -8
  73. package/src/tmdatagrid/core/rowPinning.ts +3 -3
  74. package/src/tmdatagrid/core/rowSelection.ts +12 -12
  75. package/src/tmdatagrid/core/sizes.ts +1 -1
  76. package/src/tmdatagrid/core/summary.ts +3 -3
  77. package/src/tmdatagrid/useTMDataGrid.tsx +79 -79
  78. package/skills/features/SKILL.md +0 -352
@@ -1,352 +0,0 @@
1
- ---
2
- name: features
3
- description: >
4
- Enable or disable TMDataGrid interface elements through standard TanStack
5
- table and column options, and reuse the same checks in your own components.
6
- Covers the enableSorting/enableColumnFilters/enableHiding/enableColumnPinning/
7
- enableColumnResizing/enableColumnOrdering/enableRowSelection matrix, the
8
- selection modes behind rowSelectionMode, the highlightSelectedRows flag and
9
- the --dg-row-selected-bg colour, the default-off enablePagination switch and
10
- its three modes (none, client, manual), getGridCapabilities and
11
- getColumnCapabilities, why the features argument is required for reactivity
12
- under the React Compiler, column ordering with moveColumn and
13
- moveColumnByStep, cell selection with arrow-key navigation, drag-selected
14
- ranges, Ctrl+C copy and Excel-compatible CSV export, and always-on
15
- virtualization. Load when building a read-only grid, hiding grid chrome,
16
- enabling pagination, reordering columns from code, adding cell navigation or
17
- copy/export, or writing a custom toolbar button.
18
- metadata:
19
- type: core
20
- library: '@jielga/tmdatagrid'
21
- library_version: '1.0.0'
22
- sources:
23
- - 'Jielga/TMDataGrid:src/docs/features.md'
24
- - 'Jielga/TMDataGrid:src/tmdatagrid/core/capabilities.ts'
25
- - 'Jielga/TMDataGrid:src/tmdatagrid/core/columnOrdering.ts'
26
- ---
27
-
28
- # TMDataGrid — Features and capabilities
29
-
30
- Almost every control is bound to the TanStack capability check for that feature,
31
- so setting the standard table or column option removes the corresponding
32
- interface. Empty menus and inactive buttons are never rendered.
33
-
34
- Column ordering and pagination are the two exceptions. TanStack ships state and
35
- APIs for both but no `enable` option, so the grid defines `enableColumnOrdering`
36
- (with `meta.enableOrdering`) and `enablePagination` itself. Ordering behaves
37
- like the options around it; pagination is the one switch that defaults to off.
38
-
39
- ## Option reference
40
-
41
- | Option | Level | Interface removed |
42
- | --- | --- | --- |
43
- | `enableSorting: false` | Table, column | Sort indicator, sort menu items, click-to-sort |
44
- | `enableColumnFilters: false` | Table | Filter menu item, `FilterButton`, filter panel |
45
- | `enableColumnFilter: false` | Column | That column's filter menu item and panel entry |
46
- | `enableHiding: false` | Table, column | Hide column, Manage columns, `ColumnsButton` |
47
- | `enableColumnPinning: false` | Table | Pin and unpin menu items |
48
- | `enablePinning: false` | Column | That column's pin menu items |
49
- | `enableColumnResizing: false` | Table | Resize dragging. The divider remains as a separator |
50
- | `enableResizing: false` | Column | That column's resize dragging |
51
- | `enableColumnOrdering: false` | Table | Header dragging and the move menu items |
52
- | `meta.enableOrdering: false` | Column | That column's header dragging and move menu items |
53
- | `enableRowSelection: false` | Table | The checkbox column |
54
- | `rowSelectionMode: "row"` | Table | The checkbox column — the row itself selects instead. See Row selection |
55
- | `highlightSelectedRows: false` | Table | The highlight background on selected rows. Follows the selection mode by default |
56
- | `enablePagination: true` | Table | Opt-in: adds paging and the `Footer` pager. Off by default |
57
-
58
- A column whose menu has no remaining items renders no menu button. Dividers are
59
- never left at the end of a menu.
60
-
61
- ```tsx
62
- // Read-only grid: no selection, hiding, pinning or filtering.
63
- const grid = useTMDataGrid({
64
- data,
65
- columns,
66
- enableRowSelection: false,
67
- enableHiding: false,
68
- enableColumnPinning: false,
69
- enableColumnFilters: false,
70
- });
71
- ```
72
-
73
- ## Row selection
74
-
75
- On by default, in two modes. Both write to the same `rowSelection` state, so
76
- everything downstream — the toolbar count, `getSelectedRowModel()`, persistence
77
- — is unaffected by the choice.
78
-
79
- **Checkbox** — the default. A checkbox column is added as the first column, with
80
- a select-all box in its header. Clicking a row elsewhere does not select it, and
81
- a selected row is not highlighted: the checkbox already says so.
82
-
83
- ```tsx
84
- const grid = useTMDataGrid({ data, columns });
85
- ```
86
-
87
- **Row** — no checkbox column. Clicking a row toggles it, and the row takes the
88
- highlight background — the only feedback a click gives. Other rows keep their
89
- state, so a click never clears the rest of the selection. Rows are focusable in
90
- this mode and Space or Enter toggles the focused row.
91
-
92
- ```tsx
93
- const grid = useTMDataGrid({ data, columns, rowSelectionMode: "row" });
94
- ```
95
-
96
- `enableRowSelection: false` removes both, and `rowSelectionMode` is then
97
- ignored. `TMDataGrid.Table`'s `onRowClick` still fires in either mode — under
98
- `"row"` it runs in addition to the selection, not instead of it.
99
-
100
- `highlightSelectedRows` follows the mode — on for `"row"`, off for
101
- `"checkbox"` — and can be set to override either way. The colour is the
102
- `--dg-row-selected-bg` CSS variable (default `--mantine-primary-color-light`);
103
- change it on the grid element without touching the flag:
104
-
105
- ```tsx
106
- // Checkbox column, and selected rows are highlighted too.
107
- const grid = useTMDataGrid({ data, columns, highlightSelectedRows: true });
108
-
109
- <TMDataGrid
110
- {...grid}
111
- style={{ "--dg-row-selected-bg": "var(--mantine-color-blue-0)" }}
112
- />
113
- ```
114
-
115
- Rows carry `data-selected` whenever selected and `data-highlighted` only when
116
- also highlighted, so custom styling can key off either.
117
-
118
- ## Pagination
119
-
120
- Off by default: the grid renders every filtered and sorted row and relies on
121
- virtualization. Three modes:
122
-
123
- ```tsx
124
- // No pagination (default) — TMDataGrid.Footer renders nothing.
125
- const grid = useTMDataGrid({ data, columns });
126
-
127
- // Client pagination — pages locally, Footer renders its pager.
128
- const grid = useTMDataGrid({ data, columns, enablePagination: true });
129
-
130
- // Manual pagination — manualPagination implies enablePagination.
131
- const grid = useTMDataGrid({
132
- data: page.rows,
133
- columns,
134
- manualPagination: true,
135
- rowCount: page.total,
136
- state: { pagination },
137
- onPaginationChange: setPagination,
138
- });
139
- ```
140
-
141
- The built-in pager can be replaced with the Footer's `pagination` render prop
142
- (see the `getting-started` skill) or built from scratch on the table API.
143
-
144
- ## Capability helpers
145
-
146
- Use these to apply the same checks in your own components.
147
-
148
- ```tsx
149
- import { getGridCapabilities, useTMDataGridContext } from "@jielga/tmdatagrid";
150
-
151
- function ExportButton() {
152
- const { table, features } = useTMDataGridContext();
153
- const { canFilterAny } = getGridCapabilities(table, features);
154
-
155
- if (!canFilterAny) return null;
156
- return <Button onClick={exportRows}>Export</Button>;
157
- }
158
- ```
159
-
160
- `getGridCapabilities(table, features)`:
161
-
162
- | Field | Description |
163
- | --- | --- |
164
- | `canSortAny` | At least one leaf column can be sorted. |
165
- | `canFilterAny` | At least one leaf column can be filtered. |
166
- | `canHideAny` | At least one leaf column can be hidden. |
167
- | `canPinAny` | At least one leaf column can be pinned. |
168
- | `canReorderAny` | At least one leaf column can be moved. |
169
- | `canSelectRows` | `enableRowSelection` is not `false`. The mode is in `features.rowSelectionMode`. |
170
- | `canPaginate` | `enablePagination` or `manualPagination` is `true`. |
171
-
172
- `getColumnCapabilities(column, features)` returns the same information for a
173
- single column as `canSort`, `canFilter`, `canHide`, `canPin`, `canResize` and
174
- `canReorder`.
175
-
176
- `readFeatureFlags(options)` derives the flags from a table options object.
177
-
178
- ## Why capabilities take a features argument
179
-
180
- `features` is returned by `useTMDataGrid` and re-derived from the options object
181
- on every render. It is required *in addition to* TanStack's `getCanX()` methods
182
- because it is what makes the result reactive.
183
-
184
- `column.getCanSort()` is a method call on a column object whose identity is
185
- preserved across an options change. Under the React Compiler the call is
186
- memoized, so a grid whose `enableSorting` flips to `false` would keep rendering
187
- sort indicators. Passing `features` supplies a value that actually changes, while
188
- `getCanX()` still determines the outcome and applies per-column overrides.
189
-
190
- The same rule applies to any value derived from the table elsewhere in an
191
- application: read state through `useSelector(table.store, …)` and options through
192
- `features`, rather than calling methods on a long-lived object.
193
-
194
- ## Column pinning
195
-
196
- Pin to left and Pin to right appear in each column menu. The current position is
197
- marked, and selecting it again unpins. Pinned columns are sticky within the
198
- scroll container, and the boundary is marked with a divider and a short gradient.
199
-
200
- Headers, cells and grid tracks are ordered left, centre, right from the same
201
- source, so pinning does not change a column's position relative to its group.
202
-
203
- Pinning is stored in `columnPinning`, one of the slices covered by `settingsKey`
204
- in the `options` skill.
205
-
206
- ## Column ordering
207
-
208
- Enabled by default. Drag a column header sideways to move it; "Move left" and
209
- "Move right" in the column menu do the same one step at a time, and are the path
210
- that works without a pointer.
211
-
212
- A column only moves within its own pinned region, so a header in another region
213
- never accepts the drop. That follows TanStack's pipeline: pinning splits the
214
- grid into left, centre and right, then `columnOrder` sequences the centre while
215
- `columnPinning.left` / `.right` sequence the pinned lanes. Unpin first to move a
216
- column out of a pinned region.
217
-
218
- Ordering writes `columnOrder` as the complete leaf order — hidden and pinned
219
- columns included — so a column keeps its position when it is later shown or
220
- unpinned; moving a pinned column also rewrites its `columnPinning` array. Both
221
- slices are covered by `settingsKey`.
222
-
223
- A neighbour that cannot be moved acts as a wall rather than being stepped over,
224
- which is what keeps the checkbox column at the start of the left region.
225
- Columns inside a header group are never movable: `columnOrder` sequences leaf
226
- columns, so moving one would leave the group header spanning columns that no
227
- longer belong to it.
228
-
229
- ```tsx
230
- import {
231
- getStepTargetColumn,
232
- moveColumn,
233
- moveColumnByStep,
234
- } from "@jielga/tmdatagrid";
235
-
236
- moveColumn({ table, columnId: "salary", targetId: "age", side: "before" });
237
- moveColumnByStep({ table, columnId: "salary", direction: 1 });
238
-
239
- // null at the edge of a region — what the move menu items disable themselves on.
240
- const next = getStepTargetColumn({ table, columnId: "salary", direction: 1 });
241
- ```
242
-
243
- Both movers are no-ops for a move that is not allowed, including one across
244
- regions.
245
-
246
- ## Cell selection
247
-
248
- Off by default. `cellSelection: "single"` gives one focused cell moved with the
249
- arrow keys; `"range"` adds a selectable rectangle, Ctrl+C and CSV export.
250
-
251
- ```tsx
252
- const grid = useTMDataGrid({ data, columns, cellSelection: "range" });
253
- ```
254
-
255
- On, the body's tab stop moves from the row to a cell (the whole grid is one Tab
256
- stop), the container reports `role="grid"` with `gridcell` children, and cells
257
- carry `data-focused` / `data-selected` / `data-edge-*`.
258
-
259
- | Key | Does |
260
- | --- | --- |
261
- | Arrows | one cell, clamped at the edges |
262
- | Shift+arrows | extends the rectangle from its anchor |
263
- | PageUp / PageDown | one viewport of rows |
264
- | Home / End, Ctrl+Home / Ctrl+End | ends of the row, corners of the grid |
265
- | Enter or F2 | steps into the cell's control; Escape steps back out |
266
- | Space | selects the row |
267
- | Ctrl+C | copies the block as tab-separated text |
268
-
269
- The body is one tab stop: controls inside body cells take `tabindex="-1"` while
270
- cell selection is on, so Tab leaves the grid instead of walking one control per
271
- mounted row. Enter/F2 steps in, Escape steps out, Space ticks the row from any
272
- cell. Custom cell controls should do the same —
273
- `tabIndex={useCellControlTabIndex()}`. Header controls are untouched.
274
-
275
- The generated lanes (checkbox, tree, details) are selectable and navigable —
276
- they take the tint and the outline — but never exported; a block covering only
277
- those disables Copy and Export.
278
-
279
- Drag across cells to select a rectangle; Shift+click extends one. The state is
280
- `ui.state.focusedCell` and `ui.state.cellRange`, both held as `{ rowId,
281
- columnId }` pairs so sorting and filtering carry the selection with the cells.
282
- Move them with `ui.actions.setFocusedCell` / `setCellRange`, follow them with
283
- `onFocusedCellChange`. One rectangle at a time.
284
-
285
- Right-clicking inside the selection offers Copy, "Export as CSV for Excel" and
286
- an Include headers toggle; a consumer's `rowContextMenu` items follow a divider.
287
- The CSV is Nordic-Excel shaped — `sep=;` line, UTF-8 BOM, CRLF, semicolons,
288
- decimal comma — and `cellExport` on `TMDataGrid.Table` changes any of that.
289
- Generated lanes (checkbox, tree, details) are never exported, and what is
290
- written is the cell's value rather than what it renders.
291
-
292
- ## Virtualization
293
-
294
- Always enabled. Only rows within the viewport, plus a small overscan, are
295
- mounted, so page size does not affect how much is rendered.
296
-
297
- `overscan` on `useTMDataGrid` (default `6`) sets how many rows are kept mounted
298
- on each side of the viewport — the one configurable part.
299
-
300
- Row height comes from `meta.rowHeight`, or from the `size` prop when unset. Rows
301
- are fixed height; an accurate value keeps scrolling precise.
302
-
303
- ## Common mistakes
304
-
305
- ### Calling getCanX() in a custom component
306
-
307
- ```tsx
308
- // Wrong — memoized under the React Compiler, so the button
309
- // never reappears when enableColumnFilters flips back to true.
310
- const { table } = useTMDataGridContext();
311
- if (!table.getAllLeafColumns().some((c) => c.getCanFilter())) return null;
312
-
313
- // Right — features is a value that changes.
314
- const { table, features } = useTMDataGridContext();
315
- const { canFilterAny } = getGridCapabilities(table, features);
316
- if (!canFilterAny) return null;
317
- ```
318
-
319
- ### Setting a custom row height in CSS only
320
-
321
- The virtualizer needs the height as a number to position rows. Overriding row
322
- height in a stylesheet leaves the virtualizer measuring the old value, so rows
323
- overlap or leave gaps as you scroll. Set `meta.rowHeight` instead.
324
-
325
- ### Reordering a pinned column through columnOrder
326
-
327
- ```tsx
328
- // Wrong — the left and right regions are sequenced by columnPinning,
329
- // so this moves nothing on screen.
330
- table.setColumnOrder(["__select__", "department", "id", …]);
331
-
332
- // Right — moveColumn writes whichever slice the column's region uses.
333
- moveColumn({ table, columnId: "department", targetId: "id", side: "before" });
334
- ```
335
-
336
- ### Rendering the Footer without enabling pagination
337
-
338
- ```tsx
339
- // Wrong — pagination defaults to off, so the Footer renders nothing.
340
- const grid = useTMDataGrid({ data, columns });
341
- <TMDataGrid.Footer />
342
-
343
- // Right — opt in (manualPagination: true also counts).
344
- const grid = useTMDataGrid({ data, columns, enablePagination: true });
345
- <TMDataGrid.Footer />
346
- ```
347
-
348
- ### Expecting a table-level flag to override a column
349
-
350
- Table and column options compose — the table flag gates the feature, and the
351
- column flag narrows it further. `enableSorting: true` on a column does not
352
- re-enable sorting for a table that set `enableSorting: false`.