@alaarab/ogrid-mcp 2.8.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/bundled-docs/api/README.md +7 -32
  2. package/bundled-docs/api/column-def.mdx +1 -1
  3. package/bundled-docs/api/components-column-chooser.mdx +0 -96
  4. package/bundled-docs/api/components-column-header-filter.mdx +1 -83
  5. package/bundled-docs/api/components-datagrid-table.mdx +0 -63
  6. package/bundled-docs/api/components-pagination-controls.mdx +0 -94
  7. package/bundled-docs/api/components-sidebar.mdx +0 -76
  8. package/bundled-docs/api/components-status-bar.mdx +0 -66
  9. package/bundled-docs/api/headless-hooks.mdx +410 -0
  10. package/bundled-docs/api/ogrid-props.mdx +1 -1
  11. package/bundled-docs/api/types.mdx +1 -1
  12. package/bundled-docs/features/cell-references.mdx +2 -116
  13. package/bundled-docs/features/column-chooser.mdx +0 -131
  14. package/bundled-docs/features/column-groups.mdx +1 -136
  15. package/bundled-docs/features/column-pinning.mdx +1 -108
  16. package/bundled-docs/features/column-reordering.mdx +1 -168
  17. package/bundled-docs/features/column-types.mdx +0 -71
  18. package/bundled-docs/features/context-menu.mdx +1 -93
  19. package/bundled-docs/features/csv-export.mdx +1 -104
  20. package/bundled-docs/features/editing.mdx +0 -149
  21. package/bundled-docs/features/filtering.mdx +0 -119
  22. package/bundled-docs/features/formulas.mdx +2 -102
  23. package/bundled-docs/features/grid-api.mdx +1 -108
  24. package/bundled-docs/features/keyboard-navigation.mdx +1 -74
  25. package/bundled-docs/features/mobile-touch.mdx +0 -71
  26. package/bundled-docs/features/pagination.mdx +0 -105
  27. package/bundled-docs/features/performance.mdx +0 -191
  28. package/bundled-docs/features/premium-inputs.mdx +0 -311
  29. package/bundled-docs/features/responsive-columns.mdx +1 -76
  30. package/bundled-docs/features/row-selection.mdx +2 -106
  31. package/bundled-docs/features/server-side-data.mdx +1 -129
  32. package/bundled-docs/features/sidebar.mdx +1 -78
  33. package/bundled-docs/features/sorting.mdx +2 -108
  34. package/bundled-docs/features/spreadsheet-selection.mdx +2 -79
  35. package/bundled-docs/features/status-bar.mdx +1 -72
  36. package/bundled-docs/features/toolbar.mdx +1 -75
  37. package/bundled-docs/features/virtual-scrolling.mdx +1 -304
  38. package/bundled-docs/getting-started/headless-or-component.mdx +112 -0
  39. package/bundled-docs/getting-started/installation.mdx +11 -141
  40. package/bundled-docs/getting-started/overview.mdx +15 -55
  41. package/bundled-docs/getting-started/quick-start.mdx +4 -279
  42. package/bundled-docs/guides/browser-support-matrix.mdx +6 -17
  43. package/bundled-docs/guides/mcp-live-testing.mdx +0 -82
  44. package/bundled-docs/guides/mcp.mdx +4 -4
  45. package/bundled-docs/guides/migration-from-ag-grid.mdx +2 -3
  46. package/bundled-docs/guides/theming.mdx +50 -23
  47. package/dist/esm/index.js +9 -39
  48. package/package.json +5 -5
  49. package/bundled-docs/api/js-api.mdx +0 -198
  50. package/bundled-docs/getting-started/vanilla-js.mdx +0 -218
  51. package/bundled-docs/guides/framework-showcase.mdx +0 -246
@@ -0,0 +1,410 @@
1
+ ---
2
+ sidebar_position: 11
3
+ title: Headless hooks
4
+ description: API reference for useHeadlessGrid + the spreadsheet hook set (useInlineEdit, useRangeSelection, useFillHandle, useCellClipboard, useUndoRedo, useGridFocus).
5
+ ---
6
+
7
+ # Headless hooks
8
+
9
+ OGrid 2.9 ships seven framework-native hooks that expose grid logic without
10
+ imposing any chrome. Pair `useHeadlessGrid` with the spreadsheet hooks to
11
+ add inline edit, range selection, fill handle, clipboard, undo/redo, and
12
+ keyboard navigation to your own table markup (shadcn `<Table>`, plain HTML,
13
+ Material `<DataGrid>`, anything).
14
+
15
+ All seven hooks ship as React hooks:
16
+
17
+ - `import { useX } from '@alaarab/ogrid-react-radix'`
18
+
19
+ ### Bundle-size tip — headless-only consumers
20
+
21
+ If your app **only** uses the hooks (no `<OGrid>` chrome), import from
22
+ `@alaarab/ogrid-react` instead of `@alaarab/ogrid-react-radix`. Same hooks,
23
+ no chrome CSS load (~40KB saved), and `sideEffects: false` lets your
24
+ bundler tree-shake aggressively:
25
+
26
+ ```ts
27
+ // Headless-only — skip the radix package entirely
28
+ ```
29
+
30
+ Use `@alaarab/ogrid-react-radix` when you want both the headless hooks AND
31
+ the drop-in `<OGrid>` component.
32
+
33
+ ---
34
+
35
+ ## `useHeadlessGrid` — data layer
36
+
37
+ The foundation. Returns sort/filter/paginate state plus the current page
38
+ of rows. Supports `dataSource` for server-side mode.
39
+
40
+ ```tsx
41
+
42
+ const grid = useHeadlessGrid({
43
+ columns,
44
+ data: rows,
45
+ getRowId: (row) => row.id,
46
+ initialSort: { field: 'name', direction: 'asc' },
47
+ initialPageSize: 25,
48
+ });
49
+ ```
50
+
51
+ ### Parameters
52
+
53
+ | Param | Type | Notes |
54
+ |---|---|---|
55
+ | `columns` | `IColumnDef<T>[]` | Column definitions |
56
+ | `data` | `T[]` | Full dataset (client-side) or empty array (server-side) |
57
+ | `getRowId` | `(row: T) => RowId` | Stable row-identity extractor |
58
+ | `initialSort?` | `{ field, direction }` | Initial sort, omit for none |
59
+ | `initialFilters?` | `IFilters` | Initial filter values |
60
+ | `initialPage?` | `number` | Default `1` |
61
+ | `initialPageSize?` | `number` | Default `25` |
62
+ | `sort?`, `filters?`, `page?`, `pageSize?` | controlled overrides | Pass to put state under your control |
63
+ | `onSortChange?`, `onFiltersChange?`, `onPageChange?`, `onPageSizeChange?` | callbacks | Fired when state changes |
64
+ | `dataSource?` | `IDataSource<T>` | **React only.** Server-side mode |
65
+ | `workerSort?` | `boolean \| 'auto'` | **React only.** Worker-thread sort for large datasets |
66
+
67
+ ### Returns
68
+
69
+ | Field | Description |
70
+ |---|---|
71
+ | `rows` | Current page rows after sort + filter |
72
+ | `allFilteredRows` | Full filtered+sorted set (client mode) or current page (server mode) |
73
+ | `columns` | Resolved columns |
74
+ | `totalCount` | Post-filter total |
75
+ | `totalPages` | Total pages at current page size |
76
+ | `sort`, `filters`, `page`, `pageSize` | Current state |
77
+ | `setSort`, `toggleSort(columnId)`, `sortIndicator(columnId)` | Sort actions |
78
+ | `setFilters(filters)`, `setFilter(key, value)`, `hasActiveFilters` | Filter actions |
79
+ | `setPage(n)`, `setPageSize(n)` | Pagination |
80
+ | `getRowId`, `getCellValue(row, columnId)` | Row + cell helpers |
81
+ | `selectedRowIds`, `isRowSelected(row)`, `toggleRowSelection(row)`, `selectAllOnPage()`, `clearSelection()` | Minimal Set-based row selection |
82
+
83
+ ---
84
+
85
+ ## `useInlineEdit` — cell editing lifecycle
86
+
87
+ Manages start/commit/cancel for one cell at a time. Honors the column's
88
+ `editable` flag (boolean or per-row predicate) and validates new values
89
+ through `valueParser` — same flow `<OGrid>` uses internally.
90
+
91
+ ```tsx
92
+ const edit = useInlineEdit({
93
+ columns,
94
+ getRowId: (row) => row.id,
95
+ onCellEdit: ({ item, columnId, oldValue, newValue }) =>
96
+ updateRow(item.id, { [columnId]: newValue }),
97
+ });
98
+
99
+ // In render:
100
+ <TableCell onDoubleClick={() => edit.startEdit(row, col.columnId)}>
101
+ {edit.isEditing(row, col.columnId) ? (
102
+ <input autoFocus {...edit.getEditorProps(row, col.columnId)} />
103
+ ) : (
104
+ String(grid.getCellValue(row, col.columnId))
105
+ )}
106
+ </TableCell>
107
+ ```
108
+
109
+ ### Parameters
110
+
111
+ | Param | Type |
112
+ |---|---|
113
+ | `columns` | `IColumnDef<T>[]` |
114
+ | `getRowId` | `(row: T) => RowId` |
115
+ | `onCellEdit` | `(event: { item, columnId, oldValue, newValue }) => void` |
116
+ | `isCellEditable?` | `(row, columnId) => boolean` (override per-row) |
117
+
118
+ ### Returns
119
+
120
+ | Field | Description |
121
+ |---|---|
122
+ | `editingCell` | `{ rowId, columnId } \| null` |
123
+ | `pendingValue`, `setPendingValue` | Buffered new value |
124
+ | `startEdit(row, columnId)` | Begin editing (no-op if not editable) |
125
+ | `commitEdit()` | Validate via `valueParser`, fire `onCellEdit` |
126
+ | `cancelEdit()` | Close without firing |
127
+ | `isEditing(row, columnId)` | `boolean` |
128
+ | `canEdit(row, columnId)` | `boolean` |
129
+ | `getEditorProps(row, columnId)` | Spread onto your input — `{ value, onChange, onBlur, onKeyDown }` (Enter commits, Escape cancels) |
130
+
131
+ ---
132
+
133
+ ## `useRangeSelection` — Excel-style range
134
+
135
+ Anchor + focus model. Foundation for `useFillHandle` and `useCellClipboard`.
136
+
137
+ ```tsx
138
+ const range = useRangeSelection({
139
+ rowCount: grid.rows.length,
140
+ colCount: grid.columns.length,
141
+ });
142
+
143
+ // Click + drag:
144
+ <TableCell
145
+ onMouseDown={(e) => e.shiftKey ? range.extendRange(rowIdx, colIdx) : range.startRange(rowIdx, colIdx)}
146
+ onMouseEnter={(e) => e.buttons === 1 && range.extendRange(rowIdx, colIdx)}
147
+ data-selected={range.isInRange(rowIdx, colIdx)}
148
+ />
149
+ ```
150
+
151
+ ### Parameters
152
+
153
+ | Param | Type |
154
+ |---|---|
155
+ | `rowCount` | `number` (visible row count) |
156
+ | `colCount` | `number` (visible column count) |
157
+
158
+ ### Returns
159
+
160
+ | Field | Description |
161
+ |---|---|
162
+ | `range` | `ISelectionRange \| null` (normalized rectangular bounds) |
163
+ | `anchor`, `focus` | `CellCoord \| null` |
164
+ | `startRange(row, col)`, `extendRange(row, col)`, `setRange(range)`, `clearRange()` | State actions |
165
+ | `selectAll()` | Select every cell |
166
+ | `isInRange(row, col)` | `boolean` |
167
+ | `getRangeRows()`, `getRangeCells()` | Convenience extractors |
168
+
169
+ ---
170
+
171
+ ## `useFillHandle` — drag-to-fill
172
+
173
+ Excel-style fill via core's `applyFillValues`. Type-compatibility checks
174
+ prevent dragging incompatible types (text into a number column).
175
+
176
+ ```tsx
177
+ const fill = useFillHandle({
178
+ rangeSelection: range,
179
+ rows: grid.rows,
180
+ columns,
181
+ onFillCells: (events) => events.forEach(applyEdit),
182
+ });
183
+
184
+ // Bottom-right of active range:
185
+ <div onMouseDown={fill.startFill} className="fill-handle-dot" />
186
+
187
+ // On every cell during drag:
188
+ <TableCell
189
+ onMouseEnter={() => fill.isFilling && fill.updateFill(rowIdx, colIdx)}
190
+ onMouseUp={fill.commitFill}
191
+ data-fill={fill.isInFillRange(rowIdx, colIdx)}
192
+ />
193
+ ```
194
+
195
+ ### Parameters
196
+
197
+ | Param | Type |
198
+ |---|---|
199
+ | `rangeSelection` | `UseRangeSelectionResult` |
200
+ | `rows` | `T[]` (current page rows) |
201
+ | `columns` | `IColumnDef<T>[]` |
202
+ | `onFillCells` | `(events: ICellValueChangedEvent<T>[]) => void` |
203
+
204
+ ### Returns
205
+
206
+ | Field | Description |
207
+ |---|---|
208
+ | `fillTarget` | `CellCoord \| null` (current drag target) |
209
+ | `isFilling` | `boolean` |
210
+ | `fillRange` | `ISelectionRange \| null` (source range extended to target) |
211
+ | `startFill()`, `updateFill(row, col)`, `commitFill()`, `cancelFill()` | Lifecycle |
212
+ | `isInFillRange(row, col)` | `boolean` for highlighting |
213
+
214
+ ---
215
+
216
+ ## `useCellClipboard` — TSV copy/cut/paste
217
+
218
+ Round-trippable through Excel and Google Sheets. Honors `clipboardFormatter`
219
+ on copy and `valueParser` on paste validation.
220
+
221
+ ```tsx
222
+ const clipboard = useCellClipboard({
223
+ rangeSelection: range,
224
+ rows: grid.rows,
225
+ columns,
226
+ onCellEdit: (events) => events.forEach(applyEdit),
227
+ });
228
+
229
+ useEffect(() => {
230
+ const handler = (e) => {
231
+ const mod = e.metaKey || e.ctrlKey;
232
+ if (mod && e.key === 'c') clipboard.copyRange();
233
+ if (mod && e.key === 'x') clipboard.cutRange();
234
+ if (mod && e.key === 'v') clipboard.pasteRange();
235
+ };
236
+ document.addEventListener('keydown', handler);
237
+ return () => document.removeEventListener('keydown', handler);
238
+ }, [clipboard]);
239
+ ```
240
+
241
+ ### Parameters
242
+
243
+ | Param | Type |
244
+ |---|---|
245
+ | `rangeSelection` | `UseRangeSelectionResult` |
246
+ | `rows` | `T[]` |
247
+ | `columns` | `IColumnDef<T>[]` |
248
+ | `onCellEdit` | `(events: ICellValueChangedEvent<T>[]) => void` |
249
+ | `clipboard?` | `{ readText, writeText }` override (defaults to `navigator.clipboard`) |
250
+
251
+ ### Returns
252
+
253
+ | Field | Description |
254
+ |---|---|
255
+ | `copyRange()`, `cutRange()`, `pasteRange()` | Async actions |
256
+ | `canPaste` | `boolean` (feature detection) |
257
+ | `activeCutRange`, `activeCopyRange` | Marching-ants tracking |
258
+ | `clearClipboard()` | Dismiss markers (bind to Escape) |
259
+
260
+ ---
261
+
262
+ ## `useUndoRedo` — action history stack
263
+
264
+ Wraps your `onCellEdit` callback with an undo/redo history. Pair with
265
+ `useInlineEdit` / `useFillHandle` / `useCellClipboard` to get spreadsheet-
266
+ style undo across all of them for free.
267
+
268
+ ```tsx
269
+ const undo = useUndoRedo({ onCellValueChanged: applyEditToRows });
270
+
271
+ const edit = useInlineEdit({ columns, getRowId, onCellEdit: undo.onCellValueChanged });
272
+ const fill = useFillHandle({ ..., onFillCells: (events) => events.forEach(undo.onCellValueChanged) });
273
+
274
+ <button onClick={undo.undo} disabled={!undo.canUndo}>Undo</button>
275
+ <button onClick={undo.redo} disabled={!undo.canRedo}>Redo</button>
276
+ ```
277
+
278
+ ### Parameters
279
+
280
+ | Param | Type |
281
+ |---|---|
282
+ | `onCellValueChanged` | `(event: ICellValueChangedEvent<T>) => void` |
283
+ | `maxUndoDepth?` | `number` (default `100`) |
284
+
285
+ ### Returns
286
+
287
+ | Field | Description |
288
+ |---|---|
289
+ | `onCellValueChanged` | Wrapped callback — pass to other hooks instead of your raw handler |
290
+ | `undo()`, `redo()` | Actions |
291
+ | `canUndo`, `canRedo` | `boolean` flags |
292
+ | `beginBatch()`, `endBatch()` | Group multiple edits as one undo step |
293
+
294
+ ---
295
+
296
+ ## `useGridFocus` — keyboard navigation
297
+
298
+ Arrow / Tab / Enter / Home / End / PageUp / PageDown. Pairs with
299
+ `useRangeSelection` so Shift+Arrow extends the active range.
300
+
301
+ ```tsx
302
+ const focus = useGridFocus({
303
+ rowCount: grid.rows.length,
304
+ colCount: grid.columns.length,
305
+ rangeSelection: range, // optional — enables Shift+Arrow extend
306
+ });
307
+
308
+ <div tabIndex={0} onKeyDown={focus.getKeyDownHandler()}>
309
+ {/* Render cells; highlight focus.activeCell */}
310
+ </div>
311
+ ```
312
+
313
+ ### Parameters
314
+
315
+ | Param | Type |
316
+ |---|---|
317
+ | `rowCount` | `number` |
318
+ | `colCount` | `number` |
319
+ | `pageSize?` | `number` (PageUp/Down step, default `10`) |
320
+ | `rangeSelection?` | `UseRangeSelectionResult` (optional, for Shift+Arrow extend) |
321
+
322
+ ### Returns
323
+
324
+ | Field | Description |
325
+ |---|---|
326
+ | `activeCell`, `setActiveCell(cell)` | Current focus + setter |
327
+ | `moveUp/Down/Left/Right(n?)` | Programmatic movement |
328
+ | `moveToRowStart/RowEnd/Start/End()` | Navigation helpers |
329
+ | `getKeyDownHandler()` | Returns the handler to attach to your grid container's `onKeyDown` |
330
+
331
+ ---
332
+
333
+ ## `useGridVirtualization` — windowed rendering
334
+
335
+ Headless row + column virtualization for large datasets. Tracks scroll
336
+ position on a consumer-owned container and reports which slice of rows/
337
+ columns to render with spacer offsets that preserve scroll geometry. Zero
338
+ external dependencies — uses core's pure compute helpers.
339
+
340
+ ```tsx
341
+
342
+ const grid = useHeadlessGrid({ columns, data, getRowId, initialPageSize: 10000 });
343
+ const containerRef = useRef<HTMLDivElement>(null);
344
+ const virt = useGridVirtualization({
345
+ rowCount: grid.totalCount,
346
+ rowHeight: 36,
347
+ containerRef,
348
+ });
349
+
350
+ return (
351
+ <div ref={containerRef} onScroll={virt.onScroll} style={{ height: 400, overflow: 'auto' }}>
352
+ <div style={{ height: virt.totalHeight, position: 'relative' }}>
353
+ <div style={{ transform: `translateY(${virt.rowRange.offsetTop}px)` }}>
354
+ {grid.rows.slice(virt.rowRange.startIndex, virt.rowRange.endIndex + 1).map((row) => (
355
+ <div key={grid.getRowId(row)} style={{ height: 36 }}>
356
+ {/* render row */}
357
+ </div>
358
+ ))}
359
+ </div>
360
+ </div>
361
+ </div>
362
+ );
363
+ ```
364
+
365
+ ### Parameters
366
+
367
+ | Param | Type | Notes |
368
+ |-------|------|-------|
369
+ | `rowCount` | `number` | Total rows in the data set. |
370
+ | `rowHeight` | `number` | Uniform row height in pixels. |
371
+ | `containerRef` | `RefObject<HTMLElement \| null>` | The scroll container — must have a fixed height + `overflow: auto`. |
372
+ | `overscan` | `number` | Extra rows above/below the visible window. Default `5`. |
373
+ | `enabled` | `boolean` | Disable virtualization entirely. Default `true`. |
374
+ | `threshold` | `number` | Below this row count, all rows render (avoids small-dataset artifacts). Default `100`. |
375
+ | `columnWidths` | `number[]` | Per-column widths (unpinned only) — enables column virt. Omit for row-only. |
376
+ | `columnOverscan` | `number` | Extra columns left/right of the viewport. Default `2`. |
377
+
378
+ ### Returns
379
+
380
+ | Field | Type | Notes |
381
+ |-------|------|-------|
382
+ | `totalHeight` | `number` | Total scroll height (`rowCount × rowHeight`). |
383
+ | `rowRange` | `{ startIndex; endIndex; offsetTop; offsetBottom }` | Visible row slice + spacer pixels. |
384
+ | `columnRange` | `{ startIndex; endIndex; leftOffset; rightOffset } \| null` | Visible column slice (null when `columnWidths` omitted). |
385
+ | `scrollToIndex` | `(index, align?) => void` | Programmatically scroll a row into view (`'start' \| 'center' \| 'end'`). |
386
+ | `onScroll` | `() => void` | Attach to the container's `onScroll` prop. |
387
+ | `isActive` | `boolean` | True when virtualization is engaged (above threshold + enabled). |
388
+
389
+ ---
390
+
391
+ ## All seven combined
392
+
393
+ The canonical demo combining every hook on a plain HTML table is the
394
+ [`SpreadsheetDemo` Storybook story](https://github.com/alaarab/ogrid/blob/main/packages/react-radix/src/OGrid/SpreadsheetDemo.stories.tsx) —
395
+ ~200 lines you can copy as a starter template.
396
+
397
+ ```tsx
398
+ const grid = useHeadlessGrid({ columns, data, getRowId: (r) => r.id });
399
+ const range = useRangeSelection({ rowCount: grid.rows.length, colCount: grid.columns.length });
400
+ const undo = useUndoRedo({ onCellValueChanged: applyEditToRows });
401
+ const edit = useInlineEdit({ columns, getRowId, onCellEdit: undo.onCellValueChanged });
402
+ const fill = useFillHandle({ rangeSelection: range, rows: grid.rows, columns, onFillCells });
403
+ const clipboard = useCellClipboard({ rangeSelection: range, rows: grid.rows, columns, onCellEdit });
404
+ const focus = useGridFocus({ rowCount: grid.rows.length, colCount: grid.columns.length, rangeSelection: range });
405
+ ```
406
+
407
+ ## See also
408
+
409
+ - [Headless or component?](/docs/getting-started/headless-or-component) — When to use these hooks vs `<OGrid>`
410
+ - [Theming](/docs/guides/theming) — Including the shadcn preset
@@ -5,7 +5,7 @@ title: OGrid Props
5
5
 
6
6
  # OGrid Props
7
7
 
8
- Complete reference for `IOGridProps<T>`, the props accepted by the `OGrid` component in all UI packages (`@alaarab/ogrid-react-radix`, `@alaarab/ogrid-react-fluent`, `@alaarab/ogrid-react-material`).
8
+ Complete reference for `IOGridProps<T>`, the props accepted by the `OGrid` component in all UI packages (`@alaarab/ogrid-react-radix`, `@alaarab/ogrid-react-fluent`).
9
9
 
10
10
  ```typescript
11
11
  ```
@@ -5,7 +5,7 @@ title: Types
5
5
 
6
6
  # Types
7
7
 
8
- Reference for all shared types exported from `@alaarab/ogrid-core`. These types are also re-exported from all UI packages (`@alaarab/ogrid-react-radix`, `@alaarab/ogrid-react-fluent`, `@alaarab/ogrid-react-material`).
8
+ Reference for all shared types exported from `@alaarab/ogrid-core`. These types are also re-exported from all UI packages (`@alaarab/ogrid-react-radix`, `@alaarab/ogrid-react-fluent`).
9
9
 
10
10
  ## RowId
11
11
 
@@ -13,14 +13,8 @@ Enable Excel-style cell references with a single prop. Column letter headers (A,
13
13
 
14
14
  <CellReferencesDemo />
15
15
 
16
- :::tip Framework-Specific Styling
17
- The live demo above shows **React Radix UI** styling (lightweight default). To see how cell references look in your framework's design system, click the framework buttons above the demo to open online demo:
18
- - **React** -- Radix UI default theme
19
- - **Angular** -- Angular Material theme
20
- - **Vue** -- Vuetify theme
21
- - **JS** -- Vanilla JS default theme
22
-
23
- Each framework renders with its native components, so the styling matches your design system.
16
+ :::tip UI styling
17
+ The live demo above shows **Radix UI** styling (lightweight default). The same feature renders through the Fluent UI package with its native components.
24
18
  :::
25
19
 
26
20
  ## Quick Example
@@ -58,116 +52,8 @@ The `OGrid` component has the same props across all React UI packages. To switch
58
52
 
59
53
  - **Radix** (lightweight, default): `from '@alaarab/ogrid-react-radix'`
60
54
  - **Fluent UI** (Microsoft 365 / SPFx): `from '@alaarab/ogrid-react-fluent'` -- wrap in `<FluentProvider>`
61
- - **Material UI** (MUI v7): `from '@alaarab/ogrid-react-material'` -- wrap in `<ThemeProvider>`
62
55
  :::
63
56
 
64
- </TabItem>
65
- <TabItem value="angular" label="Angular">
66
-
67
- ```typescript
68
-
69
- @Component({
70
- standalone: true,
71
- imports: [OGridComponent],
72
- template: `<ogrid [props]="gridProps" />`
73
- })
74
- export class GridComponent {
75
- gridProps = {
76
- columns: [
77
- { columnId: 'name', name: 'Name' },
78
- { columnId: 'age', name: 'Age', type: 'numeric' },
79
- { columnId: 'email', name: 'Email' },
80
- { columnId: 'department', name: 'Department' },
81
- {
82
- columnId: 'salary', name: 'Salary', type: 'numeric',
83
- valueFormatter: (v: unknown) => `$${Number(v).toLocaleString()}`,
84
- },
85
- ] as IColumnDef<Person>[],
86
- data: people,
87
- getRowId: (item: Person) => item.id,
88
- cellReferences: true,
89
- defaultPageSize: 25,
90
- entityLabelPlural: 'people',
91
- };
92
- }
93
- ```
94
-
95
- :::tip Switching UI libraries
96
- Same component API across Angular packages. To switch, just change the import:
97
-
98
- - **Radix (CDK)**: `from '@alaarab/ogrid-angular-radix'` *(default, lightweight)*
99
- - **Angular Material**: `from '@alaarab/ogrid-angular-material'`
100
- - **PrimeNG**: `from '@alaarab/ogrid-angular-primeng'`
101
-
102
- All components are standalone -- no NgModule required.
103
- :::
104
-
105
- </TabItem>
106
- <TabItem value="vue" label="Vue">
107
-
108
- ```vue
109
- <script setup lang="ts">
110
-
111
- const columns: IColumnDef<Person>[] = [
112
- { columnId: 'name', name: 'Name' },
113
- { columnId: 'age', name: 'Age', type: 'numeric' },
114
- { columnId: 'email', name: 'Email' },
115
- { columnId: 'department', name: 'Department' },
116
- {
117
- columnId: 'salary', name: 'Salary', type: 'numeric',
118
- valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
119
- },
120
- ];
121
-
122
- const gridProps = {
123
- columns,
124
- data: people,
125
- getRowId: (item) => item.id,
126
- cellReferences: true,
127
- defaultPageSize: 25,
128
- entityLabelPlural: 'people',
129
- };
130
- </script>
131
-
132
- <template>
133
- <OGrid :gridProps="gridProps" />
134
- </template>
135
- ```
136
-
137
- :::tip Switching UI libraries
138
- Same component API across Vue packages. To switch, just change the import:
139
-
140
- - **Radix (Headless UI)**: `from '@alaarab/ogrid-vue-radix'` *(default, lightweight)*
141
- - **Vuetify**: `from '@alaarab/ogrid-vue-vuetify'` -- wrap in `<v-app>` for theming
142
- - **PrimeVue**: `from '@alaarab/ogrid-vue-primevue'`
143
- :::
144
-
145
- </TabItem>
146
- <TabItem value="js" label="Vanilla JS">
147
-
148
- ```js
149
-
150
- const grid = new OGrid(document.getElementById('grid'), {
151
- columns: [
152
- { columnId: 'name', name: 'Name' },
153
- { columnId: 'age', name: 'Age', type: 'numeric' },
154
- { columnId: 'email', name: 'Email' },
155
- { columnId: 'department', name: 'Department' },
156
- {
157
- columnId: 'salary',
158
- name: 'Salary',
159
- type: 'numeric',
160
- valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
161
- },
162
- ],
163
- data: people,
164
- getRowId: (item) => item.id,
165
- cellReferences: true,
166
- pageSize: 25,
167
- entityLabelPlural: 'people',
168
- });
169
- ```
170
-
171
57
  </TabItem>
172
58
  </Tabs>
173
59
 
@@ -65,139 +65,8 @@ The `OGrid` component has the same props across all React UI packages. To switch
65
65
 
66
66
  - **Radix** (lightweight, default): `from '@alaarab/ogrid-react-radix'`
67
67
  - **Fluent UI** (Microsoft 365 / SPFx): `from '@alaarab/ogrid-react-fluent'` - wrap in `<FluentProvider>`
68
- - **Material UI** (MUI v7): `from '@alaarab/ogrid-react-material'` - wrap in `<ThemeProvider>`
69
68
  :::
70
69
 
71
- </TabItem>
72
- <TabItem value="angular" label="Angular">
73
-
74
- ```typescript
75
-
76
- interface Person {
77
- id: number;
78
- name: string;
79
- email: string;
80
- age: number;
81
- department: string;
82
- salary: number;
83
- startDate: string;
84
- }
85
-
86
- const columns: IColumnDef<Person>[] = [
87
- { columnId: 'name', name: 'Name', required: true },
88
- { columnId: 'email', name: 'Email' },
89
- { columnId: 'age', name: 'Age', type: 'numeric', defaultVisible: false },
90
- { columnId: 'department', name: 'Department' },
91
- {
92
- columnId: 'salary',
93
- name: 'Salary',
94
- type: 'numeric',
95
- valueFormatter: (v: unknown) => `$${Number(v).toLocaleString()}`,
96
- },
97
- { columnId: 'startDate', name: 'Start Date', defaultVisible: false },
98
- ];
99
-
100
- @Component({
101
- standalone: true,
102
- imports: [OGridComponent],
103
- template: `<ogrid [props]="gridProps" />`
104
- })
105
- export class GridComponent {
106
- gridProps = {
107
- columns,
108
- data: people,
109
- getRowId: (p: Person) => p.id,
110
- defaultPageSize: 10,
111
- };
112
- }
113
- ```
114
-
115
- :::tip Switching UI libraries
116
- Same component API across Angular packages. To switch, just change the import:
117
-
118
- - **Radix (CDK)**: `from '@alaarab/ogrid-angular-radix'` *(default, lightweight)*
119
- - **Angular Material**: `from '@alaarab/ogrid-angular-material'`
120
- - **PrimeNG**: `from '@alaarab/ogrid-angular-primeng'`
121
-
122
- All components are standalone - no NgModule required.
123
- :::
124
-
125
- </TabItem>
126
- <TabItem value="vue" label="Vue">
127
-
128
- ```vue
129
- <script setup lang="ts">
130
-
131
- interface Person {
132
- id: number;
133
- name: string;
134
- email: string;
135
- age: number;
136
- department: string;
137
- salary: number;
138
- startDate: string;
139
- }
140
-
141
- const columns: IColumnDef<Person>[] = [
142
- { columnId: 'name', name: 'Name', required: true },
143
- { columnId: 'email', name: 'Email' },
144
- { columnId: 'age', name: 'Age', type: 'numeric', defaultVisible: false },
145
- { columnId: 'department', name: 'Department' },
146
- {
147
- columnId: 'salary',
148
- name: 'Salary',
149
- type: 'numeric',
150
- valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
151
- },
152
- { columnId: 'startDate', name: 'Start Date', defaultVisible: false },
153
- ];
154
-
155
- const gridProps = {
156
- columns,
157
- data: people,
158
- getRowId: (p: Person) => p.id,
159
- defaultPageSize: 10,
160
- };
161
- </script>
162
-
163
- <template>
164
- <OGrid :gridProps="gridProps" />
165
- </template>
166
- ```
167
-
168
- :::tip Switching UI libraries
169
- Same component API across Vue packages. To switch, just change the import:
170
-
171
- - **Radix (Headless UI)**: `from '@alaarab/ogrid-vue-radix'` *(default, lightweight)*
172
- - **Vuetify**: `from '@alaarab/ogrid-vue-vuetify'` - wrap in `<v-app>` for theming
173
- - **PrimeVue**: `from '@alaarab/ogrid-vue-primevue'`
174
- :::
175
-
176
- </TabItem>
177
- <TabItem value="js" label="Vanilla JS">
178
-
179
- ```js
180
-
181
- const grid = new OGrid(document.getElementById('grid'), {
182
- columns: [
183
- { columnId: 'name', name: 'Name', required: true },
184
- { columnId: 'email', name: 'Email' },
185
- { columnId: 'age', name: 'Age', type: 'numeric', defaultVisible: false },
186
- { columnId: 'department', name: 'Department' },
187
- {
188
- columnId: 'salary',
189
- name: 'Salary',
190
- type: 'numeric',
191
- valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
192
- },
193
- { columnId: 'startDate', name: 'Start Date', defaultVisible: false },
194
- ],
195
- data: people,
196
- getRowId: (p) => p.id,
197
- pageSize: 10,
198
- });
199
- ```
200
-
201
70
  </TabItem>
202
71
  </Tabs>
203
72