@opencorestack/opengridx 0.1.9 → 1.0.1

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 (64) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +162 -19
  3. package/dist/index.d.ts +60 -41
  4. package/dist/opengridx.es.js +5045 -4549
  5. package/dist/opengridx.es.js.map +1 -1
  6. package/dist/opengridx.umd.js +11 -11
  7. package/dist/opengridx.umd.js.map +1 -1
  8. package/docs/API_REFERENCE.md +17 -7
  9. package/docs/README.md +14 -0
  10. package/docs/components/aggregation-footer.md +48 -0
  11. package/docs/components/datagrid.md +8 -3
  12. package/docs/components/empty-state.md +50 -0
  13. package/docs/components/error-overlay.md +40 -0
  14. package/docs/features/editing-reordering.md +11 -7
  15. package/docs/features/filtering.md +10 -8
  16. package/docs/features/selection.md +2 -1
  17. package/docs/features/sorting-pagination.md +3 -1
  18. package/docs/features/state-persistence.md +1 -2
  19. package/docs/roadmap.md +20 -1
  20. package/lib/components/Cell/Cell.tsx +9 -10
  21. package/lib/components/Cell/GridEditInputCell.tsx +4 -4
  22. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +3 -2
  23. package/lib/components/DataGrid/DataGrid.regression.test.tsx +132 -0
  24. package/lib/components/DataGrid/DataGrid.tsx +336 -1018
  25. package/lib/components/DataGrid/GridAggregationFooter.tsx +68 -0
  26. package/lib/components/DataGrid/GridEmptyState.tsx +16 -0
  27. package/lib/components/DataGrid/GridErrorOverlay.tsx +33 -0
  28. package/lib/components/DataGrid/GridListView.tsx +116 -0
  29. package/lib/components/DataGrid/GridPinnedRows.tsx +98 -0
  30. package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +124 -0
  31. package/lib/components/DataGrid/GridVirtualRows.tsx +202 -0
  32. package/lib/components/FilterPanel/FilterPanel.tsx +18 -10
  33. package/lib/components/Header/ColumnMenu.tsx +2 -2
  34. package/lib/components/Header/Header.tsx +4 -4
  35. package/lib/components/ListView/ListViewRow.tsx +2 -2
  36. package/lib/components/Row/Row.tsx +10 -10
  37. package/lib/components/SkeletonRow/SkeletonRow.tsx +9 -2
  38. package/lib/components/Toolbar/GridToolbar.tsx +6 -0
  39. package/lib/hooks/core/useDataGrid.regression.test.ts +66 -0
  40. package/lib/hooks/core/useDataGrid.ts +14 -34
  41. package/lib/hooks/core/useGridColumns.tsx +228 -0
  42. package/lib/hooks/core/useGridControlledState.ts +192 -0
  43. package/lib/hooks/core/useGridRowPipeline.ts +109 -0
  44. package/lib/hooks/core/useGridScrollSync.ts +52 -0
  45. package/lib/hooks/core/useGridStateSnapshot.ts +63 -0
  46. package/lib/hooks/core/useGridVirtualization.ts +186 -0
  47. package/lib/hooks/core/useGridVisibleRows.ts +66 -0
  48. package/lib/hooks/core/useLayout.ts +0 -6
  49. package/lib/hooks/features/useAggregation.ts +7 -7
  50. package/lib/hooks/features/useGridDataSource.ts +1 -1
  51. package/lib/hooks/features/useGridEditing.ts +31 -32
  52. package/lib/hooks/features/usePivot.test.ts +202 -0
  53. package/lib/hooks/features/usePivot.ts +0 -0
  54. package/lib/hooks/useColumnReorder.ts +1 -1
  55. package/lib/hooks/useRowGrouping.ts +14 -14
  56. package/lib/hooks/useTreeData.ts +1 -1
  57. package/lib/state/types.ts +1 -1
  58. package/lib/state/useGridStateStorage.ts +1 -1
  59. package/lib/types/index.ts +48 -32
  60. package/lib/utils/export/exportToExcelAdvanced.ts +14 -14
  61. package/lib/utils/export/index.ts +22 -17
  62. package/lib/utils/filtering/index.ts +20 -20
  63. package/lib/utils/sorting/index.ts +1 -1
  64. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,57 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## [1.0.1] — July 30, 2026 📚
9
+
10
+ ### Fixed
11
+ - **Bundled documentation accuracy**: All doc files shipped inside the npm package (`docs/`) have been corrected to match the actual v1.0.0 API. Key fixes: removed non-existent `pageSize` standalone prop (correct API is `paginationModel` + `pageSizeOptions`), fixed `height` type to `number | string`, corrected `onColumnOrderChange` params shape, removed non-existent `isRowSelectable` and `reorderable` props, fixed `GridFilterModel.items` type, added missing `GridApi` methods (`getFilterModel`, `getAllColumns`, `setPageSize`, `getAggregationResult`, `getAggregationModel`, `copySelectedRows`), and corrected `GridInitialState` persisted state fields. AI agents (Cursor, Copilot, Windsurf) reading bundled docs will now generate accurate code.
12
+ - **README API reference**: Same prop and type corrections applied — complete `apiRef` method list, new prop tables for Events, Columns, Pinning, Inline Editing, Row Reordering, and updated comparison table.
13
+
14
+ ---
15
+
16
+ ## [1.0.0] — July 30, 2026 🚀
17
+
18
+ First stable public release. All 32 demo pages ship with a live source viewer. npm publish workflow is live.
19
+
20
+ ### Added
21
+ - **npm publish workflow**: GitHub Actions workflow (`.github/workflows/npm-publish.yml`) triggers on any `v*.*.*` tag push — runs lint, build, then `npm publish`. The package is now publicly available as `@opencorestack/opengridx` on the npm registry.
22
+ - **Source viewer on all 32 demos**: Every demo page now uses `DocsLayout` with a collapsible "View Source" tab showing the full component source code. Previously only 7 of 32 demos had this; the remaining 25 have been migrated.
23
+
24
+ ### Changed
25
+ - **Version**: `0.1.x` pre-release series → `1.0.0` stable. The public API (`DataGridProps`, `GridColDef`, `GridApi`, all hooks and types) is now considered stable.
26
+ - **Demo consistency**: All 32 demos share the same `DocsLayout` shell — consistent title, description, live preview, and source viewer. Inline `<h1>` / `<h2>` + `<p>` manual headers removed from every migrated demo.
27
+
28
+ ### Fixed (during migration)
29
+ - `PivotModeDemo` — `apiRef: any`, `fallbackRows: any[]`, `props: any` toolbar → fully typed
30
+ - `InfiniteScrollDemo` — introduced `PersonRow` interface, all `any` in data source and sort params replaced
31
+ - `ServerSideAggregationDemo` — `(a as any)[field]` field access → `keyof Employee` keyed access
32
+ - `AggregationFooter` + `ServerSideAggregationDemo` — `valueFormatter: { value: any }` → `unknown` with narrowing
33
+ - `SlotsDemo` — added `EmployeeRow` interface, `renderCell: (params: any)` × 2 replaced
34
+ - `CRUDTutorial` — `renderCell: (params: any)` → `GridRenderCellParams<User>`
35
+ - `RealEstatePortfolio` — `useState<any>` for pinnedColumns → `useState<GridColumnPinning>`
36
+ - `ExportDemo` — `apiRef: any` → `ReturnType<typeof useGridApiRef>`, `rowsToPrint: any[]` → typed
37
+ - `CustomPagination` — `(props: any)` component signature → explicit typed interface
38
+ - `Editing` — `handleProcessRowUpdate = (newRow: any)` → `MockRow` inferred from data
39
+
40
+ ---
41
+
42
+ ## [0.1.10] — July 30, 2026 🐛🔒
43
+
44
+ ### Fixed
45
+ - **`onRowClick` never fired when `onCellClick` was registered**: `Cell.tsx` was calling `e.stopPropagation()` inside its click handler whenever `onCellClick` was provided. This silently ate the event before it could bubble to the row's `onClick` handler, making `onRowClick` permanently unreachable from cell clicks. Removed the stopPropagation — both callbacks now fire in the natural bubble order (cell first, then row), matching standard data grid behavior.
46
+ - **Column visibility panel list not updating after column reorder**: The toolbar was receiving `effectiveColumns` (the pre-ordering array, in original definition order) instead of `orderedColumns` (the reordered array). After a drag-reorder in the panel, the grid columns reordered correctly but the panel list stayed frozen in definition order. Fixed `toolbarProps.columns` to use `orderedColumns`.
47
+ - **Reset button ignoring column sequence**: The Reset button in the column visibility panel called `onShowAll` only (restoring visibility), leaving any user-reordered sequence in place. Added `onColumnOrderReset` prop threaded from `ColumnVisibilityPanel` → `ColumnsPanelWrapper` → `GridToolbar` → `DataGrid`. DataGrid provides `() => setInternalColumnOrder(columns.map(c => c.field))` to restore original definition order on reset.
48
+ - **`FilterPanelDemo` filter panel inaccessible**: The demo had no `slots={{ toolbar: GridToolbar }}`, so the toolbar never rendered and the filter icon never appeared. Added the toolbar slot and rewrote the demo to use `DocsLayout` (consistent with all other demos).
49
+ - **`EventsDemo` event handlers never fired**: `onRowClick` was broken by the stopPropagation bug above. `onFilterModelChange` and `onColumnOrderChange` were dead — no toolbar existed to trigger them. Fixed by adding `slots={{ toolbar: GridToolbar }}`. Also replaced three `any`-typed handler signatures with `GridSortItem[]`, `GridFilterModel`, and `GridColumnOrderChangeParams`.
50
+ - **`FilterPanel` debounce stale-closure bug**: The 300 ms debounce `useEffect` read `item`, `col.field`, and `currentOperator` directly from closure (stale values after operator or field changes), suppressed with `eslint-disable-next-line`. Replaced with a refs-sync pattern (`useLayoutEffect` writing `itemRef`, `colFieldRef`, `operatorRef` each render) so the effect reads current values without the lint suppression and without stale closures.
51
+
52
+ ### Changed
53
+ - **Type safety — full `any` elimination**: Every `any` across `lib/` replaced with explicit types or `unknown`. Key changes: `GridRowModel` index signature `any → unknown` (with explicit internal row fields added to the type), all cell/value/error params typed as `unknown`, aggregation functions typed as `(values: unknown[]) => unknown`, `GridAggregationResult` typed as `Record<string, unknown>`, slot component types use `Record<string, unknown>`, export utilities narrowed with `instanceof Error` guards.
54
+ - **No more lint suppressions**: Removed all `eslint-disable-next-line react-hooks/exhaustive-deps` comments — every case fixed at the root cause rather than suppressed. Methods include: state refactors (`scrollTick` anti-pattern → `scrollTop`/`scrollLeft` state), ref patterns for stable callbacks, and correct dep arrays.
55
+ - **DataGrid.tsx continued decomposition**: Further hooks and components extracted — `useGridScrollSync` (RAF-batched scroll state), `useGridVirtualization`, `useGridVisibleRows`, `useGridColumns`, `GridAggregationFooter`, `GridEmptyState`, `GridErrorOverlay`, `GridVirtualRows`, `GridPinnedRows`, `GridStandaloneColumnPanel`, `GridListView`. Each module has a single clear responsibility and typed params/return interface.
56
+
57
+ ---
58
+
8
59
  ## [0.1.9] — July 29, 2026 🛠️✨
9
60
 
10
61
  ### Added
package/README.md CHANGED
@@ -40,14 +40,14 @@ const columns: GridColDef[] = [
40
40
  { field: 'name', headerName: 'Name', width: 180 },
41
41
  { field: 'role', headerName: 'Role', width: 150 },
42
42
  { field: 'salary', headerName: 'Salary', width: 120, type: 'number',
43
- valueFormatter: ({ value }) => `$${value.toLocaleString()}` },
43
+ valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}` },
44
44
  { field: 'department', headerName: 'Department', width: 160 },
45
45
  ];
46
46
 
47
47
  const rows = [
48
- { id: 1, name: 'Jon Snow', role: 'Engineer', salary: 95000, department: 'Defense' },
49
- { id: 2, name: 'Cersei Lannister', role: 'Manager', salary: 140000, department: 'Management' },
50
- { id: 3, name: 'Arya Stark', role: 'Analyst', salary: 65000, department: 'Special Ops' },
48
+ { id: 1, name: 'Jon Snow', role: 'Engineer', salary: 95000, department: 'Defense' },
49
+ { id: 2, name: 'Cersei Lannister', role: 'Manager', salary: 140000, department: 'Management' },
50
+ { id: 3, name: 'Arya Stark', role: 'Analyst', salary: 65000, department: 'Special Ops' },
51
51
  ];
52
52
 
53
53
  export default function App() {
@@ -77,18 +77,23 @@ export default function App() {
77
77
  - **Clipboard**: `Ctrl+C` / `Cmd+C` copies selected rows as TSV for Excel/Sheets.
78
78
  - **Accessibility**: WCAG 2.1 AA — full ARIA roles and keyboard navigation.
79
79
  - **Theming**: CSS variable API with 5 built-in themes + custom theme support.
80
+ - **Column & Row Reordering**: Drag-and-drop column reordering and row reordering.
81
+ - **Inline Cell Editing**: Full inline editing with `processRowUpdate` validation.
82
+ - **State Persistence**: Save and restore grid state (sort, filter, columns) via `useGridStateStorage`.
80
83
  - **AI-Native Integration**: Shipped with raw `lib/` source and `docs/` inside the npm package, allowing AI agents (Cursor, Copilot, Windsurf) to flawlessly implement features by "seeing" the internal logic.
81
84
 
82
85
  ---
83
86
 
84
87
  ## 🤖 AI-Powered Implementation
85
88
 
86
- OpenGridX is built for the era of AI-native development. When you install `@opencorestack/opengridx`, we include the full raw source code and markdown documentation in your `node_modules`.
89
+ OpenGridX is built for the era of AI-native development. When you install `@opencorestack/opengridx`, we include the full raw source code and markdown documentation in your `node_modules`.
87
90
 
88
91
  This means that **Cursor**, **GitHub Copilot**, **Windsurf**, and other AI agents can read the actual implementation patterns and docs to accurately help you build complex features like server-side tree data or pivot tables without guessing.
89
92
 
90
93
  > **Tip for Cursor/Copilot users:** If your AI is struggling, tell it to "Read the docs and source in `./node_modules/@opencorestack/opengridx/docs`" for instant context.
91
94
 
95
+ ---
96
+
92
97
  ## 📐 API Reference
93
98
 
94
99
  ### Core Props
@@ -97,14 +102,21 @@ This means that **Cursor**, **GitHub Copilot**, **Windsurf**, and other AI agent
97
102
  | :--- | :--- | :--- | :--- |
98
103
  | `rows` | `GridRowModel[]` | — | **Required.** Array of data rows. |
99
104
  | `columns` | `GridColDef[]` | — | **Required.** Column definitions. |
100
- | `height` | `number` | `500` | Grid height in pixels. |
105
+ | `height` | `number \| string` | `500` | Grid height in pixels or CSS string (e.g. `'100%'`). |
106
+ | `autoHeight` | `boolean` | `false` | Expands grid height to fit all rows. |
101
107
  | `loading` | `boolean` | `false` | Shows skeleton loader when `true`. |
108
+ | `density` | `'compact' \| 'standard' \| 'comfortable'` | `'standard'` | Visual row density. |
102
109
  | `checkboxSelection` | `boolean` | `false` | Enables checkbox column for row selection. |
103
110
  | `pagination` | `boolean` | `false` | Enables client-side pagination. |
104
- | `pageSize` | `number` | `25` | Rows per page. |
111
+ | `paginationModel` | `{ page: number; pageSize: number }` | — | Controlled pagination state. |
112
+ | `onPaginationModelChange` | `(model) => void` | — | Fires on page or page size change. |
113
+ | `pageSizeOptions` | `number[]` | `[10, 25, 50]` | Available page size options. |
105
114
  | `getRowId` | `(row) => GridRowId` | `row.id` | Custom row ID accessor. |
106
115
  | `rowHeight` | `number` | `52` | Row height in pixels. |
107
116
  | `headerHeight` | `number` | `56` | Header height in pixels. |
117
+ | `noRowsLabel` | `string` | — | Custom empty-state message. |
118
+ | `className` | `string` | — | Custom CSS class on the grid container. |
119
+ | `style` | `React.CSSProperties` | — | Custom inline styles on the grid container. |
108
120
 
109
121
  ### Selection
110
122
 
@@ -113,17 +125,37 @@ This means that **Cursor**, **GitHub Copilot**, **Windsurf**, and other AI agent
113
125
  | `rowSelectionModel` | `GridRowId[]` | Controlled selected row IDs. |
114
126
  | `onRowSelectionModelChange` | `(model: GridRowId[]) => void` | Fires on selection change. |
115
127
  | `disableRowSelectionOnClick` | `boolean` | Prevent row click from toggling selection. |
128
+ | `disableMultipleRowSelection` | `boolean` | Restrict to single-row selection. |
129
+ | `pinCheckboxColumn` | `boolean` | Keeps the checkbox column visible during horizontal scroll. |
116
130
 
117
131
  ### Sorting & Filtering
118
132
 
119
133
  | Prop | Type | Description |
120
134
  | :--- | :--- | :--- |
121
135
  | `sortModel` | `GridSortItem[]` | Controlled sort model. |
122
- | `onSortModelChange` | `(model) => void` | Fires on sort change. |
136
+ | `onSortModelChange` | `(model: GridSortItem[]) => void` | Fires on sort change. |
123
137
  | `filterModel` | `GridFilterModel` | Controlled filter model. |
124
- | `onFilterModelChange` | `(model) => void` | Fires on filter change. |
138
+ | `onFilterModelChange` | `(model: GridFilterModel) => void` | Fires on filter change. |
125
139
  | `disableColumnFilter` | `boolean` | Disables column-level filtering. |
126
140
 
141
+ ### Columns
142
+
143
+ | Prop | Type | Description |
144
+ | :--- | :--- | :--- |
145
+ | `columnVisibilityModel` | `GridColumnVisibilityModel` | Controlled column visibility. |
146
+ | `onColumnVisibilityModelChange` | `(model) => void` | Fires when column visibility changes. |
147
+ | `columnOrder` | `string[]` | Controlled column field order. |
148
+ | `onColumnOrderChange` | `(params) => void` | Fires when columns are reordered. |
149
+ | `disableColumnReorder` | `boolean` | Disables drag-and-drop column reordering. |
150
+
151
+ ### Events
152
+
153
+ | Prop | Type | Description |
154
+ | :--- | :--- | :--- |
155
+ | `onRowClick` | `(params: GridRowParams) => void` | Fires when a row is clicked. |
156
+ | `onCellClick` | `(params: GridCellParams) => void` | Fires when a cell is clicked. |
157
+ | `onRowsScrollEnd` | `(params: GridRowScrollEndParams) => void` | Fires when scrolling reaches the bottom. |
158
+
127
159
  ### Server-Side
128
160
 
129
161
  | Prop | Type | Description |
@@ -134,11 +166,60 @@ This means that **Cursor**, **GitHub Copilot**, **Windsurf**, and other AI agent
134
166
  | `dataSource` | `GridDataSource` | Server-side data adapter. |
135
167
  | `rowCount` | `number` | Total rows for server-side pagination. |
136
168
 
169
+ ### Pinning
170
+
171
+ | Prop | Type | Description |
172
+ | :--- | :--- | :--- |
173
+ | `pinnedColumns` | `GridColumnPinning` | Pin columns to `left` or `right`. |
174
+ | `onPinnedColumnsChange` | `(model) => void` | Fires when column pinning changes. |
175
+ | `pinnedRows` | `GridRowPinning` | Pin rows to `top` or `bottom`. |
176
+ | `onPinnedRowsChange` | `(model) => void` | Fires when row pinning changes. |
177
+
178
+ ### Inline Editing
179
+
180
+ | Prop | Type | Description |
181
+ | :--- | :--- | :--- |
182
+ | `isCellEditable` | `(params: GridCellParams) => boolean` | Per-cell editability predicate. |
183
+ | `processRowUpdate` | `(newRow, oldRow) => R \| Promise<R>` | Handles row save; supports async validation. |
184
+ | `onProcessRowUpdateError` | `(error: unknown) => void` | Fires if `processRowUpdate` throws. |
185
+
186
+ ### Row Reordering
187
+
188
+ | Prop | Type | Description |
189
+ | :--- | :--- | :--- |
190
+ | `rowReordering` | `boolean` | Enables drag-and-drop row reordering. |
191
+ | `onRowOrderChange` | `(params) => void` | Fires when rows are reordered. |
192
+
193
+ ### Advanced Features
194
+
195
+ | Prop | Type | Description |
196
+ | :--- | :--- | :--- |
197
+ | `treeData` | `boolean` | Enables hierarchical tree data display. |
198
+ | `getTreeDataPath` | `(row) => string[]` | Returns the path array for each row in tree mode. |
199
+ | `groupingColDef` | `GridColDef` | Overrides the auto-generated grouping column. |
200
+ | `defaultGroupingExpansionDepth` | `number` | Initial expansion depth for tree data. |
201
+ | `rowGroupingModel` | `GridRowGroupingModel` | Controlled row grouping state. |
202
+ | `onRowGroupingModelChange` | `(model) => void` | Fires when grouping changes. |
203
+ | `aggregationModel` | `GridAggregationModel` | Controlled aggregation state (e.g. `{ salary: 'sum' }`). |
204
+ | `onAggregationModelChange` | `(model) => void` | Fires when aggregation changes. |
205
+ | `pivotMode` | `boolean` | Switches the grid to multidimensional pivot mode. |
206
+ | `pivotModel` | `GridPivotModel` | Controlled pivot configuration (rows, columns, values). |
207
+ | `onPivotModelChange` | `(model) => void` | Fires when pivot model changes. |
208
+
209
+ ### Master-Detail
210
+
211
+ | Prop | Type | Description |
212
+ | :--- | :--- | :--- |
213
+ | `getDetailPanelContent` | `(params) => ReactNode` | Renders the expandable detail panel. |
214
+ | `getDetailPanelHeight` | `(params) => number \| 'auto'` | Controls detail panel height. |
215
+ | `detailPanelExpandedRowIds` | `Set<GridRowId>` | Controlled expanded rows. |
216
+ | `onDetailPanelExpandedRowIdsChange` | `(ids) => void` | Fires when expanded rows change. |
217
+
137
218
  ### Customization
138
219
 
139
220
  | Prop | Type | Description |
140
221
  | :--- | :--- | :--- |
141
- | `slots` | `GridSlots` | Replace built-in components (toolbar, pagination, overlays). |
222
+ | `slots` | `GridSlots` | Replace built-in components (toolbar, pagination, overlays, footer). |
142
223
  | `slotProps` | `GridSlotProps` | Pass custom props to slot components. |
143
224
  | `getRowClassName` | `(params) => string` | Add custom CSS class to rows. |
144
225
  | `getCellClassName` | `(params) => string` | Add custom CSS class to cells. |
@@ -150,14 +231,42 @@ This means that **Cursor**, **GitHub Copilot**, **Windsurf**, and other AI agent
150
231
  const apiRef = useGridApiRef();
151
232
  <DataGrid apiRef={apiRef} ... />
152
233
 
153
- // Usage
234
+ // Rows
235
+ apiRef.current.getRow(id) // → GridRowModel | null
236
+ apiRef.current.getAllRows() // → GridRowModel[]
237
+ apiRef.current.getVisibleRows() // → GridRowModel[] (post-filter/sort)
238
+
239
+ // Columns
240
+ apiRef.current.getColumn(field) // → GridColDef | null
241
+ apiRef.current.getAllColumns() // → GridColDef[]
242
+ apiRef.current.getVisibleColumns() // → GridColDef[]
243
+
244
+ // Selection
245
+ apiRef.current.selectRow(id, true)
246
+ apiRef.current.selectRows([id1, id2], true)
154
247
  apiRef.current.getSelectedRows() // → GridRowId[]
155
- apiRef.current.copySelectedRows() // → Promise<void>
156
- apiRef.current.selectRow(id, true) // select a row
157
- apiRef.current.setFilterModel(model) // programmatic filter
248
+
249
+ // Sorting
158
250
  apiRef.current.sortColumn('name', 'asc')
251
+ apiRef.current.getSortModel() // → GridSortItem[]
252
+
253
+ // Filtering
254
+ apiRef.current.setFilterModel(model)
255
+ apiRef.current.getFilterModel() // → GridFilterModel
256
+
257
+ // Pagination
159
258
  apiRef.current.setPage(2)
160
- apiRef.current.getVisibleRows() // → GridRowModel[]
259
+ apiRef.current.setPageSize(50)
260
+
261
+ // Scroll
262
+ apiRef.current.scrollToIndexes({ rowIndex: 100, colIndex: 3 })
263
+
264
+ // Clipboard
265
+ apiRef.current.copySelectedRows() // → Promise<void>
266
+
267
+ // Aggregation
268
+ apiRef.current.getAggregationResult() // → Record<string, unknown> | null
269
+ apiRef.current.getAggregationModel() // → GridAggregationModel | null
161
270
  ```
162
271
 
163
272
  ---
@@ -186,6 +295,20 @@ Replace any built-in component with your own:
186
295
  />
187
296
  ```
188
297
 
298
+ ### Built-in Toolbar
299
+
300
+ ```tsx
301
+ import { DataGrid, GridToolbar } from '@opencorestack/opengridx';
302
+
303
+ <DataGrid
304
+ rows={rows}
305
+ columns={columns}
306
+ slots={{ toolbar: GridToolbar }}
307
+ />
308
+ ```
309
+
310
+ `GridToolbar` provides global search, column visibility panel, filter panel, and export controls out of the box.
311
+
189
312
  ### Export Functionality
190
313
 
191
314
  OpenGridX has **two tiers of Excel export**:
@@ -214,6 +337,21 @@ printGrid(rows, columns, 'Report Title');
214
337
  > npm install exceljs
215
338
  > ```
216
339
 
340
+ ### State Persistence
341
+
342
+ ```tsx
343
+ import { useGridStateStorage } from '@opencorestack/opengridx';
344
+
345
+ const { initialState, onStateChange } = useGridStateStorage('my-grid-key');
346
+
347
+ <DataGrid
348
+ rows={rows}
349
+ columns={columns}
350
+ initialState={initialState}
351
+ onStateChange={onStateChange}
352
+ />
353
+ ```
354
+
217
355
  ### Theming
218
356
 
219
357
  ```tsx
@@ -232,11 +370,11 @@ Built-in themes: `darkTheme`, `roseTheme`, `emeraldTheme`, `amberTheme`, `compac
232
370
 
233
371
  | Artifact | Minified | Gzipped | Notes |
234
372
  | :--- | :--- | :--- | :--- |
235
- | **Core ES Module** (`opengridx.es.js`) | 220 KB | **52 KB** | Use this — tree-shakeable |
236
- | **Core UMD** (`opengridx.umd.js`) | 146 KB | **44 KB** | CommonJS / CDN compat |
237
- | **Styles** (`opengridx.css`) | 57 KB | **9 KB** | Auto-included |
373
+ | **Core ES Module** (`opengridx.es.js`) | 242 KB | **58 KB** | Use this — tree-shakeable |
374
+ | **Core UMD** (`opengridx.umd.js`) | 164 KB | **48 KB** | CommonJS / CDN compat |
375
+ | **Styles** (`opengridx.css`) | 62 KB | **10 KB** | Auto-included |
238
376
  | **ExcelJS** (optional peer dep) | — | — | `npm install exceljs` |
239
- | **npm package download** | — | **400 KB** | Total compressed tarball |
377
+ | **npm package download** | — | **613 KB** | Total compressed tarball |
240
378
 
241
379
  - **Tree-shaking Ready**: ES Module build — bundlers (Vite, Webpack) only include what you use.
242
380
  - **Zero UI Dependencies**: No MUI, Ant Design, or Radix. Pure React + vanilla CSS.
@@ -252,6 +390,8 @@ Full documentation at 👉 **[opencorestack.github.io/OpenGridX](https://opencor
252
390
  ### 🏛️ Components
253
391
  - **[DataGrid](docs/components/datagrid.md)** — Main component props and slots
254
392
  - **[Toolbar & Pagination](docs/components/toolbar.md)** — Supplemental UI components
393
+ - **[Filter Panel](docs/components/filter-panel.md)** — Advanced filter panel component
394
+ - **[Column Visibility](docs/components/column-visibility.md)** — Column show/hide panel
255
395
 
256
396
  ### 🚀 Features
257
397
  - **[Virtualization](docs/features/virtualization.md)** — 60fps rendering for 100k+ rows
@@ -264,6 +404,7 @@ Full documentation at 👉 **[opencorestack.github.io/OpenGridX](https://opencor
264
404
  - **[Infinite Scroll](docs/features/infinite-scroll.md)** — Seamless lazy-loading
265
405
  - **[Export Guide](docs/features/export-guide.md)** — Excel, CSV, and Print
266
406
  - **[Data Source](docs/features/data-source.md)** — Server-side integration
407
+ - **[Loading States](docs/features/loading-states.md)** — Skeleton and shimmer overlays
267
408
 
268
409
  ### 📊 Advanced Data
269
410
  - **[Aggregation & Pivot](docs/features/aggregation-pivot.md)** — Summary totals
@@ -292,6 +433,8 @@ Most React grids gatekeep essential features like **Row Grouping**, **Excel Expo
292
433
  | Advanced Filtering | ❌ | ✅ | ❌ | ✅ |
293
434
  | Aggregation | ❌ | ✅ | ❌ | ✅ |
294
435
  | Pivot Mode | ❌ | ✅ | ❌ | ✅ |
436
+ | Inline Cell Editing | ❌ | ✅ | ✅ | ✅ |
437
+ | State Persistence | ❌ | ✅ | ❌ | ✅ |
295
438
  | **Price** | Free | **$$$** | Free (limited) | **Free** |
296
439
 
297
440
  ---
package/dist/index.d.ts CHANGED
@@ -34,9 +34,9 @@ declare function CellImpl<R extends GridRowModel = GridRowModel>(props: CellProp
34
34
 
35
35
  declare interface CellProps<R extends GridRowModel = GridRowModel> {
36
36
  onCellClick?: (params: GridCellParams<R>) => void;
37
- onCellEditStart?: (field: string, value: any) => void;
38
- onCellValueChange?: (field: string, newValue: any) => void;
39
- value: any;
37
+ onCellEditStart?: (field: string, value: unknown) => void;
38
+ onCellValueChange?: (field: string, newValue: unknown) => void;
39
+ value: unknown;
40
40
  row: R;
41
41
  colDef: GridColDef<R>;
42
42
  rowIndex: number;
@@ -52,7 +52,7 @@ declare interface CellProps<R extends GridRowModel = GridRowModel> {
52
52
  isEditing?: boolean;
53
53
  onEditStart?: () => void;
54
54
  onEditStop?: (cancel?: boolean) => void;
55
- onValueChange?: (newValue: any) => void;
55
+ onValueChange?: (newValue: unknown) => void;
56
56
  colSpanInfo?: CellColSpanInfo;
57
57
  rowSpan?: number;
58
58
  isHiddenByRowSpan?: boolean;
@@ -75,7 +75,7 @@ export declare interface CsvExportOptions {
75
75
  includeHeaders?: boolean;
76
76
  delimiter?: string;
77
77
  selectedRows?: (string | number)[];
78
- aggregationResult?: Record<string, any> | null;
78
+ aggregationResult?: Record<string, unknown> | null;
79
79
  aggregationModel?: GridAggregationModel | null;
80
80
  }
81
81
 
@@ -218,7 +218,7 @@ export declare interface DataGridProps<R extends GridRowModel = GridRowModel> {
218
218
  /** Callback to process an updated row after inline editing. Supports promises and validation. */
219
219
  processRowUpdate?: (newRow: R, oldRow: R) => R | Promise<R>;
220
220
  /** Callback fired if `processRowUpdate` throws or rejects. */
221
- onProcessRowUpdateError?: (error: any) => void;
221
+ onProcessRowUpdateError?: (error: unknown) => void;
222
222
  /** Interface for connecting the grid to an external (server-side) data source. */
223
223
  dataSource?: GridDataSource<R>;
224
224
  /** Callback fired when scrolling reaches the bottom of the grid viewport. */
@@ -228,23 +228,23 @@ export declare interface DataGridProps<R extends GridRowModel = GridRowModel> {
228
228
  /** Custom components to replace internal grid parts. */
229
229
  slots?: {
230
230
  /** Component rendered as the grid toolbar. */
231
- toolbar?: React.ComponentType<any>;
231
+ toolbar?: React.ComponentType<Record<string, unknown>>;
232
232
  /** Component rendered as the pagination control. */
233
- pagination?: React.ComponentType<any>;
233
+ pagination?: React.ComponentType<Record<string, unknown>>;
234
234
  /** Component rendered when the grid is empty. */
235
- noRowsOverlay?: React.ComponentType<any>;
235
+ noRowsOverlay?: React.ComponentType<Record<string, unknown>>;
236
236
  /** Component rendered during loading states. */
237
- loadingOverlay?: React.ComponentType<any>;
237
+ loadingOverlay?: React.ComponentType<Record<string, unknown>>;
238
238
  /** Component rendered at the very bottom of the grid. */
239
- footer?: React.ComponentType<any>;
239
+ footer?: React.ComponentType<Record<string, unknown>>;
240
240
  };
241
241
  /** Properties passed directly to custom slots. */
242
242
  slotProps?: {
243
- toolbar?: any;
244
- pagination?: any;
245
- noRowsOverlay?: any;
246
- loadingOverlay?: any;
247
- footer?: any;
243
+ toolbar?: Record<string, unknown>;
244
+ pagination?: Record<string, unknown>;
245
+ noRowsOverlay?: Record<string, unknown>;
246
+ loadingOverlay?: Record<string, unknown>;
247
+ footer?: Record<string, unknown>;
248
248
  };
249
249
  /** When true, renders the grid as a single-column list of cards. Perfect for mobile/responsive views. */
250
250
  listView?: boolean;
@@ -293,7 +293,7 @@ export declare interface ExcelAdvancedExportOptions {
293
293
  /** Body font size (default: 10) */
294
294
  bodyFontSize?: number;
295
295
  /** Current aggregation result */
296
- aggregationResult?: Record<string, any> | null;
296
+ aggregationResult?: Record<string, unknown> | null;
297
297
  /** Current aggregation model */
298
298
  aggregationModel?: GridAggregationModel | null;
299
299
  /** Currently selected row IDs */
@@ -325,7 +325,7 @@ export declare interface ExcelExportOptions {
325
325
  sheetName?: string;
326
326
  includeHeaders?: boolean;
327
327
  selectedRows?: (string | number)[];
328
- aggregationResult?: Record<string, any> | null;
328
+ aggregationResult?: Record<string, unknown> | null;
329
329
  aggregationModel?: GridAggregationModel | null;
330
330
  }
331
331
 
@@ -373,13 +373,13 @@ declare interface FilterPanelProps {
373
373
  onFilterModelChange: (model: GridFilterModel) => void;
374
374
  }
375
375
 
376
- export declare function formatAggregationValue(value: any, fnName: string): string;
376
+ export declare function formatAggregationValue(value: unknown, fnName: string): string;
377
377
 
378
378
  export declare interface GridAggregationModel {
379
379
  [field: string]: string;
380
380
  }
381
381
 
382
- export declare type GridAggregationResult = Record<string, any>;
382
+ export declare type GridAggregationResult = Record<string, unknown>;
383
383
 
384
384
  export declare type GridAlignment = 'left' | 'center' | 'right';
385
385
 
@@ -398,7 +398,7 @@ export declare interface GridApi {
398
398
  /** Returns all rows currently visible after filtering and sorting. */
399
399
  getVisibleRows: () => GridRowModel[];
400
400
  /** Returns the current aggregation results. */
401
- getAggregationResult: () => Record<string, any> | null;
401
+ getAggregationResult: () => Record<string, unknown> | null;
402
402
  /** Returns the active aggregation configuration. */
403
403
  getAggregationModel: () => GridAggregationModel | null;
404
404
  /** Returns the column definition for the given field. */
@@ -453,7 +453,7 @@ export declare interface GridApi {
453
453
  export declare interface GridCellParams<R extends GridRowModel = GridRowModel> {
454
454
  row: R;
455
455
  field: string;
456
- value: any;
456
+ value: unknown;
457
457
  colDef: GridColDef<R>;
458
458
  rowIndex: number;
459
459
  colIndex: number;
@@ -498,15 +498,17 @@ export declare interface GridColDef<R extends GridRowModel = GridRowModel> {
498
498
  hideable?: boolean;
499
499
  /** If false, the column cannot be pinned. */
500
500
  pinnable?: boolean;
501
+ /** Internal: marks this column as a virtual spacer used for horizontal virtualization. */
502
+ isSpacer?: boolean;
501
503
  /** Type used to determine default operators and formatting logic. */
502
504
  type?: 'string' | 'number' | 'date' | 'boolean' | 'singleSelect' | 'image';
503
505
  /** Options used for 'singleSelect' type. */
504
506
  valueOptions?: Array<string | number | {
505
- value: any;
507
+ value: unknown;
506
508
  label: string;
507
509
  }>;
508
510
  /** Function to compute a cell value from raw row data. */
509
- valueGetter?: (params: GridValueGetterParams<R>) => any;
511
+ valueGetter?: (params: GridValueGetterParams<R>) => unknown;
510
512
  /** Function to format a value into a human-readable string. */
511
513
  valueFormatter?: (params: GridValueFormatterParams<R>) => string;
512
514
  /** Custom component or element to render in the cell. */
@@ -615,12 +617,12 @@ export declare interface GridDataSource<R extends GridRowModel = GridRowModel> {
615
617
  /**
616
618
  * Optional: Fetches aggregation results for the entire dataset.
617
619
  */
618
- getAggregations?: (params: Omit<GridGetRowsParams, 'startRow' | 'endRow'>) => Promise<Record<string, any>>;
620
+ getAggregations?: (params: Omit<GridGetRowsParams, 'startRow' | 'endRow'>) => Promise<Record<string, unknown>>;
619
621
  }
620
622
 
621
623
  declare interface GridDataSourceState {
622
624
  loading: boolean;
623
- error?: any;
625
+ error?: unknown;
624
626
  }
625
627
 
626
628
  export declare interface GridDensityState {
@@ -654,7 +656,7 @@ export declare interface GridFilterItem {
654
656
  /** The comparison operator. */
655
657
  operator: GridFilterOperator;
656
658
  /** The value to compare against. */
657
- value?: any;
659
+ value?: unknown;
658
660
  }
659
661
 
660
662
  /** The overall state of grid filtering. */
@@ -685,7 +687,7 @@ export declare interface GridGetRowsParams {
685
687
  export declare interface GridGetRowsResponse<R extends GridRowModel = GridRowModel> {
686
688
  rows: R[];
687
689
  rowCount?: number;
688
- aggregationResults?: Record<string, any>;
690
+ aggregationResults?: Record<string, unknown>;
689
691
  }
690
692
 
691
693
  export declare type GridInitialState = GridState;
@@ -725,7 +727,7 @@ export declare interface GridPivotValueField {
725
727
  /** Parameters passed to the `renderCell` function. */
726
728
  export declare interface GridRenderCellParams<R extends GridRowModel = GridRowModel> {
727
729
  /** The current cell value. */
728
- value: any;
730
+ value: unknown;
729
731
  /** The row object. */
730
732
  row: R;
731
733
  /** The field name and unique ID. */
@@ -753,8 +755,24 @@ export declare type GridRowId = string | number;
753
755
  export declare interface GridRowModel {
754
756
  /** Uniquely identifies the row. */
755
757
  id: GridRowId;
758
+ /** Internal: row has child nodes (tree data / row grouping). */
759
+ _hasChildren?: boolean;
760
+ /** Internal: row is a skeleton placeholder during infinite-scroll loading. */
761
+ _isSkeleton?: boolean;
762
+ /** Internal: depth in the tree or grouping hierarchy. */
763
+ _treeDepth?: number;
764
+ /** Internal: whether the group/tree node is currently expanded. */
765
+ _isExpanded?: boolean;
766
+ /** Internal: field used for grouping at this level. */
767
+ _groupingField?: string;
768
+ /** Internal: grouping field value at this level. */
769
+ _groupingValue?: unknown;
770
+ /** Internal: total descendant count for tree/grouping nodes. */
771
+ _descendantCount?: number;
772
+ /** Internal: server-reported child count for lazy-loaded tree nodes. */
773
+ serverChildrenCount?: number;
756
774
  /** Any other dynamic row properties. */
757
- [key: string]: any;
775
+ [key: string]: unknown;
758
776
  }
759
777
 
760
778
  export declare interface GridRowOrderChangeParams<R extends GridRowModel = GridRowModel> {
@@ -958,7 +976,7 @@ export declare interface GridThemeTypography {
958
976
  fontSizeXl?: string;
959
977
  }
960
978
 
961
- export declare function GridToolbar({ columns, baseColumns, aggregationModel, onAggregationModelChange, pivotModel, onPivotModelChange, filterModel, onFilterModelChange, columnVisibilityModel, onColumnVisibilityModelChange, onColumnReorder, forceColumnsOpen, onColumnsPanelClose, children, rightContent, style, }: GridToolbarProps): JSX.Element;
979
+ export declare function GridToolbar({ columns, baseColumns, aggregationModel, onAggregationModelChange, pivotModel, onPivotModelChange, filterModel, onFilterModelChange, columnVisibilityModel, onColumnVisibilityModelChange, onColumnReorder, onColumnOrderReset, forceColumnsOpen, onColumnsPanelClose, children, rightContent, style, }: GridToolbarProps): JSX.Element;
962
980
 
963
981
  export declare interface GridToolbarProps {
964
982
  columns?: GridColDef[];
@@ -976,6 +994,7 @@ export declare interface GridToolbarProps {
976
994
  columnVisibilityModel?: Record<string, boolean>;
977
995
  onColumnVisibilityModelChange?: (model: Record<string, boolean>) => void;
978
996
  onColumnReorder?: (fromField: string, toField: string) => void;
997
+ onColumnOrderReset?: () => void;
979
998
  forceColumnsOpen?: boolean;
980
999
  onColumnsPanelClose?: () => void;
981
1000
  children?: default_2.ReactNode;
@@ -1006,9 +1025,9 @@ export declare interface GridTreeNode {
1006
1025
  /** The field this node is grouping by. */
1007
1026
  groupingField?: string;
1008
1027
  /** The actual value being grouped. */
1009
- groupingValue?: any;
1028
+ groupingValue?: unknown;
1010
1029
  /** Computed aggregation results for this group. */
1011
- aggregatedValues?: Record<string, any>;
1030
+ aggregatedValues?: Record<string, unknown>;
1012
1031
  /** Position of the aggregation row relative to the group. */
1013
1032
  aggregationPosition?: 'inline' | 'footer' | null;
1014
1033
  /** Current expansion state. */
@@ -1026,7 +1045,7 @@ export declare interface GridTreeNode {
1026
1045
  /** Parameters passed to the `valueFormatter` function. */
1027
1046
  export declare interface GridValueFormatterParams<R extends GridRowModel = GridRowModel> {
1028
1047
  /** The raw value to format. */
1029
- value: any;
1048
+ value: unknown;
1030
1049
  /** The row object. */
1031
1050
  row: R;
1032
1051
  /** The field name. */
@@ -1040,7 +1059,7 @@ export declare interface GridValueGetterParams<R extends GridRowModel = GridRowM
1040
1059
  /** The field name. */
1041
1060
  field: string;
1042
1061
  /** The raw value from the row object. */
1043
- value: any;
1062
+ value: unknown;
1044
1063
  }
1045
1064
 
1046
1065
  export declare function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps<R>): JSX.Element;
@@ -1095,7 +1114,7 @@ export declare interface JsonExportOptions {
1095
1114
  fileName?: string;
1096
1115
  pretty?: boolean;
1097
1116
  selectedRows?: (string | number)[];
1098
- aggregationResult?: Record<string, any> | null;
1117
+ aggregationResult?: Record<string, unknown> | null;
1099
1118
  aggregationModel?: GridAggregationModel | null;
1100
1119
  }
1101
1120
 
@@ -1107,7 +1126,7 @@ export declare function printGrid<R extends GridRowModel>(rows: R[], columns: Gr
1107
1126
  export declare interface PrintOptions {
1108
1127
  title?: string;
1109
1128
  selectedRows?: (string | number)[];
1110
- aggregationResult?: Record<string, any> | null;
1129
+ aggregationResult?: Record<string, unknown> | null;
1111
1130
  aggregationModel?: GridAggregationModel | null;
1112
1131
  }
1113
1132
 
@@ -1144,12 +1163,12 @@ declare interface RowProps<R extends GridRowModel = GridRowModel> {
1144
1163
  editingCell?: {
1145
1164
  id: GridRowId;
1146
1165
  field: string;
1147
- value: any;
1166
+ value: unknown;
1148
1167
  } | null;
1149
1168
  onEditStart?: (params: {
1150
1169
  id: GridRowId;
1151
1170
  field: string;
1152
- value: any;
1171
+ value: unknown;
1153
1172
  }) => void;
1154
1173
  onEditStop?: (params?: {
1155
1174
  cancel?: boolean;
@@ -1157,7 +1176,7 @@ declare interface RowProps<R extends GridRowModel = GridRowModel> {
1157
1176
  onEditCellValueChange?: (params: {
1158
1177
  id: GridRowId;
1159
1178
  field: string;
1160
- value: any;
1179
+ value: unknown;
1161
1180
  }) => void;
1162
1181
  focusedCellField?: string | null;
1163
1182
  isFocusVisible?: boolean;
@@ -1194,7 +1213,7 @@ export declare interface UseAggregationParams<R extends GridRowModel> {
1194
1213
  export declare interface UseAggregationReturn {
1195
1214
  aggregationResult: GridAggregationResult;
1196
1215
  isLoading: boolean;
1197
- error: any;
1216
+ error: unknown;
1198
1217
  }
1199
1218
 
1200
1219
  /**