@jielga/tmdatagrid 0.1.0 → 0.3.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 (47) hide show
  1. package/README.md +35 -2
  2. package/dist/index.d.ts +792 -327
  3. package/dist/index.js +1581 -892
  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 +78 -20
  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 +73 -0
  14. package/src/tmdatagrid/{TMDataGrid.tsx → components/TMDataGrid.tsx} +15 -4
  15. package/src/tmdatagrid/components/TMDataGridColumnsPanel.module.css +25 -0
  16. package/src/tmdatagrid/{TMDataGridColumnsPanel.tsx → components/TMDataGridColumnsPanel.tsx} +10 -4
  17. package/src/tmdatagrid/components/TMDataGridFilterPanel.module.css +35 -0
  18. package/src/tmdatagrid/{TMDataGridFilterPanel.tsx → components/TMDataGridFilterPanel.tsx} +91 -14
  19. package/src/tmdatagrid/components/TMDataGridFilterPills.module.css +35 -0
  20. package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +135 -0
  21. package/src/tmdatagrid/components/TMDataGridFooter.module.css +18 -0
  22. package/src/tmdatagrid/components/TMDataGridFooter.tsx +171 -0
  23. package/src/tmdatagrid/components/TMDataGridGroupColumn.module.css +48 -0
  24. package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +147 -0
  25. package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +159 -0
  26. package/src/tmdatagrid/{TMDataGridHeaderCell.tsx → components/TMDataGridHeaderCell.tsx} +99 -14
  27. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +177 -0
  28. package/src/tmdatagrid/components/TMDataGridTable.module.css +137 -0
  29. package/src/tmdatagrid/components/TMDataGridTable.tsx +720 -0
  30. package/src/tmdatagrid/components/TMDataGridToolbar.module.css +12 -0
  31. package/src/tmdatagrid/{TMDataGridToolbar.tsx → components/TMDataGridToolbar.tsx} +8 -5
  32. package/src/tmdatagrid/{icons.ts → components/icons.ts} +5 -0
  33. package/src/tmdatagrid/components/sticky.module.css +45 -0
  34. package/src/tmdatagrid/core/capabilities.ts +215 -0
  35. package/src/tmdatagrid/{columnOrdering.ts → core/columnOrdering.ts} +2 -2
  36. package/src/tmdatagrid/{columnUtils.ts → core/columnUtils.ts} +1 -1
  37. package/src/tmdatagrid/{filterOperators.ts → core/filterOperators.ts} +25 -0
  38. package/src/tmdatagrid/core/grouping.ts +21 -0
  39. package/src/tmdatagrid/{persistence.ts → core/persistence.ts} +92 -2
  40. package/src/tmdatagrid/core/rowSelection.ts +202 -0
  41. package/src/tmdatagrid/index.ts +39 -9
  42. package/src/tmdatagrid/useTMDataGrid.tsx +318 -66
  43. package/src/tmdatagrid/TMDataGrid.module.css +0 -410
  44. package/src/tmdatagrid/TMDataGridFooter.tsx +0 -74
  45. package/src/tmdatagrid/TMDataGridTable.tsx +0 -297
  46. package/src/tmdatagrid/capabilities.ts +0 -117
  47. /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_13dg1_8[data-size=xs]{--dg-row-height:34px;--dg-header-height:32px;--dg-font-size:var(--mantine-font-size-xs);--dg-padding:6px}._root_13dg1_8[data-size=sm]{--dg-row-height:42px;--dg-header-height:38px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:8px}._root_13dg1_8[data-size=md]{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px}._root_13dg1_8[data-size=lg]{--dg-row-height:62px;--dg-header-height:52px;--dg-font-size:var(--mantine-font-size-md);--dg-padding:14px}._root_13dg1_8[data-size=xl]{--dg-row-height:72px;--dg-header-height:60px;--dg-font-size:var(--mantine-font-size-lg);--dg-padding:18px}._root_13dg1_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);--dg-row-highlight-bg:var(--mantine-primary-color-light-hover);--dg-row-group-bg:var(--mantine-color-body);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}._groupToggle_h06xv_4{width:100%;min-width:0;font-size:var(--dg-font-size);color:inherit;align-items:center;gap:6px;display:flex}._chevron_h06xv_14{color:var(--mantine-color-dimmed);flex:none;align-items:center;transition:transform .12s;display:flex}._chevron_h06xv_14[data-expanded=true]{transform:rotate(90deg)}@media (prefers-reduced-motion:reduce){._chevron_h06xv_14{transition:none}}._groupLabel_h06xv_34{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}._groupCount_h06xv_44{color:var(--mantine-color-dimmed);font-variant-numeric:tabular-nums;flex:none}._filterPanel_izakx_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_izakx_16{align-items:flex-end;gap:var(--mantine-spacing-xs);display:flex}._filterPanelHeader_izakx_22{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-md);padding-bottom:var(--mantine-spacing-xs);display:flex}._filterPanelFooter_izakx_30{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-md);display:flex}._filterPills_1yybb_3{align-items:center;gap:var(--mantine-spacing-xs);flex-wrap:wrap;display:flex}._filterPills_1yybb_3 ._pill_1yybb_15{background-color:var(--lightningcss-light,var(--mantine-color-gray-1))var(--lightningcss-dark,var(--mantine-color-dark-5));color:var(--lightningcss-light,var(--mantine-color-black))var(--lightningcss-dark,var(--mantine-color-dark-0));border:1px solid var(--lightningcss-light,var(--mantine-color-gray-3))var(--lightningcss-dark,var(--mantine-color-dark-3))}._pillLabel_1yybb_27{font:inherit;color:inherit;cursor:pointer}._pillLabel_1yybb_27:hover{text-decoration:underline}._footer_149ca_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}._footer_149ca_1[data-paging-suspended=true]{opacity:.55}._tableWrapper_chabz_2{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}._scrollContainer_chabz_10{flex:1;min-height:0;position:relative;overflow:auto}._grid_chabz_18{display:grid}._headerRow_chabz_24{grid-column:1/-1;grid-template-columns:subgrid;z-index:3;display:grid;position:sticky;top:0}._bodyRow_chabz_33{--row-bg:var(--mantine-color-body);grid-column:1/-1;grid-template-columns:subgrid;align-items:stretch;display:grid}._bodyRow_chabz_33:hover{--row-bg:var(--mantine-color-default-hover)}._bodyRow_chabz_33[data-grouped=true]{--row-bg:var(--dg-row-group-bg)}._bodyRow_chabz_33[data-context-menu=true]{--row-bg:var(--mantine-color-default-hover)}._bodyRow_chabz_33[data-selected-bg=true]{--row-bg:var(--dg-row-selected-bg)}._bodyRow_chabz_33[data-highlighted=true]{--row-bg:var(--dg-row-highlight-bg)}._bodyRow_chabz_33[data-selects-on-click=true]{-webkit-user-select:none;user-select:none}._bodyRow_chabz_33:focus-visible{outline:2px solid var(--mantine-primary-color-filled);outline-offset:-2px}._bodyCell_chabz_91{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}._bodyCell_chabz_91[data-select-column=true]{padding:0}._cellContent_chabz_89{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}._bodyCell_chabz_91[data-align=right]{justify-content:flex-end}._bodyCell_chabz_91[data-align=center]{justify-content:center}._bodyCell_chabz_91[data-align=left] ._cellContent_chabz_89{flex:auto}._messageRow_chabz_129{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_49xbo_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_49xbo_1[data-align=right]{justify-content:flex-end}._headerCell_49xbo_1[data-align=center]{justify-content:center}._headerCell_49xbo_1[data-select-column=true]{padding:0}._headerCell_49xbo_1[data-active=true] ._headerTitle_49xbo_31{color:var(--mantine-primary-color-filled)}._headerTitle_49xbo_31{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._headerCell_49xbo_1[data-align=right] ._headerTitle_49xbo_31{text-align:right}._headerCell_49xbo_1[data-align=center] ._headerTitle_49xbo_31{justify-content:center;display:flex}._headerActions_49xbo_54{flex-shrink:0;align-items:center;gap:0;margin-left:auto;display:flex}._headerCell_49xbo_1[data-align=right] ._headerActions_49xbo_54{order:-1;margin-left:0;margin-right:auto}._headerAction_49xbo_54{display:none}._headerCell_49xbo_1:hover ._headerAction_49xbo_54,._headerCell_49xbo_1:focus-within ._headerAction_49xbo_54,._headerAction_49xbo_54[data-pinned-visible=true]{display:flex}._headerCellSortable_49xbo_83{cursor:pointer}._headerCellDragging_49xbo_90{opacity:.4}._headerCellDropBefore_49xbo_94:before,._headerCellDropAfter_49xbo_95:before{content:"";background-color:var(--mantine-primary-color-filled);z-index:5;pointer-events:none;width:2px;position:absolute;top:0;bottom:0}._headerCellDropBefore_49xbo_94:before{left:0}._headerCellDropAfter_49xbo_95:before{right:0}._columnSeparator_49xbo_115{z-index:1;justify-content:center;width:10px;height:50%;display:flex;position:absolute;top:25%;right:0;transform:translate(50%)}._columnSeparatorResizable_49xbo_127{cursor:col-resize;touch-action:none}._columnSeparator_49xbo_115:after{content:"";background-color:#0000;width:1px;height:100%;transition:background-color .12s,width .12s}._headerCell_49xbo_1:hover ._columnSeparator_49xbo_115:after,._headerCell_49xbo_1:focus-within ._columnSeparator_49xbo_115:after{background-color:var(--mantine-color-default-border)}._columnSeparatorResizable_49xbo_127:hover:after,._columnSeparatorActive_49xbo_150:after{background-color:var(--mantine-primary-color-filled);width:2px}._menuItemActive_49xbo_156{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.3.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.3.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.3.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
@@ -4,25 +4,26 @@ 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, FilterButton,
7
- ColumnsButton, FilterPanel, ColumnsPanel), the size scale and the
7
+ ColumnsButton, FilterPanel, FilterPills, ColumnsPanel), the size scale and the
8
8
  bounded-height layout requirement. Load when adding a grid, choosing which
9
9
  parts to render, or when rows do not appear.
10
10
  metadata:
11
11
  type: core
12
12
  library: '@jielga/tmdatagrid'
13
- library_version: '0.1.0'
13
+ library_version: '0.3.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
 
@@ -120,21 +123,24 @@ takes a fixed pixel width once resized or pinned.
120
123
 
121
124
  ## Components
122
125
 
123
- All read the grid from context and must be rendered inside `TMDataGrid`. Order
124
- and presence are up to you — the root is a plain flex column.
126
+ All read the grid from context and must be rendered inside `TMDataGrid`, except
127
+ `TMDataGrid.FilterPills`, which takes the grid as an `api` prop and can live
128
+ anywhere on the page. Order and presence are up to you — the root is a plain
129
+ flex column.
125
130
 
126
131
  | Component | Props | Notes |
127
132
  | --- | --- | --- |
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. |
133
+ | `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`. |
134
+ | `TMDataGrid.Table` | `onRowClick(row)`, `rowContextMenu` render prop, `rowContextMenuProps` | Header, virtualized body, filter panel. `onRowClick` runs in addition to selection under `rowSelectionMode: "row"`. |
135
+ | `TMDataGrid.Footer` | `pageSizeOptions` (default `[10, 25, 50, 100]`), `pagination` render prop | Pagination controls. Renders nothing unless pagination is enabled. |
131
136
  | `TMDataGrid.Toolbar` | `children` | Flex row above the grid. |
132
137
  | `TMDataGrid.Spacer` | — | Pushes later toolbar items right. |
133
138
  | `TMDataGrid.SummaryCount` | `children` | Visible rows out of total. |
134
139
  | `TMDataGrid.FilterButton` | — | Toggles filter panel. Renders nothing if no column is filterable. |
135
140
  | `TMDataGrid.ColumnsButton` | — | Opens column manager. Renders nothing if no column is hideable. |
136
- | `TMDataGrid.FilterPanel` | — | Rendered by `.Table`; exported for custom layouts. |
141
+ | `TMDataGrid.FilterPanel` | — | Rendered by `.Table`; exported for custom layouts. Header close button, Escape, click-away, "Add filter" and "Clear all". |
137
142
  | `TMDataGrid.ColumnsPanel` | — | Rendered by `.ColumnsButton`; exported for custom layouts. |
143
+ | `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`. |
138
144
 
139
145
  Pass the row type so `onRowClick` stays typed:
140
146
 
@@ -142,10 +148,61 @@ Pass the row type so `onRowClick` stays typed:
142
148
  <TMDataGrid.Table<Employee> onRowClick={(row) => open(row.original.id)} />
143
149
  ```
144
150
 
151
+ `rowContextMenu` fills the dropdown of a Mantine `Menu` the grid opens at the
152
+ pointer on a right-click (or a long press). The grid owns the `Menu` — opening,
153
+ positioning, and closing on Escape, outside click, body scroll or an item pick —
154
+ so the render prop only says what goes in it:
155
+
156
+ ```tsx
157
+ <TMDataGrid.Table<Employee>
158
+ rowContextMenu={({ table, row, cell, close }) => (
159
+ <>
160
+ <Menu.Label>{row.original.firstName}</Menu.Label>
161
+ <Menu.Item onClick={() => open(row.original.id)}>Open</Menu.Item>
162
+ <Menu.Item
163
+ onClick={() =>
164
+ navigator.clipboard.writeText(String(cell?.getValue() ?? ""))
165
+ }
166
+ >
167
+ Copy cell value
168
+ </Menu.Item>
169
+ </>
170
+ )}
171
+ />
172
+ ```
173
+
174
+ `cell` is the one that was right-clicked, `table` is there for actions that read
175
+ the selection, and `close` is for dropdown content that is not a `Menu.Item`
176
+ (those close themselves). Return `null` to leave a row without a menu. It is
177
+ called during render, and only for the open row, so it must stay pure — put the
178
+ work in the item handlers. Right-clicking does not change the selection or the
179
+ highlight; the row carries `data-context-menu` while its menu is open. Pass
180
+ `rowContextMenuProps` for `width`, `shadow`, `position` and the rest.
181
+
145
182
  `TMDataGrid.Footer` reads totals from `table.getRowCount()`, which prefers
146
183
  `options.rowCount`. `TMDataGrid.SummaryCount` uses `meta.totalRowCount` when
147
184
  provided, otherwise the pre-filtered row count.
148
185
 
186
+ The Footer's `pagination` render prop replaces the built-in pager with your own
187
+ UI, fed by the distilled pagination API:
188
+
189
+ ```tsx
190
+ <TMDataGrid.Footer
191
+ pagination={(api) => (
192
+ <Pagination
193
+ total={api.pageCount}
194
+ value={api.pageIndex + 1}
195
+ onChange={(page) => api.setPageIndex(page - 1)}
196
+ />
197
+ )}
198
+ />
199
+ ```
200
+
201
+ `TMDataGridPaginationApi` carries `pageIndex`, `pageSize`, `pageCount`,
202
+ `rowCount`, `canPreviousPage`, `canNextPage` and the actions `setPageIndex`,
203
+ `setPageSize`, `previousPage`, `nextPage`, `firstPage`, `lastPage`. Outside the
204
+ Footer, `getTMDataGridPaginationApi(grid.table)` returns the same object.
205
+
149
206
  ## size
150
207
 
151
208
  Standard Mantine scale. Controls row height, header height, font size and cell
@@ -171,6 +228,7 @@ mirrors them. Set `meta.rowHeight` for a height outside the scale.
171
228
  | `openColumnFilter(api, columnId)` | Adds an empty filter for a column and opens the panel. |
172
229
  | `getColumnLabel(column)` | `meta.label`, a string header, or the column id. |
173
230
  | `getColumnType(column)` | `meta.type`, defaulting to `"string"`. |
231
+ | `formatFilterLabel({ label, type, filter })` | The one-line filter description used on the pills. |
174
232
  | `moveColumn({ table, columnId, targetId, side })` | Moves a column next to another. See the `features` skill. |
175
233
  | `moveColumnByStep({ table, columnId, direction })` | Moves a column one position within its region. |
176
234
  | `SELECT_COLUMN_ID` | Id of the generated checkbox column. |
@@ -201,9 +259,9 @@ is no error.
201
259
  `<TMDataGrid table={grid.table}>` omits `ui` and `features`. Panels stop opening
202
260
  and feature toggles stop being reactive. Spread instead: `<TMDataGrid {...grid}>`.
203
261
 
204
- ### Expecting Footer to control pagination
262
+ ### Expecting Footer to enable pagination
205
263
 
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.
264
+ Rendering `TMDataGrid.Footer` does not switch pagination on — the option does.
265
+ With pagination off (the default) the Footer renders nothing and every row is
266
+ rendered, virtualized. Set `enablePagination: true` (or `manualPagination:
267
+ 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.3.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.3.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
  /**