@geovi/the-datagrid 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +47 -1253
  2. package/dist/BoolEditor.cjs +1 -1
  3. package/dist/BoolEditor.js +235 -222
  4. package/dist/DateEditor.cjs +1 -1
  5. package/dist/DateEditor.js +297 -273
  6. package/dist/DateFilter.cjs +1 -1
  7. package/dist/DateFilter.js +65 -63
  8. package/dist/NumberFilter.cjs +1 -1
  9. package/dist/NumberFilter.js +104 -102
  10. package/dist/NumericEditor.cjs +1 -1
  11. package/dist/NumericEditor.js +296 -277
  12. package/dist/SelectEditor.cjs +42 -0
  13. package/dist/SelectEditor.js +6703 -0
  14. package/dist/StringFilter.cjs +1 -1
  15. package/dist/StringFilter.js +121 -119
  16. package/dist/TextEditor.cjs +2 -0
  17. package/dist/TextEditor.js +2972 -0
  18. package/dist/base.css +1 -1
  19. package/dist/community-package-manifest.json +3 -1
  20. package/dist/components/ui/input.d.ts +2 -0
  21. package/dist/components/ui/input.d.ts.map +1 -1
  22. package/dist/editors/BoolEditor.d.ts +1 -1
  23. package/dist/editors/BoolEditor.d.ts.map +1 -1
  24. package/dist/editors/DateEditor.d.ts +1 -1
  25. package/dist/editors/DateEditor.d.ts.map +1 -1
  26. package/dist/editors/NumericEditor.d.ts +1 -1
  27. package/dist/editors/NumericEditor.d.ts.map +1 -1
  28. package/dist/editors/SelectEditor.d.ts +27 -0
  29. package/dist/editors/SelectEditor.d.ts.map +1 -0
  30. package/dist/editors/TextEditor.d.ts +27 -0
  31. package/dist/editors/TextEditor.d.ts.map +1 -0
  32. package/dist/editors/editorTypes.d.ts +24 -0
  33. package/dist/editors/editorTypes.d.ts.map +1 -1
  34. package/dist/editors/index.d.ts +5 -0
  35. package/dist/editors/index.d.ts.map +1 -1
  36. package/dist/grid/ReactDataGrid.d.ts.map +1 -1
  37. package/dist/grid/components/GridBody.d.ts.map +1 -1
  38. package/dist/grid/components/GridContextMenuLayer.d.ts.map +1 -1
  39. package/dist/grid/hooks/useGridEditing.d.ts.map +1 -1
  40. package/dist/grid/menuRuntime.d.ts +27 -0
  41. package/dist/grid/menuRuntime.d.ts.map +1 -0
  42. package/dist/index.cjs +13 -13
  43. package/dist/index.css +1 -1
  44. package/dist/index.js +9435 -9164
  45. package/dist/main.d.ts +2 -2
  46. package/dist/main.d.ts.map +1 -1
  47. package/dist/style/theme/amber-dark/index.css +1 -1
  48. package/dist/style/theme/amber-light/index.css +1 -1
  49. package/dist/style/theme/blue-dark/index.css +1 -1
  50. package/dist/style/theme/blue-light/index.css +1 -1
  51. package/dist/style/theme/default-dark/index.css +1 -1
  52. package/dist/style/theme/default-light/index.css +1 -1
  53. package/dist/style/theme/green-dark/index.css +1 -1
  54. package/dist/style/theme/green-light/index.css +1 -1
  55. package/dist/style/theme/pink-dark/index.css +1 -1
  56. package/dist/style/theme/pink-light/index.css +1 -1
  57. package/dist/toolbar/RDGToolbar.d.ts.map +1 -1
  58. package/dist/toolbar/icons.d.ts +0 -2
  59. package/dist/toolbar/icons.d.ts.map +1 -1
  60. package/dist/toolbar/runtime.d.ts +7 -0
  61. package/dist/toolbar/runtime.d.ts.map +1 -1
  62. package/dist/toolbar.css +1 -1
  63. package/dist/toolbar.js +548 -651
  64. package/dist/types.d.ts +7 -0
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +20 -2
package/README.md CHANGED
@@ -1,1297 +1,91 @@
1
1
  # the-datagrid
2
2
 
3
- A modern, feature-rich React data grid built on **TanStack Table** with a **shadcn-aligned** look-and-feel and **self-contained packaged styles**.
3
+ A fast, fully typed React data grid with an Inovua-compatible API and a
4
+ shadcn-aligned interface.
4
5
 
5
- Documentation and live examples: https://geo-vi.github.io/the-datagrid/
6
+ [Documentation and live examples](https://geo-vi.github.io/the-datagrid/) ·
7
+ [npm](https://www.npmjs.com/package/@geovi/the-datagrid) ·
8
+ [GitHub](https://github.com/geo-vi/the-datagrid)
6
9
 
7
- ## Features
10
+ ## Why the-datagrid?
8
11
 
9
- - Virtualized rendering for large datasets
10
- - Sorting (single + multi-column)
11
- - Filtering with a built-in filter row and operators
12
- - Opt-in global table search through a separate, tree-shakeable entry
13
- - Opt-in grid toolbar: column toggles, export, filter-row and clear-filter actions
14
- - Column management (reorder, resize, auto-size)
15
- - Stacked and nested column headers with split/rejoin and group resizing
16
- - Pagination (local + remote)
17
- - Row selection (checkbox column)
18
- - Modern shadcn-aligned look-and-feel with packaged styles
19
- - Fully typed TypeScript API
20
- - Public product target of 100% backwards compatibility with Inovua Community
12
+ - Familiar Inovua Community 5.10.2 naming and behavior for easier migrations.
13
+ - Virtualized rows and columns for large datasets.
14
+ - Local and remote sorting, filtering, pagination, selection, and editing.
15
+ - Resizable, reorderable, hideable, nested, and responsive columns.
16
+ - Optional search, column controls, CSV/JSON/XLSX export, and mobile layout.
17
+ - Packaged styles with shadcn-compatible tokens—Tailwind and shadcn are not
18
+ required in consumer apps.
21
19
 
22
- ## Inovua compatibility
23
-
24
- the-datagrid targets **100% backwards compatibility** with the documented
25
- public API and observable behavior of
26
- [`@inovua/reactdatagrid-community@5.10.2`](https://www.npmjs.com/package/@inovua/reactdatagrid-community/v/5.10.2).
27
- After changing the package dependency and import specifier, public
28
- Inovua-shaped application business logic should not require a rewrite.
29
-
30
- The audited Community 5.10.2 release gate is implemented and backed by
31
- type, runtime, browser, packed-package, and performance tests. Compatibility
32
- covers more than similarly named TypeScript fields: it includes defaults,
33
- runtime behavior, callback payloads and timing, controlled/uncontrolled state,
34
- local and remote data flow, layout, keyboard and focus interaction, and
35
- accessibility behavior.
36
-
37
- The Issue 17 and Issue 31–45 compatibility batches implement and
38
- regression-test:
39
-
40
- - Inovua's `idProperty`, theme, row/filter height, text-selection, filter-menu,
41
- and column-menu defaults;
42
- - tri-state filter-row inference and the upstream controlled/uncontrolled local
43
- transformation split;
44
- - root class/style and focus, blur, and keyboard lifecycle handlers; and
45
- - packed-package compatibility across React 16.8, 17, 18, and 19;
46
- - natural and per-row height (`rowHeight={null}`, a `rowHeight` function,
47
- `minRowHeight`/`maxRowHeight`, and width-change remeasurement);
48
- - `onColumnResize`, controlled `width`, and uncontrolled `defaultWidth`;
49
- - weighted `flex`/`defaultFlex` remaining-space allocation;
50
- - visible zebra rows by default and the per-grid `showZebraRows` toggle;
51
- - inline editing (`editable`, `editStartEvent`, column editors, lifecycle
52
- callbacks, cancellation, focus, and keyboard navigation);
53
- - object- or function-valued whole-row `rowStyle`.
54
- - stacked and nested column groups, custom group headers, split/rejoin
55
- reordering, controlled group moves, proportional group resizing, and
56
- horizontal-virtualization geometry;
57
- - the standalone
58
- `@geovi/the-datagrid/packages/TextInput` compatibility entry, including its
59
- value-first callbacks, clear tool, legacy class hooks, and imperative ref;
60
- - the `onDidMount` computed-props lifecycle callback; and
61
- - `getVirtualList().adjustHeights()` for instantiated variable-height rows in
62
- virtual and non-virtual layouts.
63
-
64
- This closes the audited Community gate. The
65
- [source release ledger](docs/inovua-community-5.10.2-compatibility.md) maps
66
- every child issue to executable evidence, and
67
- [`community-api-manifest.json`](community-api-manifest.json) records the
68
- behavior-backed computed API, plugins, types, and Enterprise exclusions.
69
- Unknown computed method names are absent instead of being fabricated as no-op
70
- functions. Any future mismatch is a compatibility regression and must be
71
- tracked with executable coverage.
72
-
73
- Issue 48 explicitly adopts Inovua's standalone `TextInput` toolkit path. Migrate
74
- its default import to `@geovi/the-datagrid/packages/TextInput`; the package also
75
- provides a named root export. The deep entry and its class-instance TypeScript
76
- shape are now part of the compatibility contract.
77
-
78
- Read the public
79
- [compatibility contract](https://geo-vi.github.io/the-datagrid/docs/migration/inovua-compat)
80
- and the
81
- [living implementation-status ledger](https://geo-vi.github.io/the-datagrid/docs/migration/inovua-status)
82
- before treating the current package as a drop-in runtime replacement.
83
-
84
- ## Implemented today
85
-
86
- The following inventory describes behavior that ships in the current package.
87
- The public docs contain the full
88
- [source-backed implemented-surface reference](https://geo-vi.github.io/the-datagrid/docs/reference/implemented-surface),
89
- including exact defaults, timing, transform order, exports, and imperative
90
- method allowlists.
91
-
92
- - **Data loading:** local arrays, static Promises, and function-backed sources
93
- returning either an array or `{ data, count }`. Function sources
94
- receive `sortInfo`, `filterValue`, `columnOrder`, `columns`, `idProperty`, and
95
- `theme`, plus `skip`/`limit` when remote pagination is active and the optional
96
- `searchValue` when connected to the search entry. Function args also include
97
- an optional, non-enumerable `AbortSignal`; replacement requests abort the
98
- prior signal without changing the established enumerable request keys, and
99
- stale async responses are ignored even when a source does not honor it.
100
- Rejections preserve the last committed rows and clear their automatic loading
101
- state. `loading`, `loadingText`, `renderLoadMask`, and `onLoadingChange`
102
- expose the effective lifecycle without unmounting replacement rows.
103
- - **Local and remote data flow:** local arrays own local pagination. With
104
- `pagination={true}`, every Promise/function result is an authoritative remote
105
- page and is never sliced a second time. `pagination="local"` opts a
106
- Promise/function source into local slicing; bare Promise arrays can also be
107
- searched, filtered, and sorted when pagination is disabled or explicitly
108
- local.
109
- `filteredRowsCount` reports the post-search, post-filter count before local
110
- page slicing.
111
- - **Columns and cells:** stable `id`/`name` identity, controlled rendered order,
112
- callback-driven drag reordering, explicit visibility, custom headers and cell
113
- renderers, per-column sorting/filtering/search configuration, alignment, cell
114
- classes/styles, and header props. Root `groups`, `column.group`, and nested
115
- `groups[].group` render accessible stacked headers with automatic split/rejoin
116
- segments, block dragging, and proportional min/max-clamped resizing.
117
- - **Column and row sizing:** controlled `width`/`flex`, uncontrolled
118
- `defaultWidth`/`defaultFlex`, `minWidth`/`maxWidth` clamps, proportional flex
119
- allocation, the upstream 40px implicit column minimum (while preserving an
120
- explicit `minWidth={0}`), deterministic autosizing from a bounded row sample,
121
- mouse/pen/touch drag resizing with `onColumnResize`, opt-in
122
- animation-frame-coalesced `liveColumnResize`, and double-click autosizing.
123
- Rows support numeric, functional, and natural measured heights with
124
- minimum/maximum bounds and width-change remeasurement.
125
- - **Filtering and sorting:** inferred or explicitly controlled filter-row
126
- visibility, uncontrolled local filters, externally owned controlled filter
127
- state, custom filter registries and editors, filter operator menus, single
128
- sorting, persistent array-valued multi-sorting, custom comparator registries
129
- and sort tools, configurable initial direction, optional unsorting, and
130
- configurable scroll reset behavior. Filter and sort changes reset pagination
131
- to the first page.
132
- - **Pagination:** controlled or uncontrolled `skip` and `limit`, local and remote
133
- modes, configurable page sizes, a built-in accessible pager, an
134
- Inovua-shaped `renderPaginationToolbar` contract, and reload/refresh/page
135
- navigation helpers.
136
- - **Selection:** single or multi-row selection, a configurable checkbox column,
137
- controlled or uncontrolled selection maps, checkbox-only row selection,
138
- Shift-range checkbox selection, and custom checkbox rendering.
139
- - **Rendering modes:** fixed, per-row, or natural measured desktop row
140
- virtualization, a non-virtual table path, sticky header and filter rows, and
141
- an opt-in responsive virtual card layout at viewport widths up to 1024px. The
142
- mobile layout retains cell renderers and selection while providing search,
143
- sorting, and a hideable-column picker.
144
- - **Row appearance and editing:** visible default zebra striping with a per-grid
145
- toggle, data-dependent row styling, default/custom inline editors, click or
146
- double-click activation, sync/async column editability, session-safe async
147
- completion, cancellation, and keyboard traversal. Custom editors receive the
148
- Inovua-shaped editor/cell contract, and the imperative API can start, inspect,
149
- complete, or cancel an edit. Completing an edit reports the value;
150
- applications remain responsible for persisting it to their data source. The
151
- mobile card transform stays disabled whenever root or column-level editing is
152
- enabled so the editing surface is never silently replaced.
153
- - **Optional global search:** a separate tree-shakeable provider/bar/target
154
- entry, normalized AND matching, column-scoped queries and aliases, nested or
155
- derived search values, hidden-column search, a lazy cached local index, static
156
- Promise search, and `searchValue` forwarding for remote functions.
157
- - **Optional toolbar:** a separate provider/toolbar/target entry that
158
- follows live grid order and visibility, honors non-hideable columns, protects
159
- the final visible column, and accepts application actions on the right.
160
- - **Themes and UI:** packaged CSS, shadcn-aligned controls, fixed
161
- `default-light`/`light`, adaptive `default`, and fixed `dark` token bases,
162
- custom `data-theme` hooks, grid-scoped menu portals, cell-border modes, i18n
163
- overrides, and compatibility class hooks for existing Inovua-oriented theme
164
- styles.
165
- - **Imperative compatibility API:** `onDidMount`, `handle`, and `onReady`
166
- expose the same stable `TypeComputedProps` ref with implemented data,
167
- pagination, filtering, sorting, column lookup/order/visibility, selection, DOM
168
- lookup, scrolling, loading, header/filter visibility, localization, editing,
169
- and virtual-list helpers. `onDidMount` runs first from the passive mount
170
- lifecycle; `getVirtualList().adjustHeights()` reads the instantiated
171
- variable-height rows' DOM `scrollHeight` without registering extra resize
172
- observers.
173
- The editing subset includes `startEdit`, `tryStartEdit`, `completeEdit`,
174
- `cancelEdit`, `getCurrentEditInfo`, `isInEdit`, and
175
- `currentEditCompletePromise`. The API is explicit and behavior-backed;
176
- unknown method-like properties resolve to `undefined`.
177
-
178
- ### Migration: data-transform ownership
179
-
180
- This release makes one component responsible for each sort/page transform:
181
-
182
- - A controlled `sortInfo` supplies indicators and callback/request state but
183
- does not reorder a local array. Use `defaultSortInfo` for grid-owned local
184
- sorting, or sort the rows in the parent before passing them to `dataSource`.
185
- - With `pagination={true}` or `"remote"`, static Promise arrays and
186
- `Promise<{ data, count }>` values are authoritative remote pages and are not
187
- sliced a second time.
188
- - Set `pagination="local"` to opt a Promise result into local slicing. Bare
189
- Promise arrays also retain local search/filter/sort composition when
190
- pagination is disabled.
191
-
192
- These are intentional compatibility changes for consumers that relied on the
193
- previous implicit transforms. They align the grid with React controlled-state
194
- ownership, TanStack manual sorting/pagination, and Inovua 5.10.2. See the
195
- [source-backed architecture evaluation](docs/inovua-parity-issues-32-37.md#architecture-evaluation-one-owner-per-transform)
196
- for rationale and migration examples.
197
-
198
- ### Public package entries and exports
199
-
200
- The main entry, `@geovi/the-datagrid`, exports:
201
-
202
- - default and named `ReactDataGrid`, plus executable descriptors for the
203
- built-in sorting, filtering, menu, and cell-selection plugins;
204
- - `BoolEditor`, `DateEditor`, `NumericEditor`, `StringFilter`, `BoolFilter`,
205
- `DateFilter`, `NumberFilter`, `SelectFilter`, `CheckBox`, and the named
206
- `TextInput`;
207
- - `DEFAULT_FILTER_TYPES` and its `filterTypes` alias;
208
- - the public types `CellProps`, `IColumn`, `SortDirection`, `TypeColumn`,
209
- `TypeColumns`, `TypeColumnEditorProps`, `TypeColumnResizeContext`,
210
- `TypeColumnResizeInfo`, `TypeColumnEditorCell`, `TypeComputedColumn`,
211
- `TypeComputedColumnsMap`, `TypeComputedProps`, `TypeDataGridProps`,
212
- `TypeColumnGroup`, `TypeColumnGroupDOMProps`,
213
- `TypeColumnGroupHeaderProps`, `TypeDataSourceArgs`, `TypeDataSource`,
214
- `TypeDataSourceResult`,
215
- `TypePaginationProps`, `TypeLoadMaskProps`, `TypeEditInfo`, `TypeStartEditArgs`,
216
- `TypeTryStartEditArgs`, `TypeCompleteEditArgs`, `TypeCancelEditArgs`,
217
- `TypeFilterOperator`, `TypeFilterType`, `TypeFilterTypes`, `TypeFilterValue`,
218
- `TypeGetColumnByParam`, `TypeI18n`, `TypeOnSelectionChangeArg`,
219
- `TypePaginationMode`, `TypeRowSelection`, `TypeRowStyle`, `TypeRowStyleArgs`,
220
- `TypeRowStyleProps`, `TypeShowCellBorders`, `TypeSize`, `TypeSingleFilterValue`,
221
- `TypeSingleSortInfo`, `TypeSortInfo`, `TypeSortFunction`,
222
- `TypeSortFunctions`, `TypeColumnSort`, `TypeSortToolProps`,
223
- `TypeRenderSortTool`, `TypeCheckboxColumn`, `TypeCheckboxProps`,
224
- `TextInputProps`, `TypeTextInputProps`, and the TextInput
225
- callback/input/wrapper/clear-button helper types.
226
-
227
- The same editors and filters are available through their documented deep
228
- imports. `@geovi/the-datagrid/types` and the documented
229
- `@geovi/the-datagrid/types/Type*` paths expose the migration type vocabulary.
230
- The main and Community compatibility entries publish both ESM and CommonJS.
231
-
232
- The optional `@geovi/the-datagrid/search` entry exports `RDGSearchProvider`,
233
- `RDGSearchBar`, `RDGSearchTarget`, and their prop types. The explicit stylesheet
234
- fallbacks include `@geovi/the-datagrid/index.css`,
235
- `@geovi/the-datagrid/base.css`, every documented default/amber/blue/green/pink
236
- light/dark theme path, and `@geovi/the-datagrid/search/style.css`.
237
-
238
- The optional `@geovi/the-datagrid/components` entry is the one-import choice for
239
- mixed contextual controls. It exports `RDGProvider`, `RDGTarget`,
240
- `RDGSearchBar`, `RDGToolbar`, all four stable feature-specific
241
- provider/target APIs, and their prop types. It reuses the existing search and
242
- toolbar singleton contexts and automatically loads both isolated
243
- stylesheets; there is intentionally no duplicate `components/style.css`.
244
-
245
- The optional `@geovi/the-datagrid/toolbar` entry exports
246
- `RDGToolbarProvider`, `RDGToolbar`, `RDGToolbarTarget`, and their prop types.
247
- Its explicit stylesheet fallback is
248
- `@geovi/the-datagrid/toolbar/style.css`.
249
-
250
- The Inovua-compatible standalone input remains a default class export at
251
- `@geovi/the-datagrid/packages/TextInput`. That deep entry loads the packaged
252
- standalone styles, does not load the grid runtime, and preserves `focus()` /
253
- `setValue()` instance refs.
254
-
255
- ### Runtime defaults and filter registry
256
-
257
- Both the default and named grid exports expose `ReactDataGrid.defaultProps` for
258
- Inovua-shaped integrations that inspect or extend runtime defaults. It contains
259
- the shipped theme, filtering, autosize, resize, virtualization, mobile,
260
- selection-text, border, menu, and row/header/filter-height defaults, including
261
- the default filter registry.
262
-
263
- That registry ships string operators (`contains`, `notContains`, `containsOr`,
264
- `eq`, `neq`, `empty`, `notEmpty`, `startsWith`, and `endsWith`), select
265
- operators (`inlist`, `notinlist`, `eq`, and `neq`), boolean equality operators,
266
- number comparison/range operators, and date/time comparison/range operators.
267
- Operator definitions can opt into empty-value filtering, initialize a value
268
- when selected, or disable the editor for value-free operations.
269
-
270
- Unseeded `bool` and `boolean` filters default to `eq`, matching their shipped
271
- operator registry. Other defaults are `contains` for strings, `gte` for
272
- numbers, `eq` for selects, and `afterOrOn` for date/time values.
273
-
274
- Custom filter types are shallow-merged by registry key with the built-ins:
275
-
276
- ```tsx
277
- import ReactDataGrid, { type TypeFilterTypes } from "@geovi/the-datagrid";
278
-
279
- const filterTypes: TypeFilterTypes = {
280
- ...ReactDataGrid.defaultProps.filterTypes,
281
- status: {
282
- type: "status",
283
- emptyValue: null,
284
- operators: [
285
- {
286
- name: "eq",
287
- fn: ({ value, filterValue }) =>
288
- filterValue == null || value === filterValue,
289
- },
290
- ],
291
- },
292
- };
293
- ```
294
-
295
- ## Installation
20
+ ## Install
296
21
 
297
22
  ```bash
298
23
  npm install @geovi/the-datagrid react react-dom
299
- # or
300
- yarn add @geovi/the-datagrid react react-dom
301
- # or
302
- pnpm add @geovi/the-datagrid react react-dom
303
24
  ```
304
25
 
305
- That is the normal installation flow for consumers.
306
-
307
- The peer contract supports React and React DOM 16.8, 17, 18, and 19. The
308
- published-package compatibility matrix installs the packed tarball against an
309
- exact version from every supported major, compiles its declarations, and mounts
310
- the core grid, optional providers, mobile layout, and menu interactions. React
311
- 16/17 use the package's official external-store shim and compatibility fallbacks
312
- for newer React hooks.
313
-
314
- The shipped JavaScript already bundles the tested Radix, TanStack, icon, and
315
- utility implementations, so consumers do not install a second, independently
316
- resolved UI dependency graph. Those packages remain development dependencies
317
- for building the library; the official external-store shim is the only runtime
318
- dependency in the published manifest.
319
-
320
- You do **not** need to install:
321
-
322
- - Tailwind CSS
323
- - shadcn/ui
324
- - a separate package stylesheet import in normal app setups
325
-
326
- This also applies when you use custom grid themes. The grid theme variables are plain CSS variables in the shipped stylesheet, so consumers do not need Tailwind just to use `theme="dark"`, `theme="hf-dark"`, or their own imported grid theme CSS.
327
-
328
- ## Styling
329
-
330
- `@geovi/the-datagrid` ships compiled CSS and loads it automatically from the package entry.
331
-
332
- In a typical React app with a modern bundler, this is enough:
333
-
334
- - Vite
335
- - Next.js
336
- - Webpack-based apps
337
- - other setups that support CSS imports from npm packages
338
-
339
- The grid keeps a shadcn-aligned look and uses the same token vocabulary
340
- (`--background`, `--foreground`, `--border`, `--ring`, etc.). The adaptive
341
- `theme="default"` inherits those app-level variables, while fixed theme bases
342
- and explicit `--tdg-*` custom-theme tokens stay scoped to the grid. Packaged
343
- fallbacks keep the grid usable when an app does not define shadcn variables.
344
-
345
- Theme variables are resolved at runtime from normal CSS, not from the consumer's Tailwind build. Tailwind is only used to build this library, not required to consume it.
346
-
347
- Built-in theme behavior:
348
-
349
- - `theme="default-light"` is the default and keeps a fixed shadcn light token
350
- base—even below a `.dark` application ancestor—while preserving the
351
- Inovua-compatible theme name on the grid root
352
- - `theme="default"` follows the nearest `.dark` ancestor
353
- - `theme="light"` forces the light token set
354
- - `theme="dark"` forces the dark token set
355
- - `theme="<custom-name>"` activates a named custom theme on the grid root via `data-theme="<custom-name>"`
356
-
357
- The fixed light base remains customizable through the documented
358
- `--tdg-color-*` and component-level `--tdg-*` variables. A custom named theme
359
- can therefore opt into a `-light` suffix without losing its own explicit grid
360
- tokens.
361
-
362
- For non-built-in theme names, the grid also keeps Inovua-compatible root and
363
- element class hooks. When a readable legacy Inovua stylesheet for that theme is
364
- already loaded, the runtime maps its grid, text-input, combo-box, and menu
365
- colors into the corresponding `--tdg-*` tokens. This bridge helps existing
366
- themes migrate incrementally; it is browser-only, ignores unreadable or
367
- late-loaded stylesheets, and does not reproduce legacy layout CSS. Defining the
368
- grid tokens directly remains the deterministic long-term path.
369
-
370
- If your environment does **not** process CSS imported from package entries, use the exported fallback once in your app:
371
-
372
- ```ts
373
- import "@geovi/the-datagrid/style.css";
374
- ```
375
-
376
- ### Custom named themes
377
-
378
- Named themes are configured with CSS variables on the grid root selector. For example, this custom `hf-dark` theme can be used with `theme="hf-dark"`:
379
-
380
- ```css
381
- .tdg-root[data-theme="hf-dark"] {
382
- --tdg-color-background: #191919;
383
- --tdg-color-foreground: #e5e5e5;
384
- --tdg-color-accent: #26324a;
385
- --tdg-grid-bg: #191919;
386
- --tdg-header-bg: #1e1e1e;
387
- --tdg-grid-border-color: #2c2c2c;
388
- --tdg-cell-border-color: #2c2c2c;
389
- --tdg-header-border-color: #2c2c2c;
390
- --tdg-row-odd-bg: #191919;
391
- --tdg-row-even-bg: #191919;
392
- --tdg-row-odd-hover-bg: #26324a;
393
- --tdg-row-even-hover-bg: #26324a;
394
- --tdg-row-selected-bg: #1a2740;
395
- --tdg-row-selected-hover-bg: #1a2740;
396
- --tdg-input-bg: #191919;
397
- --tdg-input-border-color: #383838;
398
- --tdg-input-border-color-hover: #383838;
399
- --tdg-input-border-color-focus: #383838;
400
- --tdg-select-bg: #191919;
401
- --tdg-select-list-bg: #191919;
402
- --tdg-select-border-color: #383838;
403
- --tdg-select-border-color-hover: #383838;
404
- --tdg-select-border-color-focus: #383838;
405
- --tdg-select-item-hover-bg: #26324a;
406
- --tdg-select-item-selected-bg: #26324a;
407
- --tdg-checkbox-checked-bg: #688ad7;
408
- --tdg-checkbox-checked-color: #e5e5e5;
409
- --tdg-checkbox-indeterminate-bg: #688ad7;
410
- color-scheme: dark;
411
- }
412
- ```
413
-
414
- This lets you keep using a migration-friendly theme name such as `hf-dark` while mapping it to the grid’s internal theme tokens.
415
-
416
- The example assigns identical odd/even row colors, which intentionally
417
- suppresses visible striping for that custom theme. Built-in themes show zebra
418
- rows by default; `showZebraRows={false}` disables them for one grid, while
419
- `--tdg-row-odd-bg` and `--tdg-row-even-bg` customize their theme colors.
420
-
421
- ---
26
+ React 16.8 through 19 is supported. Package styles load automatically in modern
27
+ bundlers.
422
28
 
423
- ## Basic usage
29
+ ## Quick start
424
30
 
425
31
  ```tsx
426
- import { ReactDataGrid } from "@geovi/the-datagrid";
427
- import type { TypeColumns } from "@geovi/the-datagrid";
32
+ import ReactDataGrid, { type TypeColumns } from "@geovi/the-datagrid";
428
33
 
429
- export default function App() {
430
- const columns: TypeColumns = [
431
- { name: "id", header: "ID", sortable: true, filterable: true },
432
- { name: "name", header: "Name", sortable: true, filterable: true },
433
- { name: "email", header: "Email", sortable: true, filterable: true },
434
- ];
435
-
436
- const rows = [
437
- { id: 1, name: "John Doe", email: "john@example.com" },
438
- { id: 2, name: "Jane Smith", email: "jane@example.com" },
439
- ];
440
-
441
- return (
442
- <ReactDataGrid
443
- idProperty="id"
444
- columns={columns}
445
- dataSource={rows}
446
- virtualized
447
- enableFiltering
448
- defaultFilterValue={[
449
- { name: "id", type: "number", operator: "eq", value: null },
450
- { name: "name", type: "string", operator: "contains", value: "" },
451
- { name: "email", type: "string", operator: "contains", value: "" },
452
- ]}
453
- />
454
- );
455
- }
456
- ```
457
-
458
- ## Combined contextual controls
459
-
460
- Use one `RDGProvider` when search and the toolbar control the same grid.
461
- A direct grid child connects automatically:
462
-
463
- ```tsx
464
- import ReactDataGrid from "@geovi/the-datagrid";
465
- import {
466
- RDGToolbar,
467
- RDGProvider,
468
- RDGSearchBar,
469
- } from "@geovi/the-datagrid/components";
470
-
471
- <RDGProvider>
472
- <RDGSearchBar />
473
- <RDGToolbar showExport showFilterToggle />
474
- <ReactDataGrid idProperty="id" columns={columns} dataSource={rows} />
475
- </RDGProvider>;
476
- ```
477
-
478
- If a `div`, card, Fragment, Suspense boundary, or application component sits
479
- between the provider and grid, put one `RDGTarget` immediately around the grid.
480
- `RDGProvider` and `RDGTarget` add no DOM elements and support one grid per
481
- provider scope. Use `defaultSearchValue` when the shared search query needs a
482
- non-empty initial value. Do not nest `RDGSearchTarget` and
483
- `RDGToolbarTarget`; use the combined target instead.
484
-
485
- Controls imported from `@geovi/the-datagrid/search` and
486
- `@geovi/the-datagrid/toolbar` also work inside `RDGProvider`. The
487
- existing `RDGSearchProvider`, `RDGSearchTarget`,
488
- `RDGToolbarProvider`, and `RDGToolbarTarget` exports remain
489
- supported and are not deprecated.
490
-
491
- ## Optional table search
492
-
493
- Global search is intentionally separate from the main component entry. A plain
494
- `ReactDataGrid` does not render a search control, subscribe to search context,
495
- or load the optional provider, store, or search stylesheet. The optional entry
496
- reuses the same core search field and search engine already used by the mobile
497
- layout, so search-enabled screens do not ship a second implementation. Import
498
- the provider and bar only on screens that need them:
34
+ const columns: TypeColumns = [
35
+ { name: "id", header: "ID", sortable: true },
36
+ { name: "name", header: "Name", sortable: true, filterable: true },
37
+ { name: "email", header: "Email", filterable: true },
38
+ ];
499
39
 
500
- ```tsx
501
- import ReactDataGrid from "@geovi/the-datagrid";
502
- import { RDGSearchBar, RDGSearchProvider } from "@geovi/the-datagrid/search";
40
+ const rows = [
41
+ { id: 1, name: "Ada Lovelace", email: "ada@example.com" },
42
+ { id: 2, name: "Grace Hopper", email: "grace@example.com" },
43
+ ];
503
44
 
504
- export function SearchableAccountsGrid() {
45
+ export function UsersGrid() {
505
46
  return (
506
- <RDGSearchProvider>
507
- <RDGSearchBar />
47
+ <div style={{ height: 480 }}>
508
48
  <ReactDataGrid
509
49
  idProperty="id"
510
50
  columns={columns}
511
51
  dataSource={rows}
52
+ enableFiltering
512
53
  virtualized
513
54
  />
514
- </RDGSearchProvider>
55
+ </div>
515
56
  );
516
57
  }
517
58
  ```
518
59
 
519
- The provider automatically connects marked `ReactDataGrid` elements that are
520
- its direct children. If layout markup needs to sit between the provider and the
521
- grid, mark the grid explicitly:
60
+ ## Search and toolbar
61
+
62
+ The optional components entry adds search, column visibility, filters, and
63
+ export without increasing the core grid API:
522
64
 
523
65
  ```tsx
524
66
  import {
67
+ RDGProvider,
525
68
  RDGSearchBar,
526
- RDGSearchProvider,
527
- RDGSearchTarget,
528
- } from "@geovi/the-datagrid/search";
69
+ RDGToolbar,
70
+ } from "@geovi/the-datagrid/components";
529
71
 
530
- <RDGSearchProvider>
72
+ <RDGProvider>
531
73
  <RDGSearchBar />
532
- <section className="min-h-0 flex-1">
533
- <RDGSearchTarget>
534
- <ReactDataGrid idProperty="id" columns={columns} dataSource={rows} />
535
- </RDGSearchTarget>
536
- </section>
537
- </RDGSearchProvider>;
538
- ```
539
-
540
- See [Providers and targets](https://geo-vi.github.io/the-datagrid/docs/reference/providers-and-targets)
541
- for the exact direct-child rule, Fragment and Suspense boundaries, and
542
- multiple-grid scoping.
543
-
544
- The normal-table bar and transformed-mobile search are two placements of the
545
- same internal component. They use the same shadcn-style Input and Button,
546
- column-prefix highlighting, IME handling, Escape behavior, and clear/refocus
547
- interaction. Local arrays and bare Promise snapshots under disabled/explicitly
548
- local pagination also use the same normalization and matching engine. Function
549
- data sources receive the committed `searchValue` and remain responsible for
550
- remote matching. When
551
- `allowMobileTransform` is active under `RDGSearchProvider`, the external
552
- placement remains the single search control; the mobile list suppresses only
553
- its duplicate placement while keeping its sort and column tools.
554
-
555
- `RDGSearchBar` uses the accessible label `Search all fields`, the placeholder
556
- `Search all fields`, and a 150 ms provider commit debounce by default. Set
557
- `debounceMs={0}` for an immediate remote/local commit or pass another delay.
558
- The input interaction itself is shared with mobile. Terms are matched with AND
559
- semantics after case, whitespace, and diacritic normalization. Prefix a query
560
- with a column id, name, string header, or configured alias to scope it, for
561
- example `city:paris`.
562
-
563
- Column-level search configuration stays on `TypeColumn` rather than adding new
564
- `ReactDataGrid` props. Configured columns remain searchable when hidden; use
565
- `searchable: false` for an explicit exclusion:
566
-
567
- ```tsx
568
- const columns: TypeColumns = [
569
- {
570
- name: "city",
571
- header: "Office city",
572
- searchAliases: ["location", "office"],
573
- },
574
- {
575
- name: "customer",
576
- searchValue: (row) => [row.customer.name, row.customer.reference],
577
- },
578
- { name: "internalNote", searchable: false },
579
- ];
580
- ```
581
-
582
- For local data, the normalized search index is built lazily on the first
583
- committed query and reused while the row and column arrays keep the same
584
- identity. Update rows and column configuration immutably so changed searchable
585
- content naturally invalidates that cache.
586
-
587
- The optional entry loads its own scoped stylesheet. If your environment does
588
- not process package CSS imports, add
589
- `import "@geovi/the-datagrid/search/style.css"` beside the manual grid
590
- stylesheet import.
591
-
592
- For local arrays, search is combined with column filters before local
593
- pagination and `filteredRowsCount` reports the combined result count. A bare
594
- static Promise array is locally searchable when pagination is disabled or
595
- explicitly `"local"`. With `pagination={true}`/`"remote"`, either Promise
596
- result shape is authoritative and is not post-filtered or sliced. A function
597
- data source remains remote and receives `searchValue` alongside its existing
598
- args; when remote pagination is active, a new search resets `skip` to `0`.
599
-
600
- ```tsx
601
- import type { TypeDataSourceArgs } from "@geovi/the-datagrid";
602
-
603
- const dataSource = async ({
604
- searchValue,
605
- signal,
606
- ...gridArgs
607
- }: TypeDataSourceArgs) => {
608
- const response = await fetch("/api/accounts/search", {
609
- method: "POST",
610
- headers: { "content-type": "application/json" },
611
- body: JSON.stringify({ ...gridArgs, searchValue }),
612
- signal,
613
- });
614
-
615
- return response.json();
616
- };
617
- ```
618
-
619
- Remote functions own the search operation. The grid does not post-filter one
620
- remote page and present it as a server-wide result. If the backend does not yet
621
- support global search, keep that search state application-owned until its
622
- request contract is defined.
623
-
624
- ## Optional grid toolbar
625
-
626
- Grid toolbar controls are also an opt-in contextual entry. A direct grid child
627
- connects automatically. Column toggles always render; export, filter-row and
628
- clear-filter buttons are opt-in props, and toolbar children stay a separate
629
- right-side action area for consumer-owned controls:
630
-
631
- ```tsx
632
- import ReactDataGrid from "@geovi/the-datagrid";
633
- import { RDGToolbarProvider, RDGToolbar } from "@geovi/the-datagrid/toolbar";
634
-
635
- <RDGToolbarProvider>
636
- <RDGToolbar showExport showFilterToggle showClearFilters>
637
- <button type="button" onClick={reload}>
638
- Reload
639
- </button>
640
- </RDGToolbar>
74
+ <RDGToolbar showExport showFilterToggle showClearFilters />
641
75
  <ReactDataGrid idProperty="id" columns={columns} dataSource={rows} />
642
- </RDGToolbarProvider>;
76
+ </RDGProvider>;
643
77
  ```
644
78
 
645
- `showExport` writes the grid's current columns, in grid order, as CSV, JSON or
646
- XLSX. Spreadsheet output needs the optional `xlsx` peer dependency:
79
+ Install `xlsx` only when workbook export is needed:
647
80
 
648
81
  ```bash
649
82
  npm install xlsx
650
83
  ```
651
84
 
652
- It is left out of `exportFormats` by default, since its writer is many times the
653
- size of the toolbar entry, and it is imported on demand the first time somebody
654
- exports a workbook. Values keep their JavaScript type on the way into a
655
- workbook, so numbers stay summable, `Date` values become date cells carrying
656
- `exportDateFormat`, and booleans become `TRUE`/`FALSE`; text formats stringify
657
- the same values and write dates as ISO-8601. `exportDateFormat` is an Excel
658
- number format code rather than a date-library pattern, `exportSheetName` names
659
- the worksheet, and the two callbacks report the outcome: `onExportSuccess`
660
- receives the format, scope, row and column counts, file name and byte size,
661
- which is enough for a confirmation toast, while `onExportError` reports a
662
- failure such as a missing peer dependency.
663
-
664
- `exportScope` selects the rows: `"view"` (default) exports the filtered,
665
- searched and sorted rows, `"all"` the entire data source. Under local pagination
666
- the grid holds a single page, so `"view"` exports that page. `exportFormats`,
667
- `exportFileName` and `labels` cover the rest; with exactly one format the button
668
- exports on click instead of opening a menu.
669
-
670
- Every string the toolbar renders itself comes from `labels`, as a string or an
671
- element, so a translation helper can supply all of them:
672
-
673
- ```tsx
674
- <RDGToolbar
675
- showExport
676
- showFilterToggle
677
- showClearFilters
678
- labels={{
679
- export: t("export"),
680
- showFilters: t("show_filters"),
681
- hideFilters: t("hide_filters"),
682
- clearFilters: t("clear_filters"),
683
- columns: t("columns"),
684
-
685
- // Menu entry per format; an unnamed format keeps its own name.
686
- exportFormats: { csv: t("csv"), xlsx: t("excel") },
687
-
688
- // Whole button text when one format is offered. The default joins
689
- // `export` and the format name in that order ("Export CSV"), which a
690
- // translation file cannot reorder - set this for "CSV exportieren".
691
- exportSingle: { csv: t("export_csv") },
692
- }}
693
- />
694
- ```
695
-
696
- `title`, `description` and `ariaLabel` are separate props and take the same
697
- treatment; column toggles read each column's `header`. The export menu is named
698
- after its own trigger, so a translated label needs no second string.
699
-
700
- At widths up to `1024px`, the toolbar automatically replaces the wrapping row
701
- of column buttons with one `Columns` dropdown. The menu contains the same
702
- hideable columns in grid order, stays open while several columns are toggled,
703
- and keeps the rule that the final visible column cannot be hidden. Set
704
- `toolbarCollapsedColumnToggles` to force the dropdown at every width, or set
705
- `disableMobileAutoToolbarCollapsedColumns` to keep the buttons inline on
706
- mobile. Override `labels.columns` to localize the trigger:
707
-
708
- ```tsx
709
- <RDGToolbar toolbarCollapsedColumnToggles labels={{ columns: t("columns") }} />
710
-
711
- <RDGToolbar disableMobileAutoToolbarCollapsedColumns />
712
- ```
713
-
714
- Set `collapsible` when a dense screen should show only one right-aligned control
715
- until the toolbar is needed. The card surface, border, shadow and spacing collapse
716
- fully into that disclosure button, then expand left and down from it; column,
717
- filter and export state remain mounted while it is closed. Override
718
- `labels.showToolbar` and
719
- `labels.hideToolbar` to localize the disclosure:
720
-
721
- ```tsx
722
- <RDGToolbar
723
- collapsible
724
- showExport
725
- showFilterToggle
726
- showClearFilters
727
- labels={{
728
- showToolbar: t("show_table_controls"),
729
- hideToolbar: t("hide_table_controls"),
730
- }}
731
- />
732
- ```
733
-
734
- Export reads row values, never `render`, which returns React nodes. Columns
735
- describe their own exported shape:
736
-
737
- ```tsx
738
- const columns: TypeColumns = [
739
- { name: "id", header: "ID" },
740
-
741
- // render returns a React node, so export needs its own value.
742
- {
743
- name: "active",
744
- header: "Active",
745
- render: ({ value }) => <StatusPill active={value} />,
746
- exportValue: ({ value }) => (value ? "Yes" : "No"),
747
- },
748
-
749
- // Hidden in the grid, still written to the file.
750
- {
751
- name: "auditId",
752
- header: "Audit ID",
753
- defaultVisible: false,
754
- exportWhenHidden: true,
755
- },
756
-
757
- // Row buttons have no exportable representation.
758
- { name: "actions", header: "Actions", exportable: false },
759
- ];
760
- ```
761
-
762
- Only visible columns are exported unless a column sets `exportWhenHidden`, and
763
- `exportable: false` always wins. `showFilterToggle` drives the grid's own
764
- filter-row state, so it renders disabled while `enableFiltering` is passed as a
765
- controlled prop; `showClearFilters` calls `clearAllFilters` and stays disabled
766
- while nothing is filtered.
85
+ ## Learn more
767
86
 
768
- The toolbar renders columns in the grid's current order and reflects the live
769
- visibility map. It uses string or numeric headers with stable `id`/`name`
770
- fallbacks, omits columns with `hideable={false}`, and does not allow the final
771
- visible column to be hidden. Button state is exposed through `aria-pressed`; no
772
- eye icon or parallel application visibility state is required.
87
+ - [Examples and API documentation](https://geo-vi.github.io/the-datagrid/)
88
+ - [Inovua migration contract](https://geo-vi.github.io/the-datagrid/docs/migration/inovua-compat)
89
+ - [Implemented compatibility status](https://geo-vi.github.io/the-datagrid/docs/migration/inovua-status)
773
90
 
774
- Set controlled `visible: false`, uncontrolled `defaultVisible: false`, or the
775
- legacy `defaultHidden: true` alias on a column that should start hidden.
776
- `hideable: false` disables menu/toolbar toggles but does not block the
777
- imperative API. `onColumnVisibleChange({ column, visible })` receives every
778
- effective proposal. A declarative `visible` value remains authoritative until
779
- the parent applies that proposal; otherwise the grid persists the change in
780
- its own runtime state.
781
-
782
- The default title is a level-two heading that labels the toolbar region. The
783
- toggle group keeps its `ariaLabel`, and the description is associated with both
784
- through `aria-describedby`. Passing `title={null}` suppresses the heading while
785
- preserving the group's accessible name.
786
-
787
- ### Styling the toolbar
788
-
789
- The toolbar carries no utility classes: every visual decision is a
790
- `--tdg-toolbar-*` custom property, so restyling means redeclaring tokens on
791
- `.tdg-toolbar-root` or any ancestor.
792
-
793
- ```css
794
- .tdg-toolbar-root {
795
- --tdg-toolbar-padding: 0;
796
- --tdg-toolbar-radius: 0;
797
- --tdg-toolbar-border-width: 0;
798
- --tdg-toolbar-shadow: none;
799
-
800
- --tdg-toolbar-toggle-gap: 3px;
801
- --tdg-toolbar-control-padding: 6px 8px;
802
- --tdg-toolbar-control-radius: 4px;
803
- --tdg-toolbar-control-height: auto;
804
- --tdg-toolbar-control-cursor: pointer;
805
-
806
- /* Export and clear-filters. */
807
- --tdg-toolbar-action-fill: #eef1f5;
808
- --tdg-toolbar-action-color: #12263f;
809
-
810
- /* A released toggle, filled here rather than recessed. */
811
- --tdg-toolbar-toggle-off-fill: #eef1f5;
812
- --tdg-toolbar-toggle-off-color: #5b6b7f;
813
-
814
- /* A pressed toggle, and export while its menu is open. */
815
- --tdg-toolbar-toggle-on-fill: #1a73e8;
816
- --tdg-toolbar-toggle-on-color: #ffffff;
817
- }
818
- ```
819
-
820
- The three appearances differ by one signal each: an action keeps its border, a
821
- released toggle drops it and dims the label, a pressed toggle keeps it over an
822
- opaque `card` fill. Hover only changes the fill, so it never reads as a state.
823
-
824
- Colour tokens fall back through `--tdg-color-*` and then the shadcn variable of
825
- the same name, so a themed application inherits sensible values without setting
826
- anything. Bridging another design system - BaseUI, MUI, a styled-components
827
- theme - means assigning its values to these tokens once, on a wrapper element.
828
-
829
- A grid theme named `*-dark` or `*-light` is the exception: it states a mode, so
830
- the toolbar skips the shadcn step, which tracks the page's mode rather than the
831
- grid's. Reading it would paint a dark toolbar with the page's white `--card`. A
832
- theme named `default` states no mode and keeps following the page.
833
-
834
- Two caveats when you theme a toolbar that sits outside the grid. Theme
835
- stylesheets scope their variables to the grid root, so a sibling toolbar never
836
- sees them - declare `--tdg-color-*` on a common ancestor to share one palette.
837
- And the mode rules above are selected by attribute, so they only ever move
838
- private plumbing (`--tdg-toolbar-host-*`, `--tdg-toolbar-*-fallback`,
839
- `--tdg-toolbar-surface-backdrop`); every token in the reference is declared once
840
- at plain `.tdg-toolbar-root` specificity, so your override always wins.
841
-
842
- Plain CSS overrides work too, and never need `!important`: every default rule is
843
- written with exactly one unit of specificity, so any selector of yours that adds
844
- a second part outranks it.
845
-
846
- ```css
847
- .tdg-toolbar-root button[data-state="off"] {
848
- background-color: var(--button-secondary-fill);
849
- }
850
- ```
851
-
852
- Elements expose stable `data-slot` names (`rdg-toolbar`, `rdg-column-toggle`,
853
- `rdg-toolbar-column-toggle-trigger`, `rdg-toolbar-actions`,
854
- `rdg-toolbar-export`, `rdg-toolbar-filter-toggle`, ...), and toggles expose
855
- `data-state` as `on` or `off`. Inline toggles expose `aria-pressed`; compact-menu
856
- toggles use `menuitemcheckbox` with `aria-checked`. `RDGToolbar` also accepts
857
- `className` for scoping overrides to a class of your own. The complete token
858
- table lives in
859
- [the toolbar styling reference](https://geo-vi.github.io/the-datagrid/docs/reference/toolbar#toolbar-styling).
860
-
861
- Stacked, the toolbar places its actions above the column toggles, since a
862
- wrapping toggle list would otherwise push export and the filter controls far
863
- down the card; from `80rem` it becomes a row with toggles leading.
864
-
865
- Use `RDGToolbarTarget` around the grid when layout markup separates it
866
- from the provider. Keep one grid per provider so the column model is
867
- unambiguous. The JavaScript entry loads its scoped stylesheet automatically; if
868
- your environment requires manual CSS imports, add
869
- `import "@geovi/the-datagrid/toolbar/style.css"`.
870
-
871
- For the complete direct-child rules, nested layout examples, multiple-grid
872
- scoping, and the stability contract for all feature-specific providers and
873
- targets, see [Providers and targets](https://geo-vi.github.io/the-datagrid/docs/reference/providers-and-targets).
874
-
875
- When search and the toolbar share a grid, prefer `RDGProvider`/`RDGTarget` from
876
- `@geovi/the-datagrid/components`. The feature-specific provider and target
877
- remain supported for toolbar-only screens and existing integrations.
878
-
879
- ## Advanced usage
880
-
881
- ```tsx
882
- import { useMemo, useState } from "react";
883
- import { ReactDataGrid } from "@geovi/the-datagrid";
884
- import type {
885
- TypeColumns,
886
- TypeFilterValue,
887
- TypeI18n,
888
- TypeOnSelectionChangeArg,
889
- TypeRowSelection,
890
- } from "@geovi/the-datagrid";
891
-
892
- export default function App() {
893
- const [selected, setSelected] = useState<TypeRowSelection>({});
894
- const [columnOrder, setColumnOrder] = useState<string[]>([]);
895
-
896
- const columns: TypeColumns = useMemo(
897
- () => [
898
- { name: "id", header: "ID", sortable: true, filterable: true },
899
- { name: "name", header: "Name", sortable: true, filterable: true },
900
- { name: "email", header: "Email", sortable: true, filterable: true },
901
- ],
902
- []
903
- );
904
-
905
- const defaultFilterValue = useMemo<TypeFilterValue>(
906
- () => [
907
- { name: "id", type: "number", operator: "eq", value: null },
908
- { name: "name", type: "string", operator: "contains", value: "" },
909
- { name: "email", type: "string", operator: "contains", value: "" },
910
- ],
911
- []
912
- );
913
-
914
- const rows = useMemo(
915
- () => [
916
- { id: 1, name: "John Doe", email: "john@example.com" },
917
- { id: 2, name: "Jane Smith", email: "jane@example.com" },
918
- ],
919
- []
920
- );
921
-
922
- const i18n: TypeI18n = useMemo(
923
- () => ({
924
- noRecords: "No records",
925
- clear: "Clear",
926
- clearAll: "Clear all",
927
- enable: "Enable",
928
- disable: "Disable",
929
- filter: "Filter",
930
- operator: "Operator",
931
- contains: "Contains",
932
- sortAsc: "Sort A→Z",
933
- sortDesc: "Sort Z→A",
934
- }),
935
- []
936
- );
937
-
938
- const onSelectionChange = (config: TypeOnSelectionChangeArg) => {
939
- setSelected(config.selected);
940
- };
941
-
942
- return (
943
- <ReactDataGrid
944
- theme="default"
945
- idProperty="id"
946
- columns={columns}
947
- columnOrder={columnOrder}
948
- dataSource={rows}
949
- enableFiltering
950
- defaultFilterValue={defaultFilterValue}
951
- onFilterValueChange={(v) => console.log("Filters:", v)}
952
- filteredRowsCount={(count) => console.log("Filtered rows:", count)}
953
- enableColumnFilterContextMenu
954
- enableColumnAutosize
955
- skipHeaderOnAutoSize={false}
956
- onColumnOrderChange={setColumnOrder}
957
- virtualized
958
- columnUserSelect
959
- i18n={i18n}
960
- showColumnMenuTool={false}
961
- checkboxColumn
962
- onSelectionChange={onSelectionChange}
963
- selected={selected}
964
- />
965
- );
966
- }
967
- ```
968
-
969
- `onSelectionChange` still emits the Inovua-style config object. For migration ergonomics, the grid also accepts the emitted object back through `selected`, so `onSelectionChange={setSelectedRows}` works with the same state variable used for `selected`.
970
-
971
- ## Props (high-level)
972
-
973
- Note: this is a curated overview. For the complete contract, refer to the exported TypeScript types.
974
-
975
- ### Core
976
-
977
- | Prop | Type | Default | Description |
978
- | ------------ | ------------------- | -------- | ------------------------------------------------------------ |
979
- | `idProperty` | `string` | `"id"` | Property name used as unique row identifier; JSX may omit it |
980
- | `columns` | `TypeColumns` | required | Column definitions |
981
- | `groups` | `TypeColumnGroup[]` | `[]` | Stacked and nested column-header descriptors |
982
- | `dataSource` | `TypeDataSource` | required | Data source (array, function, or promise) |
983
-
984
- ### Display
985
-
986
- | Prop | Type | Default | Description |
987
- | ---------------------- | ------------------------------------------------ | ----------------- | ----------------------------------------------------------------- |
988
- | `theme` | `string` | `"default-light"` | Theme name |
989
- | `rowHeight` | `number \| ((rowIndex) => number) \| null` | `40` | Fixed, per-row, or naturally measured row height |
990
- | `minRowHeight` | `number` | `20` | Minimum natural row height and virtualizer estimate |
991
- | `maxRowHeight` | `number` | - | Optional upper bound for measured or functional row heights |
992
- | `rowStyle` | `CSSProperties \| ({ data, props, style }) => …` | - | Static or data-dependent style merged onto each row |
993
- | `disabledRows` | `{ [displayedIndex: string]: boolean } \| null` | - | Dim and block pointer interaction for displayed row indexes |
994
- | `showZebraRows` | `boolean` | `true` | Show visible alternating row backgrounds |
995
- | `headerHeight` | `number` | `40` | Header height in pixels |
996
- | `filterRowHeight` | `number` | `40` | Filter row height in pixels |
997
- | `virtualized` | `boolean` | `true` | Enable virtual scrolling, including measured natural rows |
998
- | `allowMobileTransform` | `boolean` | `false` | Use searchable, sortable virtual cards at widths up to 1024px |
999
- | `columnUserSelect` | `boolean \| "text" \| "none"` | `false` | Column text selection behavior |
1000
- | `showCellBorders` | `boolean \| "vertical" \| "horizontal"` | `true` | Cell separator mode; use `"horizontal"` to disable vertical lines |
1001
-
1002
- A `rowStyle` callback receives the live Inovua-shaped base style, including
1003
- `height`, `width`, `minWidth`, and LTR `direction`. It may mutate that object
1004
- and return `undefined`, or return a style object to merge. `props.id` preserves
1005
- numeric IDs, `rowIndex` is page-local, and `remoteRowIndex` includes the current
1006
- pagination offset. Locked-column indexes, presence flags, and section widths
1007
- reflect the live rendered geometry.
1008
-
1009
- `disabledRows` follows the Inovua 5.10.2 index contract. A truthy entry such as
1010
- `{ 1: true }` disables the second row in the current sorted, filtered, and
1011
- page-local view; keys are not row IDs. Disabled rows receive the legacy
1012
- `InovuaReactDataGrid__row--disabled` hook, 50% opacity, and no pointer
1013
- interaction. They are deliberately still included by controlled selection,
1014
- header select-all, and imperative selection/editing APIs, matching upstream.
1015
- The current state is also exposed as `props.disabledRow` to `rowStyle` and
1016
- custom cell metadata. That callback value preserves upstream’s raw shape:
1017
- `null` when the map is absent, `undefined` for a missing key, and the explicit
1018
- `false` or `true` entry otherwise.
1019
-
1020
- ### Columns
1021
-
1022
- | Prop | Type | Default | Description |
1023
- | -------------------------- | ------------------------------- | ------- | ------------------------------------------------------------------------------- |
1024
- | `columnOrder` | `string[]` | - | Controlled ordered array of column ids/names |
1025
- | `defaultColumnOrder` | `string[]` | columns | Initial order for grid-owned ordering |
1026
- | `onColumnOrderChange` | `(order: string[]) => void` | - | Receives reorder proposals; optional for grid-owned ordering |
1027
- | `onColumnVisibleChange` | `({ column, visible }) => void` | - | Receives controlled or uncontrolled visibility proposals |
1028
- | `reorderColumns` | `boolean` | `true` | Disable user drag reordering |
1029
- | `allowGroupSplitOnReorder` | `boolean` | `true` | Allow reordering to split one logical group into visual segments |
1030
- | `resizable` | `boolean` | `true` | Enable header resize handles |
1031
- | `columnDefaultWidth` | `number` | `150` | Root fallback when a column has no width/defaultWidth |
1032
- | `columnMinWidth` | `number` | `40` | Root fallback when a column has no minWidth |
1033
- | `columnMaxWidth` | `number \| null` | `null` | Root fallback when a column has no maxWidth |
1034
- | `shareSpaceOnResize` | `boolean` | `false` | Resize the adjacent visible column in the opposite direction |
1035
- | `columnResizeHandleWidth` | `number` | `24` | Header resize pointer-target width |
1036
- | `columnResizeProxyWidth` | `number` | `5` | Deferred resize-proxy width |
1037
- | `liveColumnResize` | `boolean` | `false` | Resize rendered geometry during drag; callbacks remain completion-only |
1038
- | `onColumnResize` | `(info, context) => void` | - | Reports each proposed width/flex and reserved viewport width |
1039
- | `onBatchColumnResize` | `(entries, context) => void` | - | Reports one coherent callback for every resize transaction |
1040
- | `enableColumnAutosize` | `boolean` | `true` | Estimate widths from a bounded row sample when no numeric width is supplied |
1041
- | `skipHeaderOnAutoSize` | `boolean` | `false` | Skip header text when estimating an automatic width |
1042
- | `showColumnMenuTool` | `boolean` | `true` | Show sort, visibility, auto-size, and fit actions in the accessible column menu |
1043
-
1044
- When `columnOrder` is omitted, `defaultColumnOrder` seeds grid-owned ordering
1045
- and drag changes persist even without a callback. When `columnOrder` is
1046
- supplied, it is authoritative: `onColumnOrderChange` receives the proposal and
1047
- the display changes only after the parent returns it. The same ownership rule
1048
- applies to `column.visible` versus `defaultVisible`/`defaultHidden`.
1049
-
1050
- Column sizing precedence is controlled `width`, column `defaultWidth` and
1051
- `minWidth`/`maxWidth`, then the root fallbacks. An uncontrolled flex column
1052
- retains flex ownership by default; set `column.keepFlex: false` to convert it to
1053
- fixed sizing after a no-share resize. Shared-space resize preserves the adjacent
1054
- pair's total width and handles fixed/fixed, flex/flex, and mixed pairs.
1055
- Controlled `width` and `flex` values remain prop-owned while both resize
1056
- callbacks receive the proposal.
1057
-
1058
- Set `column.locked` to `"start"` or `"end"` to keep it visible at that
1059
- horizontal edge; `true` is the Inovua-compatible alias for `"start"`. Locked
1060
- columns keep their relative `columnOrder` within the start/unlocked/end
1061
- sections, remain mounted during column virtualization, and use the same
1062
- header, filter-row, body, resize, and controlled-reorder geometry.
1063
-
1064
- This is an opt-in, Enterprise-derived compatibility extension rather than part
1065
- of the Inovua Community 5.10.2 release gate. The implemented contract is the
1066
- declarative `column.locked` field above. Inovua's `column.defaultLocked`,
1067
- `column.lockable`, `column.autoLock`, root `onColumnLockedChange` and
1068
- `showColumnMenuLockOptions`, imperative `setColumnLocked`, lock/unlock menu
1069
- actions, and RTL edge mirroring are not implemented. Dragging may reorder
1070
- columns inside the same locked/unlocked section, but a cross-section drop is
1071
- rejected instead of changing the column's locked state. Declare the target
1072
- section in the column definition up front; changing a column's locked section
1073
- at runtime is not a supported contract yet.
1074
- The grid groups columns only for rendering: the controlled `columnOrder` and
1075
- remote data-source argument keep the application-owned sequence, with lock
1076
- state carried separately by each column. Computed locked-section widths report
1077
- the grid's logical column allocation; when an underfilled fixed-layout table is
1078
- stretched to the viewport, browser-distributed surplus space is not added to
1079
- those compatibility metrics.
1080
-
1081
- ### Filtering
1082
-
1083
- | Prop | Type | Default | Description |
1084
- | --------------------------------------- | ---------------------------------------------- | ------------------ | --------------------------------------------------------- |
1085
- | `enableFiltering` | `boolean` | inferred | Explicitly show or hide the filter row |
1086
- | `filterValue` | `TypeFilterValue` | - | Controlled display state; data ownership remains external |
1087
- | `defaultFilterValue` | `TypeFilterValue` | - | Uncontrolled initial state and local filtering input |
1088
- | `onFilterValueChange` | `(value: TypeFilterValue) => void` | - | Fired on filter change |
1089
- | `filterTypes` | `TypeFilterTypes` | built-in registry | Extend or override filter types and operators |
1090
- | `enableColumnFilterContextMenu` | `boolean` | `true` | Operator, activation, Clear, and Clear All menu |
1091
- | `scrollTopOnFilter` | `boolean` | `true` | Reset vertical scroll after a filter commits |
1092
- | `renderColumnFilterContextMenu` | `TypeRenderColumnFilterContextMenu` | - | Render a custom operator menu with grid/cell context |
1093
- | `columnFilterContextMenuAlignPositions` | `string[]` | built-in fallbacks | Configure custom/operator menu alignment candidates |
1094
- | `columnFilterContextMenuConstrainTo` | `boolean \| HTMLElement \| string \| function` | `true` | Supply the custom menu constraint target |
1095
- | `columnFilterContextMenuPosition` | `string` | `"absolute"` | Supply the custom menu positioning mode |
1096
- | `updateMenuPositionOnScroll` | `boolean` | `true` | Request custom menu repositioning while scrolling |
1097
- | `filteredRowsCount` | `(count: number) => void` | - | Reports filtered row count |
1098
-
1099
- For Inovua 5.10.2 compatibility, filter-row visibility and local array
1100
- transformation are separate decisions. With no explicit `enableFiltering`, a
1101
- non-empty `defaultFilterValue` or `filterValue` shows the row; an empty or
1102
- missing descriptor array hides it. `enableFiltering` explicitly overrides only
1103
- that row's visibility. A descriptor is still required for a column to render a
1104
- filter editor; `enableFiltering={true}` by itself renders the structural row
1105
- without inventing filter state. Active uncontrolled `defaultFilterValue`
1106
- entries filter a local array even when the row is hidden, while controlled
1107
- `filterValue` is treated as externally owned display state and is not reapplied
1108
- locally. An entry with `active: false` still makes its editor visible but does
1109
- not filter data. Clear resets values without changing activation; Enable and
1110
- Disable are explicit menu actions, and Clear All emits one aggregate update.
1111
-
1112
- ### Sorting
1113
-
1114
- | Prop | Type | Default | Description |
1115
- | ------------------------- | ------------------------------ | ------------- | -------------------------------------------------------------- |
1116
- | `sortInfo` | `TypeSortInfo` | - | Controlled sort state |
1117
- | `defaultSortInfo` | `TypeSortInfo` | - | Uncontrolled initial sort |
1118
- | `onSortInfoChange` | `(info: TypeSortInfo) => void` | - | Fired on sort change |
1119
- | `sortable` | `boolean` | `true` | Root sorting switch; `column.sortable` can override it |
1120
- | `allowUnsort` | `boolean` | `true` | Allow a single sort to return to “unsorted” |
1121
- | `defaultSortingDirection` | `"asc" \| "desc"` | `"asc"` | Default sort direction |
1122
- | `sortFunctions` | `TypeSortFunctions` | date registry | Comparator registry addressed by `column.type` |
1123
- | `renderSortTool` | `TypeRenderSortTool` | built-in icon | Root sort-indicator renderer; `column.renderSortTool` wins |
1124
- | `scrollTopOnSort` | `boolean \| "always"` | `true` | Reset vertical scroll on sort, never, or on every data refresh |
1125
-
1126
- An object-valued `sortInfo` is single-sort mode. An array-valued sort state is
1127
- persistent multi-sort mode, including when the array contains zero or one
1128
- descriptor; ordinary click, Enter, Space, header-menu, mobile, and imperative
1129
- sort actions retain that array shape without requiring Shift. Descriptor order
1130
- is sort priority, and retoggling a descriptor preserves its position until it
1131
- is removed.
1132
-
1133
- Local sorting uses `column.sort` first, then a descriptor `fn`, a
1134
- `sortFunctions[column.type]` registry entry, and finally the built-in
1135
- `number`/`date`/`string` comparator. A named column comparator receives
1136
- `(value1, value2, column, data1, data2, sortInfo)`. An id-only column receives
1137
- the complete rows as `value1` and `value2`. Controlled `sortInfo` remains
1138
- externally owned and is not applied again to local array order.
1139
-
1140
- Migration notes for the completed Inovua sorting contract:
1141
-
1142
- - Previous releases inferred numeric ordering when both values were
1143
- number-like. Untyped columns now use Inovua's string comparator; declare
1144
- `type: "number"` (or provide a comparator) for numeric ordering.
1145
- - Shift no longer changes a single descriptor into multi-sort mode. Initialize
1146
- `sortInfo` or `defaultSortInfo` as an array to opt into persistent multi-sort.
1147
- - `TypeSingleSortInfo.fn`, `column.sort`, and registered sort functions now
1148
- expose their exact comparator argument lists while retaining Inovua's
1149
- `number | boolean` result compatibility.
1150
-
1151
- ### Selection
1152
-
1153
- | Prop | Type | Default | Description |
1154
- | ------------------------------ | ----------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------- |
1155
- | `checkboxColumn` | `boolean \| IColumn` | `false` | Enable or customize the checkbox column |
1156
- | `selected` | `TypeRowSelection` | - | Controlled selection |
1157
- | `defaultSelected` | `TypeRowSelection` | `{}` for multi-select, else null | Uncontrolled initial selection |
1158
- | `unselected` | `{ [rowId: string]: boolean }` | - | Controlled exclusions while `selected === true` |
1159
- | `defaultUnselected` | `{ [rowId: string]: boolean }` | - | Initial uncontrolled select-all exclusions |
1160
- | `onSelectionChange` | `(config: TypeOnSelectionChangeArg) => void` | - | Fired with the next selection and row metadata |
1161
- | `multiSelect` | `boolean` | `true` with `checkboxColumn` | Enable multi-row selection semantics |
1162
- | `checkboxOnlyRowSelect` | `boolean` | `false` | Require the checkbox instead of a plain row click |
1163
- | `checkboxSelectEnableShiftKey` | `boolean` | `false` | Enable Shift-range selection through the checkbox column |
1164
- | `toggleRowSelectOnClick` | `boolean` | `false` | Toggle off the sole selected row on an unmodified click |
1165
- | `activeIndex` | `number` | - | Controlled active-row index |
1166
- | `defaultActiveIndex` | `number` | `-1` | Initial uncontrolled active-row index |
1167
- | `onActiveIndexChange` | `(index: number) => void` | - | Fired when pointer, keyboard, or focus changes the active row |
1168
- | `enableKeyboardNavigation` | `boolean` | `true` | Enable Arrow, Home, End, Page, Enter, and optional Tab row navigation |
1169
- | `activateRowOnFocus` | `boolean` | `true` | Restore the last active row when grid focus returns |
1170
- | `keyPageStep` | `number` | `10` | Row distance for Page Up and Page Down |
1171
- | `allowRowTabNavigation` | `boolean` | `false` | Move the active row with Tab while another row remains available |
1172
- | `disabledRows` | `{ [displayedIndex: string]: boolean } \| null` | - | Block pointer interaction by current view index without excluding API selection |
1173
-
1174
- Shift-click selects an inclusive range from the previous row anchor. Ctrl/Cmd
1175
- click toggles one row, while an unmodified multi-select click selects only that
1176
- row. Enter applies the same selection rules to the active row. Focus leaving
1177
- the grid clears the live active index and restores the last index when focus
1178
- returns; virtualized navigation scrolls the active row into view.
1179
-
1180
- ### Editing
1181
-
1182
- | Prop | Type | Default | Description |
1183
- | ------------------- | ------------------------------ | ------------ | -------------------------------------------------------------------------------------------- |
1184
- | `editable` | `boolean` | `false` | Enable default editing for columns that do not opt out |
1185
- | `editStartEvent` | `string` | `"dblclick"` | Use double-click or compatible click activation |
1186
- | `onEditStart` | `(info: TypeEditInfo) => void` | - | Reports the original value and stable row/column identity |
1187
- | `onEditValueChange` | `(info: TypeEditInfo) => void` | - | Reports each draft value change |
1188
- | `onEditStop` | `(info: TypeEditInfo) => void` | - | Runs before completion or cancellation |
1189
- | `onEditComplete` | `(info) => void \| Promise` | - | Runs after the editor stops; navigation waits for fulfillment and is suppressed on rejection |
1190
- | `onEditCancel` | `(info: TypeEditInfo) => void` | - | Reports Escape cancellation without persisting the draft |
1191
-
1192
- Column-level `editable` may be a boolean or a synchronous/asynchronous
1193
- predicate. Pointer and imperative starts pass it the same Inovua-shaped
1194
- `CellProps`, including raw string/number row identity, row/render/remote
1195
- indices, column aliases and computed indices/width, selection and row-height
1196
- metadata, theme, and native-scroll state. A falsy result or rejection refuses
1197
- the edit. `editor` accepts a component type or React element, while
1198
- `renderEditor(editorProps, cellProps, cell)` receives the compatibility
1199
- contract. Values from `editorProps` are
1200
- available both as top-level editor props and through the nested `editorProps`
1201
- object. Navigation callbacks use `(complete, direction)`: passing
1202
- `complete=false` stops the editor and navigates without firing
1203
- `onEditComplete` or `onEditCancel`. The built-in editor exposes a stable
1204
- accessible name from the column header/name/ID.
1205
-
1206
- The stable `TypeComputedProps` ref exposes these editing methods and fields:
1207
-
1208
- | Member | Behavior |
1209
- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1210
- | `startEdit({ columnId, rowIndex?, rowId?, value? })` | Starts the requested editable cell after scroll/deferred dispatch and resolves to its start value. It replaces an active editor without ending the former edit. Invalid columns reject with an error; invalid rows reject with `null`. |
1211
- | `tryStartEdit({ columnId, rowIndex?, rowId?, dir? })` | Searches in `dir` order after deferred dispatch and resolves to the first editable value, replacing an active editor without end callbacks. It rejects with `null` if none can start. Numeric columns are visible-column indices. |
1212
- | `completeEdit(args?)` | Scrolls, waits for the rendered/editable target, and reads live cell metadata/draft at dispatch. An invalid/missing column falls back both coordinates to current. No object uses `""`; an omitted cross-target value is `undefined`. |
1213
- | `cancelEdit(args?)` | Immediately targets only a rendered/editable cell and never scrolls. An invalid/missing column falls back to current; a valid column without a row, a non-editable target, or an offscreen target is a no-op. |
1214
- | `getCurrentEditInfo()` | Returns the live edit identity/value or `null`. |
1215
- | `isInEdit.current` | Exposes the upstream lifecycle edit flag. |
1216
- | `currentEditCompletePromise.current` | Tracks the current completion callback promise. |
1217
-
1218
- It also exposes behavior-backed column-state methods:
1219
-
1220
- | Member | Behavior |
1221
- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
1222
- | `setColumnVisible(column, visible)` | Uses the same controlled/uncontrolled ownership and callback path as the built-in menu and optional toolbar. |
1223
- | `setColumnOrder(order)` | Applies an uncontrolled order or emits a controlled proposal without mutating consumer state. |
1224
- | `setColumnSizes(action)` / `setColumnFlexes(action)` | Replace grid-owned width/flex maps; declarative `width`/`flex` values remain authoritative. |
1225
- | `onBatchColumnResize(entries, context?)` | Applies a width/flex transaction and emits per-column plus batch completion callbacks. |
1226
- | `setColumnSizeAuto(id, skipHeader?)` | Deterministically auto-sizes one resizable visible column. |
1227
- | `setColumnsSizesAuto(config?)` | Auto-sizes selected or all resizable visible columns as one batch. |
1228
- | `setColumnSizesToFit()` | Fits resizable visible columns to the viewport while honoring min/max bounds. |
1229
-
1230
- Completion is session-safe: an older async completion settling cannot clear or
1231
- navigate a newer edit. The editor is already stopped when `onEditComplete`
1232
- runs; rejecting its Promise leaves it stopped and suppresses keyboard
1233
- navigation. Exact 5.10.2 cross-target behavior is preserved: dispatching
1234
- complete/cancel to a different valid cell reports that target without emitting
1235
- `onEditStop` for it and leaves the current editor/edit info in place; the
1236
- upstream lifecycle flag becomes false. Numeric row IDs remain numeric in all
1237
- lifecycle payloads, and numeric row lookup accepts equivalent numeric strings.
1238
- The published upstream `TypeEditInfo` declaration nevertheless labels
1239
- `rowId` as `string`; the compatibility type intentionally uses `any` so both
1240
- existing string-typed handlers and the observed numeric runtime contract remain
1241
- source-compatible.
1242
-
1243
- ### Pagination
1244
-
1245
- | Prop | Type | Default | Description |
1246
- | ------------------------- | ------------------------------------------- | ----------------------- | ---------------------------------------------------------------------- |
1247
- | `pagination` | `true \| false \| "remote" \| "local"` | `false` | Pagination mode |
1248
- | `skip` | `number` | - | Controlled offset |
1249
- | `defaultSkip` | `number` | `0` | Initial offset |
1250
- | `limit` | `number` | - | Controlled page size |
1251
- | `defaultLimit` | `number` | first page size or `10` | Initial page size |
1252
- | `onSkipChange` | `(skip: number) => void` | - | Fired when offset changes |
1253
- | `onLimitChange` | `(limit: number) => void` | - | Fired when page size changes |
1254
- | `pageSizes` | `number[]` | `[10, 50, 100, 1000]` | Allowed page sizes |
1255
- | `renderPaginationToolbar` | `(props: TypePaginationProps) => ReactNode` | - | Custom toolbar; `undefined` uses the built-in and `null` suppresses it |
1256
-
1257
- ### Misc
1258
-
1259
- | Prop | Type | Default | Description |
1260
- | ----------------- | ---------------------------------------------------- | ----------- | ------------------------------------------------------------------- |
1261
- | `i18n` | `TypeI18n` | - | Text overrides (labels, operators, etc.) |
1262
- | `loading` | `boolean` | - | Controlled effective loading state |
1263
- | `loadingText` | `ReactNode \| (() => ReactNode)` | `"Loading"` | Built-in/custom mask content |
1264
- | `renderLoadMask` | `(props: TypeLoadMaskProps) => ReactNode \| null` | - | Custom mask; `undefined` uses the built-in and `null` suppresses it |
1265
- | `onLoadingChange` | `(loading: boolean) => void` | - | Fires once per effective loading transition |
1266
- | `onDidMount` | `(ref: MutableRefObject<TypeComputedProps \| null>)` | - | Passive mount callback after API hydration, before handle/onReady |
1267
- | `handle` | `(ref: MutableRefObject<TypeComputedProps \| null>)` | - | Receives the same stable ref after onDidMount |
1268
- | `onReady` | `(ref: MutableRefObject<TypeComputedProps \| null>)` | - | Receives the same stable ref after handle |
1269
- | `className` | `string` | - | Extra CSS classes on the outer grid root |
1270
- | `style` | `CSSProperties` | - | Inline styles on the outer grid root |
1271
- | `onFocus` | `FocusEventHandler<HTMLDivElement>` | - | Bubbling root focus lifecycle handler |
1272
- | `onBlur` | `FocusEventHandler<HTMLDivElement>` | - | Bubbling root blur lifecycle handler |
1273
- | `onKeyDown` | `KeyboardEventHandler<HTMLDivElement>` | - | Bubbling root keyboard handler |
1274
-
1275
- Issue 48 certifies the `onDidMount` mount contract. The existing `handle` and
1276
- `onReady` adapters are usable, but Inovua's callback-identity cleanup and
1277
- nonzero-width readiness details remain explicitly listed as a known gap in the
1278
- public compatibility ledger.
1279
-
1280
- ## TypeScript
1281
-
1282
- The package ships full type definitions.
1283
-
1284
- ```tsx
1285
- import { ReactDataGrid } from "@geovi/the-datagrid";
1286
- import type {
1287
- TypeColumns,
1288
- TypeColumn,
1289
- TypeDataGridProps,
1290
- TypeDataSourceArgs,
1291
- TypeRowSelection,
1292
- TypeOnSelectionChangeArg,
1293
- TypeFilterValue,
1294
- TypeSortInfo,
1295
- TypeI18n,
1296
- } from "@geovi/the-datagrid";
1297
- ```
91
+ MIT licensed.