@jielga/tmdatagrid 2.0.0-beta.9 → 2.0.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 (154) hide show
  1. package/README.md +5 -212
  2. package/dist/index.d.ts +1281 -768
  3. package/dist/index.js +4607 -3250
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/docs/adding-rows.md +132 -0
  7. package/docs/anatomy.md +119 -0
  8. package/docs/card-view.md +108 -0
  9. package/docs/cell-selection.md +194 -0
  10. package/docs/column-layout.md +182 -0
  11. package/docs/column-menu.md +66 -0
  12. package/docs/columns.md +268 -0
  13. package/docs/components.md +311 -0
  14. package/docs/draft-store.md +242 -0
  15. package/docs/editing.md +303 -0
  16. package/docs/editors.md +250 -0
  17. package/docs/export.md +319 -0
  18. package/docs/filtering.md +362 -0
  19. package/docs/getting-started.md +123 -0
  20. package/docs/grouping.md +165 -0
  21. package/docs/loading-and-empty.md +92 -0
  22. package/docs/localization.md +79 -0
  23. package/docs/menu.md +143 -0
  24. package/docs/migrating-to-2.md +163 -0
  25. package/docs/pagination.md +144 -0
  26. package/docs/persistence.md +114 -0
  27. package/docs/portfolio-rebalancer.md +94 -0
  28. package/docs/query-builder.md +179 -0
  29. package/docs/quick-search.md +84 -0
  30. package/docs/row-details.md +115 -0
  31. package/docs/row-interaction.md +149 -0
  32. package/docs/row-pinning.md +132 -0
  33. package/docs/row-selection.md +136 -0
  34. package/docs/row-styling.md +133 -0
  35. package/docs/scrolling.md +112 -0
  36. package/docs/server-query.md +246 -0
  37. package/docs/server-side.md +206 -0
  38. package/docs/sorting.md +101 -0
  39. package/docs/styling.md +126 -0
  40. package/docs/summary-row.md +76 -0
  41. package/docs/testing.md +744 -0
  42. package/docs/toolbar.md +161 -0
  43. package/docs/use-tm-data-grid.md +361 -0
  44. package/package.json +22 -46
  45. package/skills/appearance/SKILL.md +72 -19
  46. package/skills/cell-selection/SKILL.md +46 -47
  47. package/skills/columns/SKILL.md +90 -34
  48. package/skills/data/SKILL.md +86 -16
  49. package/skills/editing/SKILL.md +67 -40
  50. package/skills/editing/references/common-mistakes.md +77 -69
  51. package/skills/editing/references/editing-api.md +22 -19
  52. package/skills/editing/references/editors-and-validation.md +24 -17
  53. package/skills/filtering/SKILL.md +148 -40
  54. package/skills/getting-started/SKILL.md +17 -15
  55. package/skills/grouping/SKILL.md +31 -16
  56. package/skills/options/SKILL.md +7 -7
  57. package/skills/rows/SKILL.md +22 -18
  58. package/skills/server-side/SKILL.md +170 -17
  59. package/skills/testing/SKILL.md +150 -32
  60. package/skills/testing-components/SKILL.md +230 -0
  61. package/skills/testing-editing/SKILL.md +240 -0
  62. package/src/{tmdatagrid/components → components}/TMDataGrid.tsx +38 -21
  63. package/src/{tmdatagrid/components → components}/TMDataGridCellEditor.tsx +54 -8
  64. package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.module.css +5 -1
  65. package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.tsx +47 -55
  66. package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.tsx +5 -51
  67. package/src/{tmdatagrid/components → components}/TMDataGridDraftActions.tsx +41 -24
  68. package/src/{tmdatagrid/components → components}/TMDataGridEditColumn.tsx +12 -59
  69. package/src/{tmdatagrid/components → components}/TMDataGridEntryRows.tsx +164 -92
  70. package/src/components/TMDataGridExportPicker.module.css +77 -0
  71. package/src/components/TMDataGridExportPicker.tsx +234 -0
  72. package/src/components/TMDataGridFilterPanel.module.css +54 -0
  73. package/src/components/TMDataGridFilterPanel.tsx +348 -0
  74. package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.tsx +15 -8
  75. package/src/components/TMDataGridFilterSurface.module.css +54 -0
  76. package/src/components/TMDataGridFilterSurface.tsx +167 -0
  77. package/src/{tmdatagrid/components → components}/TMDataGridFooter.tsx +53 -90
  78. package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.tsx +5 -69
  79. package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.module.css +12 -2
  80. package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.tsx +58 -21
  81. package/src/components/TMDataGridHeaderFilterRow.module.css +51 -0
  82. package/src/components/TMDataGridHeaderFilterRow.tsx +301 -0
  83. package/src/components/TMDataGridMenu.tsx +357 -0
  84. package/src/{tmdatagrid/components → components}/TMDataGridSelectColumn.tsx +11 -48
  85. package/src/{tmdatagrid/components → components}/TMDataGridTable.module.css +69 -56
  86. package/src/{tmdatagrid/components → components}/TMDataGridTable.tsx +240 -138
  87. package/src/{tmdatagrid/components → components}/TMDataGridToolbar.module.css +5 -0
  88. package/src/components/TMDataGridToolbar.tsx +181 -0
  89. package/src/{tmdatagrid/components → components}/editors/TMDataGridBooleanEditor.tsx +3 -3
  90. package/src/{tmdatagrid/components → components}/editors/TMDataGridDateEditor.tsx +3 -3
  91. package/src/{tmdatagrid/components → components}/editors/TMDataGridMultiSelectEditor.tsx +3 -3
  92. package/src/{tmdatagrid/components → components}/editors/TMDataGridNumberEditor.tsx +3 -3
  93. package/src/{tmdatagrid/components → components}/editors/TMDataGridSelectEditor.tsx +3 -3
  94. package/src/{tmdatagrid/components → components}/editors/TMDataGridStringEditor.tsx +3 -3
  95. package/src/{tmdatagrid/components → components}/editors/editorShared.ts +16 -2
  96. package/src/{tmdatagrid/components → components}/filters/DgAutocompleteFilter.tsx +5 -4
  97. package/src/{tmdatagrid/components → components}/filters/DgDateRangeFilter.tsx +22 -5
  98. package/src/{tmdatagrid/components → components}/filters/DgRangeSliderFilter.tsx +5 -1
  99. package/src/{tmdatagrid/components → components}/filters/DgTriStateFilter.tsx +5 -1
  100. package/src/{tmdatagrid/components → components}/filters/TMDataGridFilterValueInput.tsx +44 -28
  101. package/src/components/filters/controlLayout.ts +32 -0
  102. package/src/components/filters/filterControlFor.ts +65 -0
  103. package/src/components/generatedColumns.tsx +187 -0
  104. package/src/{tmdatagrid/components → components}/icons.ts +1 -0
  105. package/src/{tmdatagrid/components → components}/sticky.module.css +44 -0
  106. package/src/components/useHideableColumns.ts +52 -0
  107. package/src/{tmdatagrid/core → core}/autosize.ts +5 -2
  108. package/src/{tmdatagrid/core → core}/columnOptions.ts +60 -8
  109. package/src/{tmdatagrid/core → core}/columnOrdering.ts +33 -14
  110. package/src/{tmdatagrid/core → core}/columnUtils.ts +44 -5
  111. package/src/core/controlledStateSync.ts +108 -0
  112. package/src/core/deletedRows.ts +34 -0
  113. package/src/core/dom.ts +74 -0
  114. package/src/{tmdatagrid/core → core}/editEngine.ts +1107 -460
  115. package/src/core/export.ts +704 -0
  116. package/src/{tmdatagrid/core → core}/filterControls.ts +38 -1
  117. package/src/{tmdatagrid/core → core}/filterOperators.ts +64 -1
  118. package/src/core/filterSurface.ts +99 -0
  119. package/src/{tmdatagrid/core → core}/grouping.ts +21 -0
  120. package/src/{tmdatagrid/core → core}/labels.ts +51 -6
  121. package/src/{tmdatagrid/core → core}/labelsSv.ts +27 -6
  122. package/src/core/pageReset.ts +120 -0
  123. package/src/core/pagination.ts +81 -0
  124. package/src/{tmdatagrid/core → core}/persistence.ts +22 -5
  125. package/src/{tmdatagrid/core → core}/summary.ts +20 -4
  126. package/src/{tmdatagrid/index.ts → index.ts} +69 -35
  127. package/src/{tmdatagrid/useTMDataGrid.tsx → useTMDataGrid.tsx} +428 -109
  128. package/src/useTMDataGridExport.ts +78 -0
  129. package/src/tmdatagrid/components/TMDataGridFilterPanel.module.css +0 -35
  130. package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +0 -354
  131. package/src/tmdatagrid/components/TMDataGridToolbar.tsx +0 -161
  132. package/src/tmdatagrid/core/cellExport.ts +0 -320
  133. /package/src/{tmdatagrid/TMDataGridContext.ts → TMDataGridContext.ts} +0 -0
  134. /package/src/{tmdatagrid/components → components}/TMDataGrid.module.css +0 -0
  135. /package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.module.css +0 -0
  136. /package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.module.css +0 -0
  137. /package/src/{tmdatagrid/components → components}/TMDataGridFooter.module.css +0 -0
  138. /package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.module.css +0 -0
  139. /package/src/{tmdatagrid/components → components}/TMDataGridRowNumberColumn.tsx +0 -0
  140. /package/src/{tmdatagrid/components → components}/TMDataGridSearch.tsx +0 -0
  141. /package/src/{tmdatagrid/core → core}/capabilities.ts +0 -0
  142. /package/src/{tmdatagrid/core → core}/cellNavigation.ts +0 -0
  143. /package/src/{tmdatagrid/core → core}/cellRange.ts +0 -0
  144. /package/src/{tmdatagrid/core → core}/controlledState.ts +0 -0
  145. /package/src/{tmdatagrid/core → core}/draftCellContext.ts +0 -0
  146. /package/src/{tmdatagrid/core → core}/editorFocus.ts +0 -0
  147. /package/src/{tmdatagrid/core → core}/expanding.ts +0 -0
  148. /package/src/{tmdatagrid/core → core}/matchHighlight.ts +0 -0
  149. /package/src/{tmdatagrid/core → core}/quickSearch.ts +0 -0
  150. /package/src/{tmdatagrid/core → core}/resizePreview.ts +0 -0
  151. /package/src/{tmdatagrid/core → core}/rowPinning.ts +0 -0
  152. /package/src/{tmdatagrid/core → core}/rowSelection.ts +0 -0
  153. /package/src/{tmdatagrid/core → core}/sizes.ts +0 -0
  154. /package/src/{tmdatagrid/core → core}/useSettledTableState.ts +0 -0
@@ -9,7 +9,7 @@ kind.
9
9
  | --- | --- | --- | --- |
10
10
  | `editing` | `TMDataGridEditingOptions` | off | The editing namespace. Setting it turns editing on. |
11
11
  | `editing.mode` | `"cell" \| "cellConfirm" \| "row"` | – | What counts as a commit, and which controls trigger it. |
12
- | `editing.draft` | `boolean` | `false` | Where a commit goes. On, it parks in the grid's draft store until `edit.saveDrafts()`. |
12
+ | `editing.draft` | `boolean` | `false` | Where a commit goes. On, it is held in the grid's draft store until `edit.saveDrafts()`. |
13
13
  | `getRowId` | `(row) => string` | – | A TanStack table option, required once `editing` is set. Drafts are keyed by it. |
14
14
  | `editing.columns` | `ReadonlyArray<string>` | every column mapping to a data path | The column ids that take edits. Gates before `meta.edit`, never past it: a column left out takes no edits whatever its meta says, and a listed column still answers to its `meta.edit.enabled`. Also decides which cells an entry row opens. |
15
15
  | `editing.isRowEditable` | `(row) => boolean` | – | Closes a whole row to editing, in every mode. |
@@ -28,8 +28,7 @@ the type.
28
28
  | Name | Argument | What it does |
29
29
  | --- | --- | --- |
30
30
  | `editing.onCommit` | `{ rowId, value, original, changes, source }` | Applies one row's change. Reject to keep the draft and show the error. |
31
- | `editing.onSaveDrafts` | `{ updated, created, deleted }` | `draft: true` only. One call for the whole draft store. Without it, `saveDrafts` loops `editing.onCommit`, `editing.onRowAdd` and `editing.onRowDelete`. |
32
- | `editing.onCommitDrafts` | `{ updated, created, deleted }` | **Deprecated** - renamed to `onSaveDrafts`. Still honoured; the new name wins if both are set. |
31
+ | `editing.onSaveDrafts` | `{ updated, created, deleted }` | `draft: true` only. One call for the whole draft store. May return a `TMDataGridSaveDraftsResponse` naming the ids that failed; they stay in the draft store. Without it, `saveDrafts` loops `editing.onCommit`, `editing.onRowAdd` and `editing.onRowDelete`. |
33
32
  | `editing.onRowAdd` | `{ tempId, value }` | Commits an entry row. Mint the real id here. |
34
33
  | `editing.onRowDelete` | `{ rowId, row }` | Deletes a row. Shows the trash; under `draft: true`, `onSaveDrafts` shows it too. |
35
34
 
@@ -54,24 +53,25 @@ path, which may be dotted.
54
53
  | Member | Signature | Notes |
55
54
  | --- | --- | --- |
56
55
  | `begin` | `({ rowId, columnId }) => void` | Row mode opens the entire row either way. `columnId` selects which cell takes the caret; `null` (the pencil) uses its first editable one. On a committed row it reopens it, taking it back out of the draft store. |
57
- | `commit` | `(rowId) => Promise<boolean>` | The OK gesture: submits the row's form. `false` keeps it open with its errors, and the message outlives the editor that found it. Under `draft: true` a pass parks the row - no consumer callback runs until `saveDrafts`. Column rules run whether or not an editor is mounted. |
58
- | `commitAll` | `() => Promise<boolean>` | Submits every open row. Rows that fail stay open. `false` when one did. |
59
- | `saveDrafts` | `() => Promise<boolean>` | Sends the draft store. Open rows are left alone and stay open. |
56
+ | `commit` | `(rowId) => Promise<boolean>` | The OK gesture: submits the row's form. `false` keeps it open with its errors, and the message outlives the editor that found it. Under `draft: true` a pass commits the row into the draft store - no consumer callback runs until `saveDrafts`. Column rules run whether or not an editor is mounted. |
57
+ | `commitAll` | `() => Promise<TMDataGridCommitAllResult>` | Submits every open row. Rows that fail stay open. Resolves `{ ok, committed, open }`: every row open at the call is in exactly one list, and `ok` is `false` when one stayed open. |
58
+ | `saveDrafts` | `() => Promise<TMDataGridSaveDraftsResult>` | Sends the draft store, re-running `editing.tableValidators` only; a committed row that fails is reopened with its errors. Open rows are left alone and stay open. Resolves `{ ok, saved, kept, reopened }` over row ids and temp ids, all kinds mixed: `saved` left the draft store, `kept` is still in it for the next save (reported failed by `onSaveDrafts`, sent when it threw, or a deletion whose per-row `onRowDelete` threw), `reopened` is open again with an error (a table rule, or a throwing per-row `onCommit` / `onRowAdd`). `ok` is `false` when anything was kept or reopened. A call during a save joins it and resolves the same result. |
60
59
  | `cancel` | `(rowId) => void` | Drops one draft. |
61
60
  | `cancelAll` | `() => void` | Drops every draft. |
62
61
  | `deactivate` | `() => void` | Closes the editor without touching the draft, as blur does under `"cellConfirm"`. |
63
- | `submitAll` | `() => Promise<boolean>` | **Deprecated** - `commitAll()` then `saveDrafts()`. |
64
62
  | `clearCell` | `(rowId, columnId) => Promise<boolean>` | What Delete does: writes the type's empty value and commits. |
65
- | `setCellValue` | `(rowId, columnId, value) => Promise<boolean>` | Writes one cell and commits the row, with no editor - toolbar actions and bulk fills. The row need not be mounted; a row inside a collapsed group takes the write. `value` is the stored value, so `meta.edit.mapValue` does not run and `meta.edit.validate` does. Under `draft: true` the row parks like any hand-made edit. `false` when the cell takes no edit, or when validation refused the value and left the row open with its errors. |
63
+ | `setCellValue` | `(rowId, columnId, value) => Promise<boolean>` | Writes one cell and commits the row, with no editor - toolbar actions and bulk fills. The row need not be mounted; a row inside a collapsed group takes the write. `value` is the stored value, so `meta.edit.mapValue` does not run and `meta.edit.validate` does. Under `draft: true` the row is committed into the draft store like any hand-made edit. `false` when the cell takes no edit, or when validation refused the value and left the row open with its errors. |
66
64
  | `setRowValues` | `(rowId, values) => Promise<boolean>` | `setCellValue` for several cells of one row in a single commit - one consumer call and one draft entry. Keys are column ids. All or nothing: if any named cell takes no edit, nothing is written and it resolves `false`. |
67
65
  | `addRow` | `(values?) => string` | Opens an entry row, returns its `tempId`. `values` overrides `editing.newRowDefaults` key by key for that row; with no argument the row is `newRowDefaults` alone. |
68
- | `addRows` | `(rows, options?) => Promise<{ committed, open }>` | Opens a batch in one write, each row seeded as `addRow` seeds. `{ commit: true }` submits each as it lands - valid rows commit, invalid ones stay open with their errors. |
69
- | `deleteRow` | `(rowId) => void` | `editing.onRowDelete`, or a deletion mark under `draft: true`. Toggles: a second call restores the row. |
66
+ | `addRows` | `(rows, options?) => Promise<TMDataGridAddRowsResult>` | Opens a batch in one write, each row seeded as `addRow` seeds. `{ commit: true }` submits each as it lands - valid rows commit, invalid ones stay open with their errors. Resolves `{ ok, committed, open }`; `ok` is `false` when a row stayed open. |
67
+ | `deleteRow` | `(rowId) => void` | `editing.onRowDelete`, or a deletion mark under `draft: true`. Idempotent: a second call leaves the row marked; `restoreRow` is the undo. |
70
68
  | `canEditCell` | `(row, column) => boolean` | The check the built-in controls use. Both halves: the column's and the row's. |
71
69
  | `canEditRow` | `(row) => boolean` | The pencil's gate. |
72
70
  | `isColumnEditable` | `(column) => boolean` | The column's half alone, with no row in hand: it maps to a field, `editing.columns` lists it when that is set, and `meta.edit.enabled` is not `false`. |
73
71
  | `canDeleteRows` | `() => boolean` | Whether the delete control should be shown. |
74
- | `getForm` | `(rowId) => TMDataGridRowEditForm \| undefined` | The row's live `FormApi`. |
72
+ | `getForm` | `(rowId) => TMDataGridRowEditForm \| undefined` | The open row's live `FormApi`; `undefined` for a committed row. |
73
+ | `getRowValues` | `(rowId) => TData \| undefined` | The row as shown: the open form's values, else the committed draft, else the `data` value. `undefined` for an unknown row. |
74
+ | `getRows` | `() => ReadonlyArray<TMDataGridEditRowSnapshot>` | Every row as shown, from the core row model: drafts overlaid, entry rows appended, deletion-marked rows included and flagged `deleted`. |
75
75
  | `state` | `TMDataGridEditState` | Snapshot, for reads outside React. |
76
76
  | `store` | `Store<TMDataGridEditState>` | For `useSelector`. |
77
77
 
@@ -81,10 +81,10 @@ path, which may be dotted.
81
81
  type TMDataGridEditState = {
82
82
  // The cell the last open gesture named - where the caret goes.
83
83
  active: { rowId: string; columnId: string | null } | null;
84
- // Rows with a live form, committed or not. A row is *open* when it is in
85
- // here and not in `committedRowIds`.
84
+ // Every row the grid holds work for: open rows and committed rows. A row
85
+ // is *open* when it is in here and not in `committedRowIds`.
86
86
  openRowIds: ReadonlyArray<string>;
87
- // One `TMDataGridEditRowProjection` per open row.
87
+ // One `TMDataGridEditRowProjection` per row in `openRowIds`.
88
88
  rows: Record<
89
89
  string,
90
90
  {
@@ -96,8 +96,8 @@ type TMDataGridEditState = {
96
96
  values: TMDataGridRowData;
97
97
  }
98
98
  >;
99
- // The draft store's edit slice: existing rows whose form passed its submit,
100
- // parked for `saveDrafts`. Empty without `editing.draft`.
99
+ // The draft store's edit slice: existing rows that passed their commit,
100
+ // held as values for `saveDrafts`. Empty without `editing.draft`.
101
101
  committedRowIds: ReadonlyArray<string>;
102
102
  // What a committed row *is* to the table: the draft store's values per row,
103
103
  // snapshotted at each commit and kept across a reopen, so the row holds its
@@ -108,6 +108,8 @@ type TMDataGridEditState = {
108
108
  // a commit adds through `onRowAdd`, so it stays `false`.
109
109
  newRows: ReadonlyArray<{ tempId: string; committed: boolean }>;
110
110
  deletedRowIds: ReadonlyArray<string>;
111
+ // `true` while `saveDrafts` is in flight.
112
+ isSaving: boolean;
111
113
  };
112
114
  ```
113
115
 
@@ -119,12 +121,13 @@ type TMDataGridEditState = {
119
121
  | `TMDataGridDraftActions` | Export | The same component, for use outside the namespace. |
120
122
  | `EDIT_COLUMN_ID` | Export | `"__edit__"`, the generated edit lane's id. |
121
123
  | `clearedValueForType` | Export | `(type) => unknown` - what Delete writes per column type. |
124
+ | `hasPendingEdits` | Export | `(state) => boolean` - unsaved work: an open row with a changed value, any entry row, the draft store, or a save in flight. `useSelector(grid.edit.store, hasPendingEdits)` for a navigation blocker; do not use `openRowIds.length`, which also counts committed rows and rows that are only open. |
122
125
  | `getEditFieldName` | Export | `(column) => string` - the data path a column's edits write to. |
123
126
  | `normalizeFieldValidate` | Export | `(validate) => validators` - a bare schema into Form's shape. |
124
127
  | `TMDataGridStringEditor` … `TMDataGridMultiSelectEditor` | Exports | The six built-in editors, for wrapping. |
125
128
 
126
129
  Types: `TMDataGridEditMode`, `TMDataGridEditApi`, `TMDataGridEditState`,
127
- `TMDataGridEditCommitArgs`, `TMDataGridEditCommitDraftsArgs`,
130
+ `TMDataGridEditCommitArgs`, `TMDataGridSaveDraftsArgs`,
128
131
  `TMDataGridEditChange`, `TMDataGridEditorArgs`, `TMDataGridEditorComponent`,
129
132
  `TMDataGridEditField`, `TMDataGridEditRowProjection`, `TMDataGridFieldValidate`,
130
133
  `TMDataGridRowValidators`, `TMDataGridRowEditForm`, `TMDataGridRowAddArgs`,
@@ -148,11 +151,11 @@ The trash itself shows when the deletion has somewhere to report to:
148
151
  mark is part of the save.
149
152
 
150
153
  What the lane holds follows the row's state, one axis each. An open row shows
151
- the mode's own controls, `save-row` and `cancel-row`. A parked row shows
154
+ the mode's own controls, `save-row` and `cancel-row`. A committed row shows
152
155
  `row-state` instead, whose `data-state` is `new`, `edited` or `deleted`,
153
156
  together with `revert-row` on an edited row, `restore-row` on one marked for
154
157
  deletion, and `edit-row` plus `discard-new-row` on an entered new row - never a
155
- save, which the engine would only park again. A parked row hides `delete-row`.
158
+ save, which the engine would only commit again. A committed row hides `delete-row`.
156
159
  Every control carries a tooltip from the labels, `revertRow`, `rowStateNew`,
157
160
  `rowStateEdited` and `rowStateDeleted` among them.
158
161
 
@@ -63,11 +63,11 @@ Bind any control to `field` exactly as inside any TanStack Form:
63
63
  `field.state.value`, `field.state.meta.errors`, `field.handleChange`,
64
64
  `field.handleBlur`.
65
65
 
66
- Binding `field.state.meta.errors` is what shows a refused commit: the built-in
67
- editors pass the first error to the input's `error` prop, and an editor that
68
- binds nothing leaves a blocked save as `data-invalid` on the cell with no
69
- message on screen. An entry is a string from a function validator, or an issue
70
- carrying a `message` from a schema.
66
+ The message itself is the host's: it shows in a tooltip on the editor, opened
67
+ by focus and by hover, for a custom editor as much as a built-in one. What an
68
+ editor binds is the invalid state - the built-ins pass a boolean to the input's
69
+ `error` prop for the border alone, and an editor that binds nothing looks
70
+ unchanged while the commit is refused.
71
71
 
72
72
  ```tsx
73
73
  import { Slider } from "@mantine/core";
@@ -193,8 +193,13 @@ meta: { edit: { validate: z.string().min(2, "At least two characters") } }
193
193
  // Object form: pick the trigger.
194
194
  meta: { edit: { validate: { onBlur: z.string().email("Not an email address") } } }
195
195
 
196
- // A plain function works too.
197
- meta: { edit: { validate: ({ value }) => (value > 0 ? undefined : "Must be positive") } }
196
+ // A plain function works too. `value` is typed `never`, so annotate the parameter.
197
+ meta: {
198
+ edit: {
199
+ validate: ({ value }: { value: unknown }) =>
200
+ typeof value === "number" && value > 0 ? undefined : "Must be positive",
201
+ },
202
+ }
198
203
  ```
199
204
 
200
205
  `normalizeFieldValidate(validate)` is exported for consumers building their own
@@ -224,8 +229,8 @@ const grid = useTMDataGrid({
224
229
  ```
225
230
 
226
231
  Issues with a path land on the matching column's cell; pathless issues land on
227
- the row, where the message shows in the edit lane's tooltip - on the open
228
- row's ✓, and on the parked row's marker. A nested schema's issues follow the
232
+ the row, where the message shows in the edit lane's tooltip on the open
233
+ row's ✓. A nested schema's issues follow the
229
234
  same rule, so a `address.city` issue lands on the column whose `editField` is
230
235
  `"address.city"`.
231
236
 
@@ -261,9 +266,9 @@ row's cells. `onSubmit` runs first, and its failure stands without
261
266
  `onSubmitAsync` running. Errors land on the committing row only.
262
267
 
263
268
  The rules run at every commit - typed, ✓, `edit.setCellValue`, an entry
264
- row's - after the row's own validators, and again for every parked row during
265
- `saveDrafts`: a draft that a later edit invalidated fails there, keeps its
266
- markers, and the save resolves `false`.
269
+ row's - after the row's own validators, and again for every committed row during
270
+ `saveDrafts`, the only rules that run there: a committed row that a later edit
271
+ invalidated is reopened with its errors, and the save reports it in `reopened`.
267
272
 
268
273
  ## Server-side errors
269
274
 
@@ -283,9 +288,9 @@ rowValidators: {
283
288
  },
284
289
  ```
285
290
 
286
- A commit blocked by validation keeps the editor open with the message on the
287
- input. A rejected `editing.onCommit` keeps the draft too, with the error on the
288
- row.
291
+ A commit blocked by validation keeps the editor open, invalid, with the message
292
+ in its tooltip. A rejected `editing.onCommit` keeps the draft too, with the
293
+ error on the row.
289
294
 
290
295
  ## Where the state shows
291
296
 
@@ -294,11 +299,13 @@ row.
294
299
  | The cell's own value | A held draft is displayed: the cell renders the draft value through the column's `cell` renderer, in every mode |
295
300
  | Blue cell corner | The field is dirty against its original value |
296
301
  | Red cell corner | The field carries a validation error |
297
- | Row error text | A pathless rule failed, or a commit was rejected. In the lane's tooltip: the open row's ✓, or the parked row's marker |
302
+ | Field error message | In a tooltip on the open editor, shown while the input has focus and on hover |
303
+ | Row error text | A pathless rule failed, or a commit was rejected. In the lane's tooltip, on the open row's ✓ |
298
304
  | `data-dirty` on the row | The row holds a dirty draft |
299
305
 
300
306
  The same information is readable from `edit.store`: `rows[rowId].dirtyFields`,
301
307
  `rows[rowId].errorFields`, `rows[rowId].errorMessages` (`{ field, message }`
302
308
  pairs), `rows[rowId].hasRowError`, `rows[rowId].isSubmitting`, and
303
309
  `rows[rowId].values` for the draft itself. The pathless message's text is not
304
- in the store; read it from `edit.getForm(rowId)?.state.errors`.
310
+ in the store; read it from `edit.getForm(rowId)?.state.errors` on the open
311
+ row that carries it.
@@ -3,24 +3,27 @@ name: filtering
3
3
  description: >
4
4
  Narrow the rows a TMDataGrid shows. Covers the shared tmDataGrid filter
5
5
  function and its {operator, value} model, the eighteen operators and which
6
- meta.type offers each, meta.filter.defaultOperator, isFilterActive and the
7
- half-typed filter, the filter panel, TMDataGrid.FilterButton,
8
- TMDataGrid.FilterPills with its api prop, openColumnFilter, replacing a value
9
- control with DgRangeSliderFilter / DgDateRangeFilter / DgAutocompleteFilter /
10
- DgTriStateFilter or a meta.filter.control component, per-column filterFn, and
11
- the quick search: TMDataGrid.Search, quickSearchMode fuzzy or contains,
12
- fuzzyGlobalFilterFn, enableMatchHighlighting and enableGlobalFilter. Load when
13
- adding filters, choosing operators, building a filter control, showing active
14
- filters outside the grid, or wiring a search box.
6
+ meta.type offers each, meta.filter.operators to offer a column only a subset
7
+ of them, meta.filter.defaultOperator, isFilterActive and the half-typed
8
+ filter, the filters option and its surfaces (popup, sidebar, none, plus
9
+ inHeader for header filters), TMDataGrid.FilterPanel and its layout prop,
10
+ TMDataGrid.FilterButton, TMDataGrid.FilterPills with its api prop,
11
+ openColumnFilter, replacing a value control with DgRangeSliderFilter /
12
+ DgDateRangeFilter / DgAutocompleteFilter / DgTriStateFilter or a
13
+ meta.filter.control component, per-column filterFn, and the quick search:
14
+ TMDataGrid.Search, quickSearchMode fuzzy or contains, fuzzyGlobalFilterFn,
15
+ enableMatchHighlighting and enableGlobalFilter. Load when adding filters,
16
+ choosing operators, building a filter control, showing active filters outside
17
+ the grid, or wiring a search box.
15
18
  metadata:
16
19
  type: core
17
20
  library: '@jielga/tmdatagrid'
18
- library_version: '2.0.0-beta.9'
21
+ library_version: '2.0.0'
19
22
  sources:
20
- - 'Jielga/TMDataGrid:src/docs/filtering.md'
21
- - 'Jielga/TMDataGrid:src/docs/quick-search.md'
22
- - 'Jielga/TMDataGrid:src/tmdatagrid/core/filterOperators.ts'
23
- - 'Jielga/TMDataGrid:src/tmdatagrid/core/quickSearch.ts'
23
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/docs/filtering.md'
24
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/docs/quick-search.md'
25
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/filterOperators.ts'
26
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/quickSearch.ts'
24
27
  ---
25
28
 
26
29
  # TMDataGrid - Filtering
@@ -48,7 +51,9 @@ leaving that end open).
48
51
 
49
52
  A filter with an empty value **stays in state** so the panel keeps its row while
50
53
  the user types. It matches every row, does not set the header indicator and
51
- produces no pill. `isFilterActive(value)` tests for that state; presence in
54
+ produces no pill. `isFilterActive(value)` tests for that state, and
55
+ `activeColumnFilters(columnFilters | table)` applies it across the slice and
56
+ types what it hands back (entries in any other value shape are dropped); presence in
52
57
  `columnFilters` does not.
53
58
 
54
59
  ## Operators
@@ -80,16 +85,105 @@ columnHelper.accessor("salary", {
80
85
  });
81
86
  ```
82
87
 
83
- ## The panel and the pills
88
+ `meta.filter.operators` narrows the list a column offers to a subset of its
89
+ type's - for a column whose backend answers only some operators, so the user is
90
+ never offered one the query cannot express. The panel dropdown and the header
91
+ funnel show only those, in the type's order. An operator the type does not
92
+ offer is ignored; a list that leaves nothing falls back to the type's full set.
93
+ Without `defaultOperator`, a fresh filter opens on the type's default when it is
94
+ offered, else on the first offered operator.
84
95
 
85
- `TMDataGrid.FilterPanel` is column, operator and value rows under a "Filters"
86
- header, above "Add filter" and "Clear all". It is rendered by
87
- `TMDataGrid.Table`; Escape and a click outside close it, with `FilterButton`
88
- exempt from the click-away so it stays a toggle. Closing only hides it; the
89
- filters stay. **Clear all** drops every filter, half-typed ones included.
96
+ ```tsx
97
+ columnHelper.accessor("customer", {
98
+ header: "Customer",
99
+ meta: { filter: { operators: ["contains", "equals", "isEmpty", "isNotEmpty"] } },
100
+ });
101
+ ```
102
+
103
+ `getColumnOperators(column)` returns the resolved list and
104
+ `getColumnDefaultOperator(column)` the operator a fresh filter opens on. The
105
+ `server-side` skill shows the list typed together with the API mapping table.
106
+
107
+ ## The filters option
108
+
109
+ `filters` on `useTMDataGrid` picks the surface. It is read field by field, so a
110
+ literal is fine.
111
+
112
+ | Option | Type | Default | What it does |
113
+ | --- | --- | --- | --- |
114
+ | `surface` | `"popup" \| "sidebar" \| "none"` | `"popup"` | What `TMDataGrid.Table` renders and `FilterButton` toggles. |
115
+ | `sidebarSide` | `"left" \| "right"` | `"right"` | Which side the sidebar sits on. Ignored by the other surfaces. |
116
+ | `sidebarWidth` | `string` | `"280px"` | Sidebar width, any CSS length. Ignored by the other surfaces. |
117
+ | `defaultOpen` | `boolean` | `true` under `"sidebar"`, else `false` | Whether the surface starts open. Read once, at mount. Under `"none"`, the starting value of `ui.state.filterPanelOpen`. |
118
+ | `inHeader` | `boolean` | `false` | A second header row of per-column controls. Independent of `surface`. |
119
+
120
+ `surface` and `inHeader` are separate choices: `{ surface: "none", inHeader: true }`
121
+ is header filters alone, `{ inHeader: true }` keeps the popup as well.
122
+
123
+ ```tsx
124
+ useTMDataGrid({ data, columns, filters: { surface: "sidebar", inHeader: true } });
125
+ ```
126
+
127
+ **Popup** - the default. Floats over the first body rows. A pointerdown
128
+ outside, Escape, and emptying it (the last row removed, or **Clear all**) all
129
+ close it; `FilterButton` is exempt from the click-away so it stays a toggle.
130
+
131
+ **Sidebar** - the same panel beside the rows, inside the grid frame and under
132
+ the toolbar. The rows give up the width rather than being covered, a click in
133
+ the table does not dismiss it, and clearing the filters leaves it standing.
134
+ Escape closes it. It starts open, being a layout choice; its rows are
135
+ `layout="stacked"`, since 280px has no room for the triple.
136
+
137
+ **Header filters** - `inHeader: true` adds a header row of value controls, one
138
+ per filterable column, on the same column tracks as everything else. The
139
+ column and operator dropdowns are not there: the column is the one the cell
140
+ sits over, and the operator is a funnel button beside the input, tinted off its
141
+ default. The column menu's Filter item and the funnel indicator both come off,
142
+ having nothing left to reveal; the filtered column's tinted title stays. A
143
+ narrow column clips its control - give it a `minSize`.
90
144
 
91
- `TMDataGrid.FilterPills` takes the grid as an `api` prop instead of reading
92
- context, so active filters can live in a page header or anywhere else:
145
+ Clearing a header control removes the column's `columnFilters` entry rather
146
+ than leaving an empty one, unless the user also picked a non-default operator,
147
+ which is kept. Panel rows still keep their empty filters.
148
+
149
+ `FilterButton` still toggles whatever `surface` names. `openColumnFilter` does
150
+ not: under `inHeader` it always focuses the header control and leaves the
151
+ surface closed.
152
+
153
+ **None** - `surface: "none"` renders no panel and no `FilterButton`, so a
154
+ hand-placed `TMDataGrid.FilterPanel` is the only one. Read
155
+ `ui.state.filterPanelOpen` if it belongs behind a control of your own.
156
+
157
+ ## TMDataGrid.FilterPanel
158
+
159
+ The panel of filter rows - one column / operator / value triple per filter, over "Add filter" and "Clear all".
160
+ A plain block with no title, no close button and no open state: it renders wherever it is mounted, and the popup and sidebar surfaces are wrappers around it.
161
+ It must be inside `<TMDataGrid>` (it reads the grid from context) and it only reads and writes `columnFilters`, so a `manualFiltering` grid gets it for free.
162
+ Closing a surface only hides it; the filters stay.
163
+ **Clear all** drops every filter, half-typed ones included.
164
+
165
+ | Prop | Type | Default | Description |
166
+ | --- | --- | --- | --- |
167
+ | `layout` | `"row" \| "stacked"` | `"row"` | `"row"` is side by side and wants about 550px; `"stacked"` fills a narrow host. Passed to every value control as its `layout`. |
168
+
169
+ ```tsx
170
+ <Drawer opened={open} onClose={close}>
171
+ <TMDataGrid.FilterPanel layout="stacked" />
172
+ </Drawer>
173
+ ```
174
+
175
+ ## TMDataGrid.FilterButton
176
+
177
+ The toolbar button that toggles the filter surface, tinted with the count of active filters.
178
+ Opening an empty panel seeds a filter row on the first filterable column; with filters already in state it opens on those.
179
+ Renders nothing when no column can be filtered, and nothing under `surface: "none"`.
180
+ No props.
181
+
182
+ ## TMDataGrid.FilterPills
183
+
184
+ One pill per **active** filter, `First name: Sofia ✕`, where the ✕ clears it and a click on the label calls `openColumnFilter`.
185
+ The label spells the operator out unless it is the type's default: `Age is greater than 30`, but `First name: Sofia`.
186
+ It takes the grid as an `api` prop instead of reading context, so it renders anywhere on the page.
93
187
 
94
188
  ```tsx
95
189
  import { TMDataGridFilterPills } from "@jielga/tmdatagrid";
@@ -97,11 +191,18 @@ import { TMDataGridFilterPills } from "@jielga/tmdatagrid";
97
191
  <TMDataGridFilterPills api={grid} onPillClick={(columnId) => focus(columnId)} />;
98
192
  ```
99
193
 
100
- One pill per **active** filter, `First name: Sofia ✕`, where ✕ clears it and a
101
- click on the label reopens the panel on its column. The label spells the
102
- operator out unless it is the type's default: `Age is greater than 30`, but
103
- `First name: Sofia`. `openColumnFilter(api, columnId)` does the same reopening
104
- from anywhere, seeding an empty row if the column has none.
194
+ | Prop | Type | Default | Description |
195
+ | --- | --- | --- | --- |
196
+ | `api` | `TMDataGridApi<TData>` | - | The object returned by `useTMDataGrid`. |
197
+ | `size` | `MantineSize` | `"sm"` | Pill size. |
198
+ | `showClearAll` | `boolean` | `true` | "Clear all", shown once two filters are active. |
199
+ | `onPillClick` | `(columnId: string) => void` | - | Replaces the default click behaviour. |
200
+ | `className` | `string` | - | Added to the wrapper class. |
201
+
202
+ ## openColumnFilter
203
+
204
+ `openColumnFilter(api, columnId)` seeds an empty filter if the column has none, then opens the surface on that column's panel row - or, under `inHeader`, scrolls the column's header control into view and focuses it, leaving the surface closed.
205
+ It is what a pill's label and the column menu's Filter item both call.
105
206
 
106
207
  ## Replacing the value control
107
208
 
@@ -220,12 +321,13 @@ const activeCount = columnFilters.length;
220
321
  Correct:
221
322
 
222
323
  ```tsx
223
- import { isFilterActive } from "@jielga/tmdatagrid";
324
+ import { activeColumnFilters } from "@jielga/tmdatagrid";
224
325
 
225
- const active = columnFilters.filter((filter) => isFilterActive(filter.value));
326
+ // The entries that narrow anything, with `value` typed rather than `unknown`.
327
+ const active = activeColumnFilters(columnFilters);
226
328
  ```
227
329
 
228
- Source: `src/docs/filtering.md` (How a filter is stored).
330
+ Source: `packages/tmdatagrid/docs/filtering.md` (How a filter is stored).
229
331
 
230
332
  ### HIGH Assuming `value` is always a string
231
333
 
@@ -246,7 +348,7 @@ if (operatorTakesRangeValue(operator)) {
246
348
  }
247
349
  ```
248
350
 
249
- Source: `src/tmdatagrid/core/filterOperators.ts`.
351
+ Source: `packages/tmdatagrid/src/core/filterOperators.ts`.
250
352
 
251
353
  ### HIGH A numeric column with no `meta.type`
252
354
 
@@ -255,7 +357,7 @@ Source: `src/tmdatagrid/core/filterOperators.ts`.
255
357
  `between` never appear in the panel, and comparisons run as text, where `"9"`
256
358
  sorts above `"10"`.
257
359
 
258
- Source: `src/docs/filtering.md` (Operators).
360
+ Source: `packages/tmdatagrid/docs/filtering.md` (Operators).
259
361
 
260
362
  ### HIGH A filter control defined inside the component
261
363
 
@@ -272,7 +374,7 @@ const StatusFilter: TMDataGridFilterControlComponent = (args) => { /* … */ };
272
374
  meta: { filter: { control: StatusFilter } }
273
375
  ```
274
376
 
275
- Source: `src/docs/filtering.md` (Writing your own).
377
+ Source: `packages/tmdatagrid/docs/filtering.md` (Writing your own).
276
378
 
277
379
  ### MEDIUM Writing the whole filter from a custom control
278
380
 
@@ -292,7 +394,7 @@ Correct:
292
394
  onChange(picked);
293
395
  ```
294
396
 
295
- Source: `src/docs/filtering.md` (Writing your own).
397
+ Source: `packages/tmdatagrid/docs/filtering.md` (Writing your own).
296
398
 
297
399
  ### MEDIUM Expecting match highlighting in a custom cell
298
400
 
@@ -301,7 +403,7 @@ does not modify a custom renderer's output. A column with a `cell` renderer
301
403
  shows no marks whatever `enableMatchHighlighting` is set to. Equality operators
302
404
  highlight nothing either.
303
405
 
304
- Source: `src/docs/quick-search.md` (Match highlighting).
406
+ Source: `packages/tmdatagrid/docs/quick-search.md` (Match highlighting).
305
407
 
306
408
  ### MEDIUM Expecting fuzzy ranking to survive a sort
307
409
 
@@ -309,7 +411,7 @@ The rank ordering applies only while the search is the sole narrowing. Any sort
309
411
  or grouping replaces it. The ordering is derived and never written into
310
412
  `sorting`, so there is nothing to clear afterwards.
311
413
 
312
- Source: `src/docs/quick-search.md` (Fuzzy by default).
414
+ Source: `packages/tmdatagrid/docs/quick-search.md` (Fuzzy by default).
313
415
 
314
416
  ## Reference
315
417
 
@@ -318,20 +420,26 @@ Source: `src/docs/quick-search.md` (Fuzzy by default).
318
420
  | `enableColumnFilters` | Table option | `boolean` | `true` | `false` removes the panel, the button and the menu item. |
319
421
  | `enableColumnFilter` | Column option | `boolean` | `true` | `false` takes one column out of filtering. |
320
422
  | `meta.type` | Column meta | `TMDataGridColumnType` | `"string"` | Selects the operators and the value control. |
321
- | `meta.filter.defaultOperator` | Column meta | `TMDataGridFilterOperator` | The type's default | The operator a fresh filter opens on. |
423
+ | `meta.filter.operators` | Column meta | `readonly TMDataGridFilterOperator[]` | The type's list | The operators this column offers, a subset of its type's. |
424
+ | `meta.filter.defaultOperator` | Column meta | `TMDataGridFilterOperator` | The type's default, else the first offered | The operator a fresh filter opens on. |
322
425
  | `meta.filter.control` | Column meta | `TMDataGridFilterControlComponent` | By type and operator | Replaces the value control. Module scope. |
323
426
  | `filterFn` | Column option | name or fn | `"tmDataGrid"` | Custom matching for one column. |
324
427
  | `quickSearchMode` | Option | `"fuzzy" \| "contains"` | `"fuzzy"` | How the quick search matches. |
325
428
  | `enableMatchHighlighting` | Option | `boolean` | `false` | Mark matched text in default-rendered cells. |
326
429
  | `enableGlobalFilter` | Table option | `boolean` | `true` | Also a column option. Removes the input, or one column's participation. |
327
430
  | `globalFilterFn` | Table option | filter fn | fuzzy | Overrides the matching, and the ranking with it. |
328
- | `TMDataGrid.FilterPanel` | Component | – | – | The panel of filter rows. |
431
+ | `TMDataGrid.FilterPanel` | Component | `layout: "row" \| "stacked"`, Mantine `BoxProps` | `"row"` | The panel of filter rows, as a plain block. Style props set on it. |
432
+ | `filters` | Table option | `TMDataGridFiltersOptions` | `{ surface: "popup" }` | Which surface holds the filter controls. |
433
+ | `TMDataGridFilterControlArgs.layout` | Type | `"row" \| "stacked" \| "header"` | – | How much room a value control has, and whether it names itself. |
434
+ | `filterValueShape` | Export | `(operator) => "scalar" \| "set" \| "range"` | – | Which shape an operator's value takes. |
329
435
  | `TMDataGrid.FilterButton` | Component | – | – | Toolbar button opening the panel, with an active count. |
330
- | `TMDataGrid.FilterPills` | Component | `api`, `size`, `showClearAll`, `onPillClick`, `className` | – | Active filters as removable pills, renderable anywhere. |
436
+ | `TMDataGrid.FilterPills` | Component | `api`, `size`, `showClearAll`, `onPillClick`, Mantine `BoxProps` | – | Active filters as removable pills, renderable anywhere. Style props set on the wrapper. |
331
437
  | `TMDataGrid.Search` | Component | `placeholder`, `debounce` (`250`), `w` (`220`) | – | The debounced quick-search input. |
332
438
  | `openColumnFilter` | Export | `(api, columnId) => void` | – | Opens the panel on a column. |
333
439
  | `isFilterActive` | Export | `(value) => boolean` | – | Whether a filter value narrows anything. |
440
+ | `activeColumnFilters` | Export | `(columnFilters \| table) => Array<{ id, value }>` | – | The filters in the grid's own value shape that narrow anything, typed. |
334
441
  | `getOperatorsForType` | Export | `(type) => operators` | – | The operator list a type offers. |
442
+ | `getColumnOperators` · `getColumnDefaultOperator` | Exports | `(column) => operators` · `(column) => operator` | – | One column's list after `meta.filter.operators`, and the operator a fresh filter on it opens on. |
335
443
  | `FILTER_OPERATOR_LABELS` | Export | record | – | The label shown for each operator. |
336
444
  | `formatFilterLabel` | Export | `({ label, type, filter }) => string` | – | The one-line description used on the pills. |
337
445
  | `emptyValueForOperator` · `operatorNeedsValue` · `operatorTakesArrayValue` · `operatorTakesRangeValue` | Exports | – | – | What shape of value an operator expects. |
@@ -4,19 +4,19 @@ description: >
4
4
  Set up TMDataGrid, a compound React data grid built on TanStack Table v9 and
5
5
  Mantine. Covers useTMDataGrid, the TMDataGrid root, context, the component
6
6
  catalog (Table, Footer, Toolbar, Spacer, SummaryCount, Search,
7
- LoadingIndicator, DraftActions, FilterButton, ColumnsButton, FilterPanel,
8
- FilterPills, ColumnsPanel), the size scale and the bounded-height layout
9
- requirement. Load when adding a grid, choosing which parts to render, or when
10
- rows do not appear.
7
+ LoadingIndicator, DraftActions, FilterButton, Menu, FilterPanel, FilterPills,
8
+ ColumnsPanel), the size scale and the bounded-height layout requirement. Load
9
+ when adding a grid, choosing which parts to render, or when rows do not
10
+ appear.
11
11
  metadata:
12
12
  type: core
13
13
  library: '@jielga/tmdatagrid'
14
- library_version: '2.0.0-beta.9'
14
+ library_version: '2.0.0'
15
15
  sources:
16
- - 'Jielga/TMDataGrid:src/docs/getting-started.md'
17
- - 'Jielga/TMDataGrid:src/docs/anatomy.md'
18
- - 'Jielga/TMDataGrid:src/tmdatagrid/components/TMDataGrid.tsx'
19
- - 'Jielga/TMDataGrid:src/tmdatagrid/core/sizes.ts'
16
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/docs/getting-started.md'
17
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/docs/anatomy.md'
18
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/src/components/TMDataGrid.tsx'
19
+ - 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/sizes.ts'
20
20
  ---
21
21
 
22
22
  # TMDataGrid - Getting started
@@ -80,7 +80,9 @@ export function Employees({ data }: { data: Employee[] }) {
80
80
  <TMDataGrid.SummaryCount />
81
81
  <TMDataGrid.Spacer />
82
82
  <TMDataGrid.FilterButton />
83
- <TMDataGrid.ColumnsButton />
83
+ <TMDataGrid.Menu>
84
+ <TMDataGrid.Menu.Columns />
85
+ </TMDataGrid.Menu>
84
86
  </TMDataGrid.Toolbar>
85
87
 
86
88
  <TMDataGrid.Table<Employee> />
@@ -149,7 +151,7 @@ flex column.
149
151
  | Component | Props | Notes |
150
152
  | --- | --- | --- |
151
153
  | `TMDataGrid` | `table`, `ui`, `features`, `size`, `className`, `style` | Root. Provides context. `style` also takes CSS variables: `--dg-row-selected-bg`, `--dg-row-height`, `--dg-header-height`, `--dg-font-size`, `--dg-padding`. |
152
- | `TMDataGrid.Table` | `onRowClick(row)`, `renderRowContextMenu`, `renderColumnMenuItems`, `rowContextMenuProps` | Header, virtualized body, filter panel. `onRowClick` runs in addition to selection under `selectionMode: "row"`. |
154
+ | `TMDataGrid.Table` | `onRowClick(row)`, `renderRowContextMenu`, `renderColumnMenuItems`, `rowContextMenuProps` | Header, virtualized body, and whichever filter surface the `filters` option asks for. `onRowClick` runs in addition to selection under `selectionMode: "row"`. |
153
155
  | `TMDataGrid.Footer` | `pageSizeOptions` (default `[10, 25, 50, 100]`), `pagination` render prop | Pagination controls. Renders nothing unless pagination is enabled. |
154
156
  | `TMDataGrid.Toolbar` | `children` | Flex row above the grid. |
155
157
  | `TMDataGrid.Spacer` | - | Pushes later toolbar items right. |
@@ -157,10 +159,10 @@ flex column.
157
159
  | `TMDataGrid.Search` | `placeholder`, `debounce` (default `250`), `w` (default `220`) | Quick search over every column, debounced into `globalFilter`. Renders nothing under `enableGlobalFilter: false`. |
158
160
  | `TMDataGrid.LoadingIndicator` | - | Small spinner while `meta.loading` is `true` and rows stay on screen. |
159
161
  | `TMDataGrid.DraftActions` | `renderActions` | Save with the pending count, and Discard. Renders nothing while editing is off - see the `editing` skill. |
160
- | `TMDataGrid.FilterButton` | - | Toggles filter panel. Renders nothing if no column is filterable. |
161
- | `TMDataGrid.ColumnsButton` | - | Opens column manager. Renders nothing if no column is hideable. |
162
- | `TMDataGrid.FilterPanel` | - | Rendered by `.Table`; exported for custom layouts. Header close button, Escape, click-away, "Add filter" and "Clear all". |
163
- | `TMDataGrid.ColumnsPanel` | - | Rendered by `.ColumnsButton`; exported for custom layouts. |
162
+ | `TMDataGrid.FilterButton` | - | Toggles the filter surface, seeding a filter row on the first filterable column. Renders nothing if no column is filterable, or under `filters.surface: "none"`. |
163
+ | `TMDataGrid.Menu` | `children`, `icon`, `label`, Mantine `MenuProps` | The burger and its dropdown: your own `Menu.Item`s, and `TMDataGrid.Menu.Columns`, the column chooser as menu items (renders nothing if no column is hideable). See the `appearance` skill. |
164
+ | `TMDataGrid.FilterPanel` | `layout` (`"row"` \| `"stacked"`, default `"row"`) | Filter rows over "Add filter" / "Clear all", as a plain block. Rendered by `.Table` inside the popup and the sidebar; place it yourself under `filters.surface: "none"`. See the `filtering` skill. |
165
+ | `TMDataGrid.ColumnsPanel` | - | The column chooser as plain controls, for a Popover or a Drawer. |
164
166
  | `TMDataGrid.FilterPills` | `api`, `size` (default `"sm"`), `showClearAll` (default `true`), `onPillClick(columnId)`, `className` | One pill per active filter, ✕ to clear it. Takes the api as a prop, so it can be rendered outside the grid. Also exported as `TMDataGridFilterPills`. |
165
167
 
166
168
  Pass the row type so `onRowClick` stays typed: