@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
package/dist/styles.css CHANGED
@@ -1,2 +1,2 @@
1
- ._root_pt0ni_3[data-size=xs]{--dg-row-height:34px;--dg-header-height:32px;--dg-font-size:var(--mantine-font-size-xs);--dg-padding:6px}._root_pt0ni_3[data-size=sm]{--dg-row-height:42px;--dg-header-height:38px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:8px}._root_pt0ni_3[data-size=md]{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px}._root_pt0ni_3[data-size=lg]{--dg-row-height:62px;--dg-header-height:52px;--dg-font-size:var(--mantine-font-size-md);--dg-padding:14px}._root_pt0ni_3[data-size=xl]{--dg-row-height:72px;--dg-header-height:60px;--dg-font-size:var(--mantine-font-size-lg);--dg-padding:18px}._root_pt0ni_3{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px;text-align:left;border:1px solid var(--mantine-color-default-border);border-radius:var(--mantine-radius-md);background-color:var(--mantine-color-body);flex-direction:column;min-height:0;display:flex;overflow:hidden}._toolbar_pt0ni_57{align-items:center;gap:var(--mantine-spacing-xs);padding:6px var(--mantine-spacing-xs);flex-shrink:0;min-height:42px;display:flex}._toolbarSpacer_pt0ni_66{flex:1}._tableWrapper_pt0ni_71{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}._scrollContainer_pt0ni_79{flex:1;min-height:0;position:relative;overflow:auto}._grid_pt0ni_87{display:grid}._headerRow_pt0ni_93{grid-column:1/-1;grid-template-columns:subgrid;z-index:3;display:grid;position:sticky;top:0}._headerCell_pt0ni_102{padding:0 var(--dg-padding);min-width:0;min-height:var(--dg-header-height);font-weight:600;font-size:var(--dg-font-size);background-color:var(--mantine-color-body);border-bottom:1px solid var(--mantine-color-default-border);-webkit-user-select:none;user-select:none;align-items:center;gap:2px;display:flex;position:relative}._headerCell_pt0ni_102[data-align=right]{justify-content:flex-end}._headerCell_pt0ni_102[data-align=center]{justify-content:center}._headerCell_pt0ni_102[data-active=true] ._headerTitle_pt0ni_126{color:var(--mantine-primary-color-filled)}._headerTitle_pt0ni_126{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._headerCell_pt0ni_102[data-align=right] ._headerTitle_pt0ni_126{text-align:right}._headerCell_pt0ni_102[data-align=center] ._headerTitle_pt0ni_126{justify-content:center;display:flex}._headerActions_pt0ni_149{flex-shrink:0;align-items:center;gap:0;margin-left:auto;display:flex}._headerCell_pt0ni_102[data-align=right] ._headerActions_pt0ni_149{order:-1;margin-left:0;margin-right:auto}._headerAction_pt0ni_149{display:none}._headerCell_pt0ni_102:hover ._headerAction_pt0ni_149,._headerCell_pt0ni_102:focus-within ._headerAction_pt0ni_149,._headerAction_pt0ni_149[data-pinned-visible=true]{display:flex}._headerCellSortable_pt0ni_178{cursor:pointer}._headerCellDragging_pt0ni_185{opacity:.4}._headerCellDropBefore_pt0ni_189:before,._headerCellDropAfter_pt0ni_190:before{content:"";background-color:var(--mantine-primary-color-filled);z-index:5;pointer-events:none;width:2px;position:absolute;top:0;bottom:0}._headerCellDropBefore_pt0ni_189:before{left:0}._headerCellDropAfter_pt0ni_190:before{right:0}._columnSeparator_pt0ni_210{z-index:1;justify-content:center;width:10px;height:50%;display:flex;position:absolute;top:25%;right:0;transform:translate(50%)}._columnSeparatorResizable_pt0ni_222{cursor:col-resize;touch-action:none}._columnSeparator_pt0ni_210:after{content:"";background-color:#0000;width:1px;height:100%;transition:background-color .12s,width .12s}._headerCell_pt0ni_102:hover ._columnSeparator_pt0ni_210:after,._headerCell_pt0ni_102:focus-within ._columnSeparator_pt0ni_210:after{background-color:var(--mantine-color-default-border)}._columnSeparatorResizable_pt0ni_222:hover:after,._columnSeparatorActive_pt0ni_245:after{background-color:var(--mantine-primary-color-filled);width:2px}._bodyRow_pt0ni_250{--row-bg:var(--mantine-color-body);grid-column:1/-1;grid-template-columns:subgrid;align-items:stretch;display:grid}._bodyRow_pt0ni_250:hover{--row-bg:var(--mantine-color-default-hover)}._bodyRow_pt0ni_250[data-selected=true]{--row-bg:var(--mantine-primary-color-light)}._bodyCell_pt0ni_268{padding:0 var(--dg-padding);border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--row-bg);font-size:var(--dg-font-size);align-items:center;display:flex}._cellContent_pt0ni_266{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}._bodyCell_pt0ni_268[data-align=right]{justify-content:flex-end}._bodyCell_pt0ni_268[data-align=center]{justify-content:center}._bodyCell_pt0ni_268[data-align=left] ._cellContent_pt0ni_266{flex:auto}._stickyLeft_pt0ni_305{border-right:1px solid var(--mantine-color-default-border)}._stickyRight_pt0ni_309{border-left:1px solid var(--mantine-color-default-border)}._stickyLeft_pt0ni_305:after,._stickyRight_pt0ni_309:after{content:"";pointer-events:none;width:4px;position:absolute;top:0;bottom:0}._stickyLeft_pt0ni_305:after{background:linear-gradient(90deg,var(--lightningcss-light,#00000014)var(--lightningcss-dark,#00000047),#0000);left:100%}._stickyRight_pt0ni_309:after{background:linear-gradient(270deg,var(--lightningcss-light,#00000014)var(--lightningcss-dark,#00000047),#0000);right:100%}._messageRow_pt0ni_341{justify-content:center;align-items:center;gap:var(--mantine-spacing-xs);padding:var(--mantine-spacing-xl);flex-direction:column;grid-column:1/-1;display:flex}._footer_pt0ni_351{justify-content:flex-end;align-items:center;gap:var(--mantine-spacing-lg);padding:4px var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);flex-shrink:0;min-height:48px;display:flex}._filterPanel_pt0ni_362{top:46px;left:var(--mantine-spacing-md);z-index:5;padding:var(--mantine-spacing-sm);border-radius:var(--mantine-radius-md);border:1px solid var(--mantine-color-default-border);background-color:var(--mantine-color-body);box-shadow:var(--mantine-shadow-md);position:absolute}._filterRow_pt0ni_374{align-items:flex-end;gap:var(--mantine-spacing-xs);display:flex}._menuItemActive_pt0ni_381{background-color:var(--mantine-color-default-hover);font-weight:600}._columnsPanel_pt0ni_386{flex-direction:column;width:280px;display:flex}._columnsPanelSearch_pt0ni_392{padding:var(--mantine-spacing-sm)}._columnsPanelList_pt0ni_396{gap:var(--mantine-spacing-sm);padding:0 var(--mantine-spacing-sm) var(--mantine-spacing-sm);flex-direction:column;display:flex}._columnsPanelFooter_pt0ni_403{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-sm);padding:var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);display:flex}
1
+ ._root_1jc4n_8[data-size=xs]{--dg-row-height:34px;--dg-header-height:32px;--dg-font-size:var(--mantine-font-size-xs);--dg-padding:6px}._root_1jc4n_8[data-size=sm]{--dg-row-height:42px;--dg-header-height:38px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:8px}._root_1jc4n_8[data-size=md]{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px}._root_1jc4n_8[data-size=lg]{--dg-row-height:62px;--dg-header-height:52px;--dg-font-size:var(--mantine-font-size-md);--dg-padding:14px}._root_1jc4n_8[data-size=xl]{--dg-row-height:72px;--dg-header-height:60px;--dg-font-size:var(--mantine-font-size-lg);--dg-padding:18px}._root_1jc4n_8{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px;--dg-row-selected-bg:var(--mantine-primary-color-light);text-align:left;border:1px solid var(--mantine-color-default-border);border-radius:var(--mantine-radius-md);background-color:var(--mantine-color-body);flex-direction:column;min-height:0;display:flex;overflow:hidden}._columnsPanel_1492o_1{flex-direction:column;width:280px;display:flex}._columnsPanelSearch_1492o_7{padding:var(--mantine-spacing-sm)}._columnsPanelList_1492o_11{gap:var(--mantine-spacing-sm);padding:0 var(--mantine-spacing-sm) var(--mantine-spacing-sm);flex-direction:column;display:flex}._columnsPanelFooter_1492o_18{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-sm);padding:var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);display:flex}._filterPanel_1jw69_4{top:calc(var(--dg-header-height) + 2px);left:var(--mantine-spacing-md);z-index:5;padding:var(--mantine-spacing-sm);border-radius:var(--mantine-radius-md);border:1px solid var(--mantine-color-default-border);background-color:var(--mantine-color-body);box-shadow:var(--mantine-shadow-md);position:absolute}._filterRow_1jw69_16{align-items:flex-end;gap:var(--mantine-spacing-xs);display:flex}._footer_6r35a_1{justify-content:flex-end;align-items:center;gap:var(--mantine-spacing-lg);padding:4px var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);flex-shrink:0;min-height:48px;display:flex}._tableWrapper_utldp_2{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}._scrollContainer_utldp_10{flex:1;min-height:0;position:relative;overflow:auto}._grid_utldp_18{display:grid}._headerRow_utldp_24{grid-column:1/-1;grid-template-columns:subgrid;z-index:3;display:grid;position:sticky;top:0}._bodyRow_utldp_33{--row-bg:var(--mantine-color-body);grid-column:1/-1;grid-template-columns:subgrid;align-items:stretch;display:grid}._bodyRow_utldp_33:hover{--row-bg:var(--mantine-color-default-hover)}._bodyRow_utldp_33[data-highlighted=true]{--row-bg:var(--dg-row-selected-bg)}._bodyRow_utldp_33[data-selects-on-click=true]{-webkit-user-select:none;user-select:none}._bodyRow_utldp_33:focus-visible{outline:2px solid var(--mantine-primary-color-filled);outline-offset:-2px}._bodyCell_utldp_65{padding:0 var(--dg-padding);border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--row-bg);font-size:var(--dg-font-size);align-items:center;display:flex}._cellContent_utldp_63{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}._bodyCell_utldp_65[data-align=right]{justify-content:flex-end}._bodyCell_utldp_65[data-align=center]{justify-content:center}._bodyCell_utldp_65[data-align=left] ._cellContent_utldp_63{flex:auto}._messageRow_utldp_95{justify-content:center;align-items:center;gap:var(--mantine-spacing-xs);padding:var(--mantine-spacing-xl);flex-direction:column;grid-column:1/-1;display:flex}._stickyLeft_1iqrf_11{border-right:1px solid var(--mantine-color-default-border)}._stickyRight_1iqrf_15{border-left:1px solid var(--mantine-color-default-border)}._stickyLeft_1iqrf_11:after,._stickyRight_1iqrf_15:after{content:"";pointer-events:none;width:4px;position:absolute;top:0;bottom:0}._stickyLeft_1iqrf_11:after{background:linear-gradient(90deg,var(--lightningcss-light,#00000014)var(--lightningcss-dark,#00000047),#0000);left:100%}._stickyRight_1iqrf_15:after{background:linear-gradient(270deg,var(--lightningcss-light,#00000014)var(--lightningcss-dark,#00000047),#0000);right:100%}._headerCell_1oqkm_1{padding:0 var(--dg-padding);min-width:0;min-height:var(--dg-header-height);font-weight:600;font-size:var(--dg-font-size);background-color:var(--mantine-color-body);border-bottom:1px solid var(--mantine-color-default-border);-webkit-user-select:none;user-select:none;align-items:center;gap:2px;display:flex;position:relative}._headerCell_1oqkm_1[data-align=right]{justify-content:flex-end}._headerCell_1oqkm_1[data-align=center]{justify-content:center}._headerCell_1oqkm_1[data-active=true] ._headerTitle_1oqkm_25{color:var(--mantine-primary-color-filled)}._headerTitle_1oqkm_25{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._headerCell_1oqkm_1[data-align=right] ._headerTitle_1oqkm_25{text-align:right}._headerCell_1oqkm_1[data-align=center] ._headerTitle_1oqkm_25{justify-content:center;display:flex}._headerActions_1oqkm_48{flex-shrink:0;align-items:center;gap:0;margin-left:auto;display:flex}._headerCell_1oqkm_1[data-align=right] ._headerActions_1oqkm_48{order:-1;margin-left:0;margin-right:auto}._headerAction_1oqkm_48{display:none}._headerCell_1oqkm_1:hover ._headerAction_1oqkm_48,._headerCell_1oqkm_1:focus-within ._headerAction_1oqkm_48,._headerAction_1oqkm_48[data-pinned-visible=true]{display:flex}._headerCellSortable_1oqkm_77{cursor:pointer}._headerCellDragging_1oqkm_84{opacity:.4}._headerCellDropBefore_1oqkm_88:before,._headerCellDropAfter_1oqkm_89:before{content:"";background-color:var(--mantine-primary-color-filled);z-index:5;pointer-events:none;width:2px;position:absolute;top:0;bottom:0}._headerCellDropBefore_1oqkm_88:before{left:0}._headerCellDropAfter_1oqkm_89:before{right:0}._columnSeparator_1oqkm_109{z-index:1;justify-content:center;width:10px;height:50%;display:flex;position:absolute;top:25%;right:0;transform:translate(50%)}._columnSeparatorResizable_1oqkm_121{cursor:col-resize;touch-action:none}._columnSeparator_1oqkm_109:after{content:"";background-color:#0000;width:1px;height:100%;transition:background-color .12s,width .12s}._headerCell_1oqkm_1:hover ._columnSeparator_1oqkm_109:after,._headerCell_1oqkm_1:focus-within ._columnSeparator_1oqkm_109:after{background-color:var(--mantine-color-default-border)}._columnSeparatorResizable_1oqkm_121:hover:after,._columnSeparatorActive_1oqkm_144:after{background-color:var(--mantine-primary-color-filled);width:2px}._menuItemActive_1oqkm_150{background-color:var(--mantine-color-default-hover);font-weight:600}._toolbar_4my8t_1{align-items:center;gap:var(--mantine-spacing-xs);padding:6px var(--mantine-spacing-xs);flex-shrink:0;min-height:42px;display:flex}._toolbarSpacer_4my8t_10{flex:1}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jielga/tmdatagrid",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A React data grid built on TanStack Table v9 and Mantine — always virtualized, with resizable, reorderable, sortable, filterable, hideable and pinnable columns.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,6 +39,7 @@
39
39
  "files": [
40
40
  "dist",
41
41
  "src/tmdatagrid",
42
+ "!src/tmdatagrid/**/*.test.*",
42
43
  "skills",
43
44
  "!skills/_artifacts"
44
45
  ],
@@ -56,8 +57,10 @@
56
57
  "scripts": {
57
58
  "dev": "vite",
58
59
  "build": "tsc -b && vite build",
59
- "build:lib": "vite build --config vite.lib.config.ts && tsc -p tsconfig.lib.json && rollup -c rollup.dts.config.mjs",
60
+ "build:lib": "vite build --config vite.lib.config.ts && tsc -p tsconfig.lib.json && rolldown -c rolldown.dts.config.mjs",
60
61
  "lint": "oxlint",
62
+ "test": "vitest run",
63
+ "test:watch": "vitest",
61
64
  "preview": "vite preview",
62
65
  "changeset": "changeset",
63
66
  "version-packages": "changeset version && node scripts/sync-skill-version.mjs",
@@ -91,21 +94,26 @@
91
94
  "@tanstack/react-virtual": "^3.14.4",
92
95
  "@tanstack/store": "^0.11.0",
93
96
  "@tanstack/table-core": "^9.0.0-beta.21",
97
+ "@testing-library/jest-dom": "^7.0.0",
98
+ "@testing-library/react": "^16.3.2",
99
+ "@testing-library/user-event": "^14.6.1",
94
100
  "@types/babel__core": "^7.20.5",
95
101
  "@types/node": "^24.13.2",
96
102
  "@types/react": "^19.2.17",
97
103
  "@types/react-dom": "^19.2.3",
98
- "@vitejs/plugin-react": "^6.0.2",
104
+ "@vitejs/plugin-react": "^6.0.4",
99
105
  "babel-plugin-react-compiler": "^1.0.0",
100
106
  "husky": "^9.1.7",
107
+ "jsdom": "^29.1.1",
101
108
  "oxlint": "^1.69.0",
102
109
  "react": "^19.2.7",
103
110
  "react-dom": "^19.2.7",
104
111
  "react-markdown": "^10.1.0",
105
112
  "remark-gfm": "^4.0.1",
106
- "rollup": "^4.62.3",
107
- "rollup-plugin-dts": "^6.4.1",
108
- "typescript": "~6.0.2",
109
- "vite": "^8.1.0"
113
+ "rolldown": "~1.1.5",
114
+ "rolldown-plugin-dts": "^0.27.14",
115
+ "typescript": "~7.0.2",
116
+ "vite": "^8.1.5",
117
+ "vitest": "^4.1.10"
110
118
  }
111
119
  }
@@ -11,11 +11,11 @@ description: >
11
11
  metadata:
12
12
  type: core
13
13
  library: '@jielga/tmdatagrid'
14
- library_version: '0.1.0'
14
+ library_version: '0.2.0'
15
15
  sources:
16
16
  - 'Jielga/TMDataGrid:src/docs/columns.md'
17
- - 'Jielga/TMDataGrid:src/tmdatagrid/filterOperators.ts'
18
- - 'Jielga/TMDataGrid:src/tmdatagrid/columnUtils.ts'
17
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/filterOperators.ts'
18
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/columnUtils.ts'
19
19
  ---
20
20
 
21
21
  # TMDataGrid — Columns
@@ -105,10 +105,11 @@ A column whose menu has no remaining items renders no menu button.
105
105
 
106
106
  ## Checkbox column
107
107
 
108
- Unless `enableRowSelection` is `false`, a column with the id `SELECT_COLUMN_ID`
109
- is added as the first column and pinned to the left. It is listed as "Checkbox
110
- selection" in the column manager and can be hidden like any other column. It has
111
- no column menu and cannot be sorted, filtered, resized, re-pinned or moved.
108
+ Unless `enableRowSelection` is `false` or `rowSelectionMode` is `"row"`, a column
109
+ with the id `SELECT_COLUMN_ID` is added as the first column and pinned to the
110
+ left. It is listed as "Checkbox selection" in the column manager and can be
111
+ hidden like any other column. It has no column menu and cannot be sorted,
112
+ filtered, resized, re-pinned or moved.
112
113
 
113
114
  Because it cannot be moved, it also anchors the left pinned region: no column
114
115
  can be placed in front of it.
@@ -4,20 +4,24 @@ description: >
4
4
  Enable or disable TMDataGrid interface elements through standard TanStack
5
5
  table and column options, and reuse the same checks in your own components.
6
6
  Covers the enableSorting/enableColumnFilters/enableHiding/enableColumnPinning/
7
- enableColumnResizing/enableColumnOrdering/enableRowSelection matrix,
8
- getGridCapabilities and getColumnCapabilities, why the features argument is
9
- required for reactivity under the React Compiler, column pinning, column
10
- ordering with moveColumn and moveColumnByStep, and always-on virtualization.
11
- Load when building a read-only grid, hiding grid chrome, reordering columns
12
- from code, or writing a custom toolbar button.
7
+ enableColumnResizing/enableColumnOrdering/enableRowSelection matrix, the
8
+ checkbox and row selection modes behind rowSelectionMode, the
9
+ highlightSelectedRows flag and the --dg-row-selected-bg colour, the
10
+ default-off enablePagination switch and its three modes (none, client,
11
+ manual), getGridCapabilities and getColumnCapabilities, why the features
12
+ argument is required for reactivity under the React Compiler, column pinning,
13
+ column ordering with moveColumn and moveColumnByStep, and always-on
14
+ virtualization. Load when building a read-only grid, hiding grid chrome,
15
+ enabling pagination, reordering columns from code, or writing a custom toolbar
16
+ button.
13
17
  metadata:
14
18
  type: core
15
19
  library: '@jielga/tmdatagrid'
16
- library_version: '0.1.0'
20
+ library_version: '0.2.0'
17
21
  sources:
18
22
  - 'Jielga/TMDataGrid:src/docs/features.md'
19
- - 'Jielga/TMDataGrid:src/tmdatagrid/capabilities.ts'
20
- - 'Jielga/TMDataGrid:src/tmdatagrid/columnOrdering.ts'
23
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/capabilities.ts'
24
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/columnOrdering.ts'
21
25
  ---
22
26
 
23
27
  # TMDataGrid — Features and capabilities
@@ -26,10 +30,10 @@ Almost every control is bound to the TanStack capability check for that feature,
26
30
  so setting the standard table or column option removes the corresponding
27
31
  interface. Empty menus and inactive buttons are never rendered.
28
32
 
29
- Column ordering is the one exception. TanStack's `columnOrderingFeature` ships
30
- state and APIs but no `enable` option, so the grid defines
31
- `enableColumnOrdering` and `meta.enableOrdering` itself. They behave like the
32
- options around them.
33
+ Column ordering and pagination are the two exceptions. TanStack ships state and
34
+ APIs for both but no `enable` option, so the grid defines `enableColumnOrdering`
35
+ (with `meta.enableOrdering`) and `enablePagination` itself. Ordering behaves
36
+ like the options around it; pagination is the one switch that defaults to off.
33
37
 
34
38
  ## Option reference
35
39
 
@@ -46,6 +50,9 @@ options around them.
46
50
  | `enableColumnOrdering: false` | Table | Header dragging and the move menu items |
47
51
  | `meta.enableOrdering: false` | Column | That column's header dragging and move menu items |
48
52
  | `enableRowSelection: false` | Table | The checkbox column |
53
+ | `rowSelectionMode: "row"` | Table | The checkbox column — the row itself selects instead. See Row selection |
54
+ | `highlightSelectedRows: false` | Table | The highlight background on selected rows. Follows the selection mode by default |
55
+ | `enablePagination: true` | Table | Opt-in: adds paging and the `Footer` pager. Off by default |
49
56
 
50
57
  A column whose menu has no remaining items renders no menu button. Dividers are
51
58
  never left at the end of a menu.
@@ -62,8 +69,76 @@ const grid = useTMDataGrid({
62
69
  });
63
70
  ```
64
71
 
65
- Pagination is not controlled by an option — omit `TMDataGrid.Footer` and no
66
- pagination controls are rendered.
72
+ ## Row selection
73
+
74
+ On by default, in two modes. Both write to the same `rowSelection` state, so
75
+ everything downstream — the toolbar count, `getSelectedRowModel()`, persistence
76
+ — is unaffected by the choice.
77
+
78
+ **Checkbox** — the default. A checkbox column is added as the first column, with
79
+ a select-all box in its header. Clicking a row elsewhere does not select it, and
80
+ a selected row is not highlighted: the checkbox already says so.
81
+
82
+ ```tsx
83
+ const grid = useTMDataGrid({ data, columns });
84
+ ```
85
+
86
+ **Row** — no checkbox column. Clicking a row toggles it, and the row takes the
87
+ highlight background — the only feedback a click gives. Other rows keep their
88
+ state, so a click never clears the rest of the selection. Rows are focusable in
89
+ this mode and Space or Enter toggles the focused row.
90
+
91
+ ```tsx
92
+ const grid = useTMDataGrid({ data, columns, rowSelectionMode: "row" });
93
+ ```
94
+
95
+ `enableRowSelection: false` removes both, and `rowSelectionMode` is then
96
+ ignored. `TMDataGrid.Table`'s `onRowClick` still fires in either mode — under
97
+ `"row"` it runs in addition to the selection, not instead of it.
98
+
99
+ `highlightSelectedRows` follows the mode — on for `"row"`, off for
100
+ `"checkbox"` — and can be set to override either way. The colour is the
101
+ `--dg-row-selected-bg` CSS variable (default `--mantine-primary-color-light`);
102
+ change it on the grid element without touching the flag:
103
+
104
+ ```tsx
105
+ // Checkbox column, and selected rows are highlighted too.
106
+ const grid = useTMDataGrid({ data, columns, highlightSelectedRows: true });
107
+
108
+ <TMDataGrid
109
+ {...grid}
110
+ style={{ "--dg-row-selected-bg": "var(--mantine-color-blue-0)" }}
111
+ />
112
+ ```
113
+
114
+ Rows carry `data-selected` whenever selected and `data-highlighted` only when
115
+ also highlighted, so custom styling can key off either.
116
+
117
+ ## Pagination
118
+
119
+ Off by default: the grid renders every filtered and sorted row and relies on
120
+ virtualization. Three modes:
121
+
122
+ ```tsx
123
+ // No pagination (default) — TMDataGrid.Footer renders nothing.
124
+ const grid = useTMDataGrid({ data, columns });
125
+
126
+ // Client pagination — pages locally, Footer renders its pager.
127
+ const grid = useTMDataGrid({ data, columns, enablePagination: true });
128
+
129
+ // Manual pagination — manualPagination implies enablePagination.
130
+ const grid = useTMDataGrid({
131
+ data: page.rows,
132
+ columns,
133
+ manualPagination: true,
134
+ rowCount: page.total,
135
+ state: { pagination },
136
+ onPaginationChange: setPagination,
137
+ });
138
+ ```
139
+
140
+ The built-in pager can be replaced with the Footer's `pagination` render prop
141
+ (see the `getting-started` skill) or built from scratch on the table API.
67
142
 
68
143
  ## Capability helpers
69
144
 
@@ -90,7 +165,8 @@ function ExportButton() {
90
165
  | `canHideAny` | At least one leaf column can be hidden. |
91
166
  | `canPinAny` | At least one leaf column can be pinned. |
92
167
  | `canReorderAny` | At least one leaf column can be moved. |
93
- | `canSelectRows` | `enableRowSelection` is not `false`. |
168
+ | `canSelectRows` | `enableRowSelection` is not `false`. The mode is in `features.rowSelectionMode`. |
169
+ | `canPaginate` | `enablePagination` or `manualPagination` is `true`. |
94
170
 
95
171
  `getColumnCapabilities(column, features)` returns the same information for a
96
172
  single column as `canSort`, `canFilter`, `canHide`, `canPin`, `canResize` and
@@ -207,6 +283,18 @@ table.setColumnOrder(["__select__", "department", "id", …]);
207
283
  moveColumn({ table, columnId: "department", targetId: "id", side: "before" });
208
284
  ```
209
285
 
286
+ ### Rendering the Footer without enabling pagination
287
+
288
+ ```tsx
289
+ // Wrong — pagination defaults to off, so the Footer renders nothing.
290
+ const grid = useTMDataGrid({ data, columns });
291
+ <TMDataGrid.Footer />
292
+
293
+ // Right — opt in (manualPagination: true also counts).
294
+ const grid = useTMDataGrid({ data, columns, enablePagination: true });
295
+ <TMDataGrid.Footer />
296
+ ```
297
+
210
298
  ### Expecting a table-level flag to override a column
211
299
 
212
300
  Table and column options compose — the table flag gates the feature, and the
@@ -10,19 +10,20 @@ description: >
10
10
  metadata:
11
11
  type: core
12
12
  library: '@jielga/tmdatagrid'
13
- library_version: '0.1.0'
13
+ library_version: '0.2.0'
14
14
  sources:
15
15
  - 'Jielga/TMDataGrid:src/docs/getting-started.md'
16
16
  - 'Jielga/TMDataGrid:src/docs/components.md'
17
- - 'Jielga/TMDataGrid:src/tmdatagrid/TMDataGrid.tsx'
18
- - 'Jielga/TMDataGrid:src/tmdatagrid/sizes.ts'
17
+ - 'Jielga/TMDataGrid:src/tmdatagrid/components/TMDataGrid.tsx'
18
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/sizes.ts'
19
19
  ---
20
20
 
21
21
  # TMDataGrid — Getting started
22
22
 
23
23
  `useTMDataGrid` creates the table, `TMDataGrid` provides it through context, and
24
24
  the parts rendered inside read what they need from that context. Only the parts
25
- you render exist: leave out `TMDataGrid.Footer` and there is no pagination.
25
+ you render exist, and only the features you enable have state: pagination is
26
+ opt-in via `enablePagination` — by default every row renders, virtualized.
26
27
 
27
28
  ## Install
28
29
 
@@ -69,6 +70,7 @@ export function Employees({ data }: { data: Employee[] }) {
69
70
  data,
70
71
  columns,
71
72
  getRowId: (row) => String(row.id),
73
+ enablePagination: true,
72
74
  });
73
75
 
74
76
  return (
@@ -101,13 +103,14 @@ Spread the hook result (`{...grid}`) rather than assigning `table`, `ui` and
101
103
  | Column menu | On hover: sort, filter, pin, move, hide, manage columns. |
102
104
  | Filter panel | Column, operator and value rows. |
103
105
  | Column manager | Search, toggle, show/hide all, reset. |
104
- | Row selection | Checkbox column pinned to the left. |
105
- | Pagination | Only when `TMDataGrid.Footer` is rendered. |
106
+ | Row selection | Checkbox column pinned to the left, or click-to-select rows with `rowSelectionMode: "row"`. |
107
+ | Pagination | Off by default: all rows render, virtualized. Opt in with `enablePagination: true`. |
106
108
  | Sizing | `size="xs"` to `size="xl"` scales rows, type and controls. |
107
109
 
108
110
  Each is bound to a capability check — disabling the standard table or column
109
- option also removes its interface. Column ordering is the one switch the grid
110
- defines itself, as `enableColumnOrdering`. See the `features` skill.
111
+ option also removes its interface. Column ordering (`enableColumnOrdering`) and
112
+ pagination (`enablePagination`) are the two switches the grid defines itself.
113
+ See the `features` skill.
111
114
 
112
115
  ## Layout
113
116
 
@@ -125,9 +128,9 @@ and presence are up to you — the root is a plain flex column.
125
128
 
126
129
  | Component | Props | Notes |
127
130
  | --- | --- | --- |
128
- | `TMDataGrid` | `table`, `ui`, `features`, `size`, `className`, `style` | Root. Provides context. |
129
- | `TMDataGrid.Table` | `onRowClick(row)` | Header, virtualized body, filter panel. |
130
- | `TMDataGrid.Footer` | `pageSizeOptions` (default `[10, 25, 50, 100]`) | Pagination controls. |
131
+ | `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`. |
132
+ | `TMDataGrid.Table` | `onRowClick(row)` | Header, virtualized body, filter panel. `onRowClick` runs in addition to selection under `rowSelectionMode: "row"`. |
133
+ | `TMDataGrid.Footer` | `pageSizeOptions` (default `[10, 25, 50, 100]`), `pagination` render prop | Pagination controls. Renders nothing unless pagination is enabled. |
131
134
  | `TMDataGrid.Toolbar` | `children` | Flex row above the grid. |
132
135
  | `TMDataGrid.Spacer` | — | Pushes later toolbar items right. |
133
136
  | `TMDataGrid.SummaryCount` | `children` | Visible rows out of total. |
@@ -146,6 +149,26 @@ Pass the row type so `onRowClick` stays typed:
146
149
  `options.rowCount`. `TMDataGrid.SummaryCount` uses `meta.totalRowCount` when
147
150
  provided, otherwise the pre-filtered row count.
148
151
 
152
+ The Footer's `pagination` render prop replaces the built-in pager with your own
153
+ UI, fed by the distilled pagination API:
154
+
155
+ ```tsx
156
+ <TMDataGrid.Footer
157
+ pagination={(api) => (
158
+ <Pagination
159
+ total={api.pageCount}
160
+ value={api.pageIndex + 1}
161
+ onChange={(page) => api.setPageIndex(page - 1)}
162
+ />
163
+ )}
164
+ />
165
+ ```
166
+
167
+ `TMDataGridPaginationApi` carries `pageIndex`, `pageSize`, `pageCount`,
168
+ `rowCount`, `canPreviousPage`, `canNextPage` and the actions `setPageIndex`,
169
+ `setPageSize`, `previousPage`, `nextPage`, `firstPage`, `lastPage`. Outside the
170
+ Footer, `getTMDataGridPaginationApi(grid.table)` returns the same object.
171
+
149
172
  ## size
150
173
 
151
174
  Standard Mantine scale. Controls row height, header height, font size and cell
@@ -201,9 +224,9 @@ is no error.
201
224
  `<TMDataGrid table={grid.table}>` omits `ui` and `features`. Panels stop opening
202
225
  and feature toggles stop being reactive. Spread instead: `<TMDataGrid {...grid}>`.
203
226
 
204
- ### Expecting Footer to control pagination
227
+ ### Expecting Footer to enable pagination
205
228
 
206
- Pagination is not an option. Omitting `TMDataGrid.Footer` removes the controls
207
- but the table still paginates at `pageSize: 25` — rows beyond the first page
208
- simply become unreachable. Set `initialState.pagination.pageSize` if you want
209
- every row on one page.
229
+ Rendering `TMDataGrid.Footer` does not switch pagination on — the option does.
230
+ With pagination off (the default) the Footer renders nothing and every row is
231
+ rendered, virtualized. Set `enablePagination: true` (or `manualPagination:
232
+ true` for server paging) to page the data and show the pager.
@@ -4,7 +4,8 @@ description: >
4
4
  useTMDataGrid options, return value and state persistence. Covers passthrough
5
5
  of TanStack TableOptions, the default initialState (pagination, columnPinning,
6
6
  globalFilterFn), the meta object (loading, noResultsLabel, rowHeight,
7
- totalRowCount), the grid's own persist and enableColumnOrdering options, the
7
+ totalRowCount), the grid's own persist, enableColumnOrdering,
8
+ enablePagination, rowSelectionMode and highlightSelectedRows options, the
8
9
  persist option with dataKey/settingsKey slice selection and storageMode, the
9
10
  returned table/ui/features triple, ui panel and column drag actions, and
10
11
  reading grid state with useSelector. Load when configuring the hook,
@@ -12,11 +13,11 @@ description: >
12
13
  metadata:
13
14
  type: core
14
15
  library: '@jielga/tmdatagrid'
15
- library_version: '0.1.0'
16
+ library_version: '0.2.0'
16
17
  sources:
17
18
  - 'Jielga/TMDataGrid:src/docs/use-tm-data-grid.md'
18
19
  - 'Jielga/TMDataGrid:src/tmdatagrid/useTMDataGrid.tsx'
19
- - 'Jielga/TMDataGrid:src/tmdatagrid/persistence.ts'
20
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/persistence.ts'
20
21
  ---
21
22
 
22
23
  # TMDataGrid — useTMDataGrid
@@ -37,21 +38,25 @@ All TanStack `TableOptions` are supported and passed through unchanged, includin
37
38
  flags and `rowCount`. The `features` option is supplied internally and cannot be
38
39
  overridden.
39
40
 
40
- `persist` and `enableColumnOrdering` are the grid's own options and are consumed
41
- by the hook rather than forwarded to TanStack.
41
+ `persist`, `enableColumnOrdering`, `enablePagination`, `rowSelectionMode` and
42
+ `highlightSelectedRows` are the grid's own options and are consumed by the hook
43
+ rather than forwarded to TanStack.
42
44
 
43
45
  | Option | Type | Default | Description |
44
46
  | --- | --- | --- | --- |
45
47
  | `data` | `TData[]` | – | Row data. Keep the reference stable with `useMemo`. |
46
48
  | `columns` | `ColumnDef[]` | – | Created with `createTMDataGridColumnHelper`. |
47
49
  | `getRowId` | `(row, index) => string` | Row index | Used by row selection and virtualization. |
48
- | `enableRowSelection` | `boolean \| (row) => boolean` | `true` | `false` removes the checkbox column. |
50
+ | `enableRowSelection` | `boolean \| (row) => boolean` | `true` | `false` removes row selection and its checkbox column. |
51
+ | `rowSelectionMode` | `"checkbox" \| "row"` | `"checkbox"` | `"row"` drops the checkbox column and selects on row click. Defined by the grid. |
52
+ | `highlightSelectedRows` | `boolean` | Follows the mode | Highlight background on selected rows: off for `"checkbox"`, on for `"row"`. Colour is the `--dg-row-selected-bg` CSS variable. Defined by the grid. |
49
53
  | `enableSorting` | `boolean` | `true` | Enables sorting for the table. |
50
54
  | `enableColumnFilters` | `boolean` | `true` | Enables filtering for the table. |
51
55
  | `enableHiding` | `boolean` | `true` | Enables column visibility for the table. |
52
56
  | `enableColumnPinning` | `boolean` | `true` | Enables pinning for the table. |
53
57
  | `enableColumnResizing` | `boolean` | `true` | Enables resizing for the table. |
54
58
  | `enableColumnOrdering` | `boolean` | `true` | Enables header dragging and the move menu items. Defined by the grid. |
59
+ | `enablePagination` | `boolean` | `false` | Enables client-side paging and the `Footer` pager. Implied by `manualPagination`. Defined by the grid. |
55
60
  | `columnResizeMode` | `"onChange" \| "onEnd"` | `"onChange"` | Resize update strategy. |
56
61
  | `initialState` | `Partial<TableState>` | See below | Merged over the grid defaults. |
57
62
  | `meta` | `TMDataGridTableMeta` | `{}` | Grid configuration, see below. |
@@ -61,7 +66,7 @@ by the hook rather than forwarded to TanStack.
61
66
 
62
67
  | Slice | Default |
63
68
  | --- | --- |
64
- | `pagination` | `{ pageIndex: 0, pageSize: 25 }` |
69
+ | `pagination` | `{ pageIndex: 0, pageSize: 25 }` — inert until pagination is enabled |
65
70
  | `columnPinning.left` | The checkbox column, followed by any columns you provide |
66
71
  | `globalFilterFn` | `"includesString"` |
67
72
 
@@ -10,7 +10,7 @@ description: >
10
10
  metadata:
11
11
  type: core
12
12
  library: '@jielga/tmdatagrid'
13
- library_version: '0.1.0'
13
+ library_version: '0.2.0'
14
14
  sources:
15
15
  - 'Jielga/TMDataGrid:src/docs/server-side.md'
16
16
  - 'Jielga/TMDataGrid:src/tmdatagrid/useTMDataGrid.tsx'
@@ -21,7 +21,10 @@ sources:
21
21
  The grid reads rows through `getPaginatedRowModel()` and totals through
22
22
  `getRowCount()` and `getPageCount()`, all of which respect TanStack's manual
23
23
  modes. A server-driven grid therefore needs only the standard `manual*`
24
- configuration — no grid-specific options.
24
+ configuration — no grid-specific options. `manualPagination: true` also
25
+ switches the grid's pagination flag on, so `TMDataGrid.Footer` renders its
26
+ pager without `enablePagination`. Declare `pageCount: -1` when the total is
27
+ unknown; the next button then stays enabled.
25
28
 
26
29
  ## Setup
27
30
 
@@ -1,5 +1,5 @@
1
1
  import { createContext, useContext } from "react";
2
- import type { TMDataGridSize } from "./sizes";
2
+ import type { TMDataGridSize } from "./core/sizes";
3
3
  import type { TMDataGridApi } from "./useTMDataGrid";
4
4
 
5
5
  /**
@@ -0,0 +1,63 @@
1
+ /* The grid root: the size scale every other module reads, and the frame.
2
+ Each component owns its own module; these variables cascade into all of
3
+ them, and the pinned-column boundary shared by header and body cells lives
4
+ in sticky.module.css. */
5
+
6
+ /* Size scale. Row heights mirror SIZE_ROW_HEIGHT in core/sizes.ts — the
7
+ virtualizer needs the number in JS, so the two have to agree. */
8
+ .root[data-size="xs"] {
9
+ --dg-row-height: 34px;
10
+ --dg-header-height: 32px;
11
+ --dg-font-size: var(--mantine-font-size-xs);
12
+ --dg-padding: 6px;
13
+ }
14
+
15
+ .root[data-size="sm"] {
16
+ --dg-row-height: 42px;
17
+ --dg-header-height: 38px;
18
+ --dg-font-size: var(--mantine-font-size-sm);
19
+ --dg-padding: 8px;
20
+ }
21
+
22
+ .root[data-size="md"] {
23
+ --dg-row-height: 52px;
24
+ --dg-header-height: 44px;
25
+ --dg-font-size: var(--mantine-font-size-sm);
26
+ --dg-padding: 10px;
27
+ }
28
+
29
+ .root[data-size="lg"] {
30
+ --dg-row-height: 62px;
31
+ --dg-header-height: 52px;
32
+ --dg-font-size: var(--mantine-font-size-md);
33
+ --dg-padding: 14px;
34
+ }
35
+
36
+ .root[data-size="xl"] {
37
+ --dg-row-height: 72px;
38
+ --dg-header-height: 60px;
39
+ --dg-font-size: var(--mantine-font-size-lg);
40
+ --dg-padding: 18px;
41
+ }
42
+
43
+ .root {
44
+ /* Fallbacks, so the parts still work if rendered outside a sized root. */
45
+ --dg-row-height: 52px;
46
+ --dg-header-height: 44px;
47
+ --dg-font-size: var(--mantine-font-size-sm);
48
+ --dg-padding: 10px;
49
+ /* Background of a highlighted (selected) row. Override it on the grid:
50
+ <TMDataGrid style={{ "--dg-row-selected-bg": "var(--mantine-color-blue-0)" }} /> */
51
+ --dg-row-selected-bg: var(--mantine-primary-color-light);
52
+
53
+ display: flex;
54
+ flex-direction: column;
55
+ min-height: 0;
56
+ overflow: hidden;
57
+ /* Header text is a stretched flex item, so an inherited `text-align: center`
58
+ from the host page would centre headers away from their cell content. */
59
+ text-align: left;
60
+ border: 1px solid var(--mantine-color-default-border);
61
+ border-radius: var(--mantine-radius-md);
62
+ background-color: var(--mantine-color-body);
63
+ }
@@ -2,7 +2,7 @@ import type { RowData } from "@tanstack/react-table";
2
2
  import { type CSSProperties, type ReactNode, useMemo } from "react";
3
3
  import classes from "./TMDataGrid.module.css";
4
4
  import { TMDataGridColumnsPanel } from "./TMDataGridColumnsPanel";
5
- import { TMDataGridContextProvider } from "./TMDataGridContext";
5
+ import { TMDataGridContextProvider } from "../TMDataGridContext";
6
6
  import { TMDataGridFilterPanel } from "./TMDataGridFilterPanel";
7
7
  import { TMDataGridFooter } from "./TMDataGridFooter";
8
8
  import { TMDataGridTable } from "./TMDataGridTable";
@@ -18,8 +18,8 @@ import {
18
18
  SIZE_CONTROL_SIZE,
19
19
  SIZE_ROW_HEIGHT,
20
20
  type TMDataGridSize,
21
- } from "./sizes";
22
- import type { TMDataGridApi } from "./useTMDataGrid";
21
+ } from "../core/sizes";
22
+ import type { TMDataGridApi } from "../useTMDataGrid";
23
23
 
24
24
  export type TMDataGridProps<TData extends RowData> = TMDataGridApi<TData> & {
25
25
  children: ReactNode;
@@ -29,7 +29,12 @@ export type TMDataGridProps<TData extends RowData> = TMDataGridApi<TData> & {
29
29
  */
30
30
  size?: TMDataGridSize;
31
31
  className?: string;
32
- style?: CSSProperties;
32
+ /**
33
+ * Inline styles. Widened to accept CSS variables, which is how the grid's
34
+ * colours are themed — `--dg-row-selected-bg` for the selected row
35
+ * background. Plain `CSSProperties` rejects `--*` keys.
36
+ */
37
+ style?: CSSProperties & Record<`--${string}`, string | number>;
33
38
  };
34
39
 
35
40
  /**
@@ -0,0 +1,25 @@
1
+ .columnsPanel {
2
+ width: 280px;
3
+ display: flex;
4
+ flex-direction: column;
5
+ }
6
+
7
+ .columnsPanelSearch {
8
+ padding: var(--mantine-spacing-sm);
9
+ }
10
+
11
+ .columnsPanelList {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: var(--mantine-spacing-sm);
15
+ padding: 0 var(--mantine-spacing-sm) var(--mantine-spacing-sm);
16
+ }
17
+
18
+ .columnsPanelFooter {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+ gap: var(--mantine-spacing-sm);
23
+ padding: var(--mantine-spacing-sm);
24
+ border-top: 1px solid var(--mantine-color-default-border);
25
+ }
@@ -1,9 +1,9 @@
1
1
  import { Button, Checkbox, ScrollArea, Text, TextInput } from "@mantine/core";
2
2
  import { useSelector } from "@tanstack/react-store";
3
3
  import { useState } from "react";
4
- import classes from "./TMDataGrid.module.css";
5
- import { useTMDataGridContext } from "./TMDataGridContext";
6
- import { getColumnLabel } from "./columnUtils";
4
+ import classes from "./TMDataGridColumnsPanel.module.css";
5
+ import { useTMDataGridContext } from "../TMDataGridContext";
6
+ import { getColumnLabel } from "../core/columnUtils";
7
7
  import { SearchIcon } from "./icons";
8
8
 
9
9
  /**