@ornery/ui-grid-react 0.1.4

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.
package/CLAUDE.md ADDED
@@ -0,0 +1,283 @@
1
+ # @ornery/ui-grid-react — React Wrapper
2
+
3
+ ## What to build
4
+
5
+ A React wrapper for the `@ornery/ui-grid` Angular library's pure-TypeScript core. This package publishes as `@ornery/ui-grid-react` and reuses 100% of the core logic — no code duplication. The React wrapper is a thin rendering layer.
6
+
7
+ ## Critical: Core reuse
8
+
9
+ The entire core is pure TypeScript with ZERO Angular dependencies. Import everything from the sibling library path. In this monorepo, the path alias `@ornery/ui-grid` maps to `projects/ui-grid/src/public-api.ts`.
10
+
11
+ **Core files to reuse (all pure TS, no Angular):**
12
+
13
+ - `grid.core.pipeline.ts` → `buildGridPipeline()` — the entire data pipeline
14
+ - `grid.api.ts` → `createGridApi()`, `UiGridApi` — the API object
15
+ - `grid.models.ts` → `GridOptions`, `GridColumnDef`, `GridRow`, `GridLabels`, `DEFAULT_GRID_LABELS`, etc.
16
+ - `grid.features.ts` → `FEATURE_SORTING`, `FEATURE_FILTERING`, etc. — build-time feature flags
17
+ - `grid.core.viewmodel.ts` → `resolveGridLabels()`, `gridSortButtonLabel()`, `gridSortAriaSort()`, all label functions
18
+ - `grid.core.display.ts` → `buildGridCellContext()`, `formatGridCellDisplayValue()`
19
+ - `grid.core.edit.ts` → `findNextGridCell()`, `isPrintableGridKey()`, `buildGridFocusCellResult()`, etc.
20
+ - `grid.core.export.ts` → `exportCsvRows()`, `headerLabel()`
21
+ - `grid.core.types.ts` → `DisplayItem`, `GroupItem`, `RowItem`, `ExpandableItem`, `PipelineResult`, `BuildGridPipelineContext`
22
+ - `grid.constants.ts` → `SORT_DIRECTIONS`, `FILTER_CONDITIONS`
23
+ - `grid.utils.ts` → `getCellValue`, `getPathValue`, `setPathValue`, `titleize`, etc.
24
+ - `row-searcher.ts` → `runColumnFilter`, `setupFilters`
25
+ - `row-sorter.ts` → `getSortFn`
26
+ - `ui-grid.commands.ts` → All command functions (pure TS, depends only on grid.api + grid.core)
27
+ - `ui-grid.events.ts` → All event raisers (pure TS, depends only on grid.api)
28
+ - `ui-grid.host.ts` → `downloadGridCsvFile()` (pure TS), `observeGridHostSize()` (pure TS)
29
+ - `i18n/en-US.json` → Default labels
30
+
31
+ **Do NOT copy any core files. Import them.**
32
+
33
+ ## File structure to create
34
+
35
+ ```
36
+ projects/ui-grid-react/
37
+ package.json
38
+ tsconfig.json
39
+ CLAUDE.md ← this file
40
+ src/
41
+ index.ts ← public API exports
42
+ UiGrid.tsx ← main React component
43
+ useGridState.ts ← state management hook (replaces Angular signals)
44
+ useVirtualScroll.ts ← fixed-size row virtualization hook
45
+ ui-grid.css ← styles adapted from grid.core.styles.scss
46
+ UiGrid.test.tsx ← tests with vitest + @testing-library/react
47
+ ```
48
+
49
+ ## package.json
50
+
51
+ ```json
52
+ {
53
+ "name": "@ornery/ui-grid-react",
54
+ "version": "0.1.0",
55
+ "description": "React wrapper for @ornery/ui-grid",
56
+ "main": "dist/index.js",
57
+ "module": "dist/index.mjs",
58
+ "types": "dist/index.d.ts",
59
+ "exports": {
60
+ ".": {
61
+ "import": "./dist/index.mjs",
62
+ "require": "./dist/index.js",
63
+ "types": "./dist/index.d.ts"
64
+ },
65
+ "./styles": "./dist/ui-grid.css"
66
+ },
67
+ "peerDependencies": {
68
+ "react": "^18.0.0 || ^19.0.0",
69
+ "react-dom": "^18.0.0 || ^19.0.0",
70
+ "@ornery/ui-grid": "^0.1.0"
71
+ },
72
+ "devDependencies": {
73
+ "react": "^19.1.0",
74
+ "react-dom": "^19.1.0",
75
+ "@testing-library/react": "^16.0.0",
76
+ "@types/react": "^19.0.0",
77
+ "@types/react-dom": "^19.0.0",
78
+ "typescript": "~5.8.0",
79
+ "vitest": "^4.1.0",
80
+ "jsdom": "^26.0.0",
81
+ "tsup": "^8.0.0"
82
+ },
83
+ "scripts": {
84
+ "build": "tsup src/index.ts --format esm,cjs --dts --external react --external react-dom --external @ornery/ui-grid",
85
+ "test": "vitest run",
86
+ "test:watch": "vitest"
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## tsconfig.json
92
+
93
+ Extend the root tsconfig. Add path alias for `@ornery/ui-grid`:
94
+
95
+ ```json
96
+ {
97
+ "extends": "../../tsconfig.json",
98
+ "compilerOptions": {
99
+ "jsx": "react-jsx",
100
+ "outDir": "./dist",
101
+ "declaration": true,
102
+ "declarationMap": true,
103
+ "paths": {
104
+ "@ornery/ui-grid": ["../ui-grid/src/public-api.ts"]
105
+ }
106
+ },
107
+ "include": ["src"]
108
+ }
109
+ ```
110
+
111
+ ## useVirtualScroll hook
112
+
113
+ A lightweight fixed-size virtualizer (~50 lines). No external dependency.
114
+
115
+ **Interface:**
116
+ ```ts
117
+ interface UseVirtualScrollOptions {
118
+ itemCount: number;
119
+ itemSize: number; // row height in px
120
+ viewportHeight: number; // container height in px
121
+ overscan?: number; // extra items above/below (default: 3)
122
+ }
123
+
124
+ interface UseVirtualScrollResult {
125
+ visibleRange: { start: number; end: number };
126
+ totalHeight: number;
127
+ offsetY: number;
128
+ onScroll: (event: React.UIEvent<HTMLDivElement>) => void;
129
+ viewportRef: React.RefObject<HTMLDivElement>;
130
+ scrollTop: number;
131
+ }
132
+ ```
133
+
134
+ **Implementation:**
135
+ - Track `scrollTop` via `useState`
136
+ - Calculate `start = Math.floor(scrollTop / itemSize) - overscan`
137
+ - Calculate `end = start + Math.ceil(viewportHeight / itemSize) + 2 * overscan`
138
+ - Clamp to `[0, itemCount)`
139
+ - `totalHeight = itemCount * itemSize`
140
+ - `offsetY = start * itemSize`
141
+ - Return a div ref and onScroll handler
142
+
143
+ ## useGridState hook
144
+
145
+ Replaces Angular signals with React state. This is the core bridge.
146
+
147
+ **Maps the Angular component's state 1:1:**
148
+
149
+ | Angular signal | React state |
150
+ |----------------|-------------|
151
+ | `activeFilters` | `useState<Record<string, string>>({})` |
152
+ | `groupByColumns` | `useState<string[]>([])` |
153
+ | `collapsedGroups` | `useState<Record<string, boolean>>({})` |
154
+ | `columnOrder` | `useState<string[]>([])` |
155
+ | `hiddenRowReasons` | `useState<Record<string, string[]>>({})` |
156
+ | `sortState` | `useState<SortState>(...)` |
157
+ | `focusedCell` | `useState<GridCellPosition \| null>(null)` |
158
+ | `editingCell` | `useState<GridCellPosition \| null>(null)` |
159
+ | `editingValue` | `useState('')` |
160
+ | `expandedRows` | `useState<Record<string, boolean>>({})` |
161
+ | `expandedTreeRows` | `useState<Record<string, boolean>>({})` |
162
+ | `currentPage` | `useState(1)` |
163
+ | `pageSize` | `useState(0)` |
164
+ | `benchmarkResult` | `useState<GridBenchmarkResult \| null>(null)` |
165
+ | `infiniteScrollState` | `useState<GridInfiniteScrollState>(...)` |
166
+
167
+ **Key behaviors:**
168
+ - Call `createGridApi()` once in a `useRef` with bindings that dispatch state updates
169
+ - Memoize `buildGridPipeline()` via `useMemo` dependent on all state inputs
170
+ - Memoize `visibleColumns` via `useMemo`
171
+ - Resolve `labels` via `useMemo(() => resolveGridLabels(options.labels), [options.labels])`
172
+ - Reset state when `options.id` changes (same as the Angular effect)
173
+ - Call `options.onRegisterApi?.(gridApi)` once
174
+
175
+ **Returns:**
176
+ - All computed values: `pipeline`, `visibleColumns`, `labels`, `gridTemplateColumns`, etc.
177
+ - All action dispatchers: `toggleSort()`, `updateFilter()`, `toggleGrouping()`, etc.
178
+ - `gridApi` ref
179
+
180
+ ## UiGrid.tsx component
181
+
182
+ **Props:**
183
+ ```tsx
184
+ interface UiGridProps {
185
+ options: GridOptions;
186
+ onRegisterApi?: (api: UiGridApi) => void;
187
+ /** Render prop for custom cell content. Return null to use default text. */
188
+ cellRenderer?: (context: GridCellTemplateContext) => React.ReactNode;
189
+ /** Render prop for expandable row content. */
190
+ expandableRenderer?: (context: GridExpandableTemplateContext) => React.ReactNode;
191
+ className?: string;
192
+ }
193
+ ```
194
+
195
+ **Rendering structure:** Match the Angular template exactly — same CSS classes, same `data-*` attributes, same ARIA roles/attributes, same part attributes. Reference the Angular template at `projects/ui-grid/src/lib/grid/ui-grid.component.html`.
196
+
197
+ **Key sections:**
198
+ 1. Hero header with title, benchmark button, export button, stats
199
+ 2. Metrics strip
200
+ 3. Grid frame (`role="grid"`) with:
201
+ - Header row (`role="row"`) with column headers (`role="columnheader"`, `aria-sort`)
202
+ - Sort buttons with SVG icons
203
+ - Group toggle buttons with SVG icons
204
+ - Filter row
205
+ - Display items via `ng-template` equivalent (just inline JSX):
206
+ - Group rows with disclosure chevron SVGs
207
+ - Expandable rows
208
+ - Data rows with cells (`role="gridcell"`, `tabindex="0"`)
209
+ - Tree toggle buttons with chevron SVGs
210
+ - Expand toggle buttons with chevron SVGs
211
+ - Cell editor input (when editing)
212
+ - Cell template / display value
213
+ - Virtual scroll viewport OR plain list
214
+ - Empty state
215
+ - Pagination footer with arrow SVG icons
216
+
217
+ **Feature flag guards:** Same pattern as Angular template — wrap sections in `{FEATURE_SORTING && ...}` etc.
218
+
219
+ **Focus management:** For cell focus/editor focus, use `useRef` + `useEffect` instead of the Angular `focusGridRenderedCell`/`focusGridEditor` (those use shadowRoot which React won't have). Query the grid container ref directly.
220
+
221
+ **Keyboard handling:** Port `handleCellKeyDown` and `handleEditorKeyDown` logic directly — it's all pure key checking + command dispatch.
222
+
223
+ ## Styles (ui-grid.css)
224
+
225
+ Adapt from `projects/ui-grid/src/lib/grid/grid.core.styles.scss`:
226
+ - Replace `:host` selectors with `.ui-grid-host`
227
+ - Replace `:host *` with `.ui-grid-host *`
228
+ - Keep ALL CSS custom properties identical (same `--ui-grid-*` variables)
229
+ - Keep all class names identical
230
+ - Add `.ui-grid-host { display: block; color: var(--ui-grid-cell-color); }`
231
+ - Ship as plain CSS (no modules needed — class names are scoped by convention)
232
+
233
+ ## Tests
234
+
235
+ Use vitest + @testing-library/react + jsdom.
236
+
237
+ **Port these key scenarios from the Angular spec:**
238
+ 1. Registers the API and renders headers and rows
239
+ 2. Filters rows and renders empty state
240
+ 3. Sorts rows and cycles sort state from header button
241
+ 4. Groups rows and collapses groups
242
+ 5. Exports visible rows as CSV
243
+ 6. Virtualizes rows when count crosses threshold
244
+ 7. Paginates rows
245
+ 8. Keyboard cell editing (commit, navigate, cancel)
246
+ 9. Resolves custom i18n label overrides
247
+ 10. Feature flags disable unused template sections
248
+
249
+ ## Public API (index.ts)
250
+
251
+ ```ts
252
+ export { UiGrid } from './UiGrid';
253
+ export type { UiGridProps } from './UiGrid';
254
+ export { useGridState } from './useGridState';
255
+ export { useVirtualScroll } from './useVirtualScroll';
256
+
257
+ // Re-export core types consumers need
258
+ export type {
259
+ GridOptions,
260
+ GridColumnDef,
261
+ GridRow,
262
+ GridRecord,
263
+ GridLabels,
264
+ GridCellTemplateContext,
265
+ GridExpandableTemplateContext,
266
+ GridCellEditableContext,
267
+ GridBenchmarkResult,
268
+ GridSavedState,
269
+ SortState,
270
+ } from '@ornery/ui-grid';
271
+
272
+ export type { UiGridApi } from '@ornery/ui-grid';
273
+ export { DEFAULT_GRID_LABELS } from '@ornery/ui-grid';
274
+ ```
275
+
276
+ ## Important notes
277
+
278
+ - Do NOT use Shadow DOM — React doesn't support it well. Use a regular div with `className="ui-grid-host"`.
279
+ - Do NOT add any Angular dependencies.
280
+ - The `GridOptions.cellTemplate` field is `TemplateRef` (Angular-specific). The React wrapper ignores it and uses the `cellRenderer` prop instead.
281
+ - Same for `expandableRowTemplate` → use `expandableRenderer` prop.
282
+ - The `GridOptions.onRegisterApi` still works — it's called with the same `UiGridApi` object.
283
+ - Keep the `GridColumnDef.cellRenderer` function (returns string) — it's already framework-agnostic.
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>UI Grid React Demo</title>
7
+ <style>
8
+ *, *::before, *::after { box-sizing: border-box; margin: 0; }
9
+ body { font-family: system-ui, -apple-system, sans-serif; background: #f5f5f7; color: #1d1d1f; }
10
+ </style>
11
+ </head>
12
+ <body>
13
+ <div id="root"></div>
14
+ <script type="module" src="./main.tsx"></script>
15
+ </body>
16
+ </html>
package/demo/main.tsx ADDED
@@ -0,0 +1,95 @@
1
+ import React, { useState, useMemo } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { UiGrid } from '../src/index';
4
+ import type { GridOptions, UiGridApi } from '../src/index';
5
+ import { FILTER_CONDITIONS } from '@ornery/ui-grid';
6
+ import '../src/ui-grid.css';
7
+
8
+ const statuses = ['Active', 'Expansion', 'Enterprise', 'Pilot'] as const;
9
+ const companies = ['Northwind', 'Blue Harbor', 'Forge Group', 'Larkspur', 'Atlas'] as const;
10
+ const owners = ['Casey Tran', 'Jordan Silva', 'Priya Rao', 'Evan Brooks', 'Mina Patel'] as const;
11
+
12
+ function createDemoData(count = 100_000) {
13
+ return Array.from({ length: count }, (_, i) => ({
14
+ id: `row-${i + 1}`,
15
+ name: `Customer ${i + 1}`,
16
+ company: companies[i % companies.length],
17
+ revenue: 40000 + i * 1350,
18
+ status: statuses[i % statuses.length],
19
+ renewalDate: `2026-${String((i % 12) + 1).padStart(2, '0')}-${String((i % 27) + 1).padStart(2, '0')}`,
20
+ account: { owner: owners[i % owners.length] },
21
+ }));
22
+ }
23
+
24
+ const currencyFormat = new Intl.NumberFormat('en-US', {
25
+ style: 'currency',
26
+ currency: 'USD',
27
+ maximumFractionDigits: 0,
28
+ });
29
+
30
+ function App() {
31
+ const [gridApi, setGridApi] = useState<UiGridApi | null>(null);
32
+ const data = useMemo(() => createDemoData(), []);
33
+
34
+ const options = useMemo<GridOptions>(
35
+ () => ({
36
+ id: 'react-demo-grid',
37
+ title: 'UI Grid React Demo',
38
+ emptyMessage: 'No rows match the current filters.',
39
+ rowHeight: 48,
40
+ viewportHeight: 620,
41
+ enableSorting: true,
42
+ enableFiltering: true,
43
+ enableGrouping: true,
44
+ enableColumnMoving: true,
45
+ enableVirtualization: true,
46
+ enableCellEditOnFocus: true,
47
+ virtualizationThreshold: 25,
48
+ grouping: { groupBy: ['status'] },
49
+ rowIdentity: (row) => String(row['id']),
50
+ onRegisterApi: (api) => setGridApi(api as UiGridApi),
51
+ columnDefs: [
52
+ {
53
+ name: 'name',
54
+ displayName: 'Customer',
55
+ width: 'minmax(14rem, 1.2fr)',
56
+ enableCellEdit: true,
57
+ },
58
+ { name: 'company', width: 'minmax(12rem, 1fr)', enableCellEdit: true },
59
+ {
60
+ name: 'revenue',
61
+ type: 'number',
62
+ align: 'end',
63
+ width: 'minmax(10rem, 0.7fr)',
64
+ filter: { condition: FILTER_CONDITIONS.greaterThan },
65
+ formatter: (value) => currencyFormat.format(Number(value ?? 0)),
66
+ },
67
+ {
68
+ name: 'status',
69
+ width: 'minmax(8rem, 0.7fr)',
70
+ filter: { condition: FILTER_CONDITIONS.exact },
71
+ },
72
+ {
73
+ name: 'renewalDate',
74
+ type: 'date',
75
+ displayName: 'Renewal',
76
+ width: 'minmax(11rem, 0.8fr)',
77
+ formatter: (value) => new Date(String(value)).toLocaleDateString('en-US'),
78
+ },
79
+ {
80
+ name: 'owner',
81
+ field: 'account.owner',
82
+ displayName: 'Account Owner',
83
+ width: 'minmax(11rem, 0.8fr)',
84
+ enableCellEdit: true,
85
+ },
86
+ ],
87
+ data,
88
+ }),
89
+ [data],
90
+ );
91
+
92
+ return <UiGrid options={options} onRegisterApi={options.onRegisterApi} />;
93
+ }
94
+
95
+ createRoot(document.getElementById('root')!).render(<App />);
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import path from 'path';
4
+
5
+ export default defineConfig({
6
+ root: __dirname,
7
+ plugins: [react()],
8
+ resolve: {
9
+ alias: {
10
+ '@ornery/ui-grid': path.resolve(__dirname, '../../ui-grid/src/public-api.react.ts'),
11
+ },
12
+ },
13
+ });
@@ -0,0 +1,133 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React$1 from 'react';
3
+ import { GridOptions, UiGridApi, GridCellTemplateContext, GridExpandableTemplateContext, PipelineResult, GridColumnDef, GridLabels, SortState, GridCellPosition, GridBenchmarkResult, GridInfiniteScrollState, DisplayItem, GroupItem, ExpandableItem, RowItem, GridRow } from '@ornery/ui-grid';
4
+ export { DEFAULT_GRID_LABELS, GridBenchmarkResult, GridCellEditableContext, GridCellTemplateContext, GridColumnDef, GridExpandableTemplateContext, GridLabels, GridOptions, GridRecord, GridRow, GridSavedState, SortState, UiGridApi } from '@ornery/ui-grid';
5
+
6
+ interface UiGridProps {
7
+ options: GridOptions;
8
+ onRegisterApi?: (api: UiGridApi) => void;
9
+ cellRenderer?: (context: GridCellTemplateContext) => React$1.ReactNode;
10
+ expandableRenderer?: (context: GridExpandableTemplateContext) => React$1.ReactNode;
11
+ className?: string;
12
+ }
13
+ declare function UiGrid({ options, onRegisterApi, cellRenderer, expandableRenderer, className }: UiGridProps): react_jsx_runtime.JSX.Element;
14
+
15
+ interface UseGridStateResult {
16
+ pipeline: PipelineResult;
17
+ visibleColumns: GridColumnDef[];
18
+ labels: GridLabels;
19
+ gridTemplateColumns: string;
20
+ gridApi: UiGridApi;
21
+ gridContainerRef: React.RefObject<HTMLDivElement | null>;
22
+ activeFilters: Record<string, string>;
23
+ groupByColumns: string[];
24
+ collapsedGroups: Record<string, boolean>;
25
+ sortState: SortState;
26
+ focusedCell: GridCellPosition | null;
27
+ editingCell: GridCellPosition | null;
28
+ editingValue: string;
29
+ expandedRows: Record<string, boolean>;
30
+ expandedTreeRows: Record<string, boolean>;
31
+ currentPage: number;
32
+ pageSize: number;
33
+ benchmarkResult: GridBenchmarkResult | null;
34
+ infiniteScrollState: GridInfiniteScrollState;
35
+ totalRows: number;
36
+ visibleRowCount: number;
37
+ displayItems: DisplayItem[];
38
+ virtualizationEnabled: boolean;
39
+ pipelineMs: number;
40
+ paginationCurrentPage: number;
41
+ paginationTotalPages: number;
42
+ paginationSelectedPageSize: number;
43
+ rowSize: number;
44
+ viewportHeightPx: string;
45
+ headerLabel: (column: GridColumnDef) => string;
46
+ isGroupItem: (item: DisplayItem) => item is GroupItem;
47
+ isExpandableItem: (item: DisplayItem) => item is ExpandableItem;
48
+ isRowItem: (item: DisplayItem) => item is RowItem;
49
+ isOddStripedRow: (item: DisplayItem) => boolean;
50
+ sortButtonLabel: (column: GridColumnDef) => string;
51
+ sortAriaSort: (column: GridColumnDef) => string;
52
+ sortDirection: (column: GridColumnDef) => string;
53
+ groupingButtonLabel: (column: GridColumnDef) => string;
54
+ filterValue: (columnName: string) => string;
55
+ filterPlaceholder: (column: GridColumnDef) => string;
56
+ isFilterInputDisabled: (column: GridColumnDef) => boolean;
57
+ groupDisclosureLabel: (item: GroupItem) => string;
58
+ displayValue: (row: GridRow, column: GridColumnDef) => string;
59
+ isFocusedCell: (row: GridRow, column: GridColumnDef) => boolean;
60
+ isEditingCell: (row: GridRow, column: GridColumnDef) => boolean;
61
+ editorInputType: (column: GridColumnDef) => string;
62
+ cellContext: (row: GridRow, column: GridColumnDef) => GridCellTemplateContext;
63
+ expandedContext: (row: GridRow) => GridExpandableTemplateContext & Record<string, unknown>;
64
+ columnWidth: (column: GridColumnDef) => string;
65
+ isColumnSortable: (column: GridColumnDef) => boolean;
66
+ isColumnFilterable: (column: GridColumnDef) => boolean;
67
+ cellIndent: (row: GridRow, column: GridColumnDef) => string;
68
+ treeToggleLabel: (row: GridRow) => string;
69
+ isTreeRowExpanded: (row: GridRow) => boolean;
70
+ expandToggleLabel: (row: GridRow) => string;
71
+ isGrouped: (column: GridColumnDef) => boolean;
72
+ showTreeToggle: (row: GridRow, column: GridColumnDef) => boolean;
73
+ showExpandToggle: (row: GridRow, column: GridColumnDef) => boolean;
74
+ showPaginationControls: () => boolean;
75
+ paginationSummary: () => string;
76
+ pageSizeOptions: () => number[];
77
+ isCellEditable: (row: GridRow, column: GridColumnDef, triggerEvent?: Event | KeyboardEvent | null) => boolean;
78
+ shouldEditOnFocus: (column: GridColumnDef) => boolean;
79
+ sortingFeature: boolean;
80
+ filteringFeature: boolean;
81
+ groupingFeature: boolean;
82
+ paginationFeature: boolean;
83
+ cellEditFeature: boolean;
84
+ expandableFeature: boolean;
85
+ treeViewFeature: boolean;
86
+ infiniteScrollFeature: boolean;
87
+ columnMovingFeature: boolean;
88
+ csvExportFeature: boolean;
89
+ isGroupingEnabled: () => boolean;
90
+ isFilteringEnabled: () => boolean;
91
+ toggleSort: (column: GridColumnDef) => void;
92
+ updateFilter: (columnName: string, value: string) => void;
93
+ clearAllFilters: () => void;
94
+ toggleGrouping: (column: GridColumnDef, event?: React.MouseEvent) => void;
95
+ toggleGroup: (item: GroupItem) => void;
96
+ focusCell: (row: GridRow, column: GridColumnDef, triggerEvent?: Event | KeyboardEvent | null) => void;
97
+ handleCellKeyDown: (row: GridRow, column: GridColumnDef, event: React.KeyboardEvent) => void;
98
+ handleCellDoubleClick: (row: GridRow, column: GridColumnDef, event: React.MouseEvent) => void;
99
+ updateEditingValue: (value: string) => void;
100
+ handleEditorKeyDown: (event: React.KeyboardEvent) => void;
101
+ handleEditorBlur: (event: React.FocusEvent) => void;
102
+ toggleRowExpansion: (row: GridRow, event?: React.MouseEvent) => void;
103
+ toggleTreeRow: (row: GridRow, event?: React.MouseEvent) => void;
104
+ moveColumn: (fromIndex: number, toIndex: number) => void;
105
+ nextPage: () => void;
106
+ previousPage: () => void;
107
+ onPageSizeChange: (value: string) => void;
108
+ runBenchmark: (iterations?: number) => GridBenchmarkResult;
109
+ exportCsv: () => void;
110
+ onViewportScroll: (startIndex: number) => void;
111
+ }
112
+ declare function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridApi) => void): UseGridStateResult;
113
+
114
+ interface UseVirtualScrollOptions {
115
+ itemCount: number;
116
+ itemSize: number;
117
+ viewportHeight: number;
118
+ overscan?: number;
119
+ }
120
+ interface UseVirtualScrollResult {
121
+ visibleRange: {
122
+ start: number;
123
+ end: number;
124
+ };
125
+ totalHeight: number;
126
+ offsetY: number;
127
+ onScroll: (event: React.UIEvent<HTMLDivElement>) => void;
128
+ viewportRef: React.RefObject<HTMLDivElement | null>;
129
+ scrollTop: number;
130
+ }
131
+ declare function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualScrollResult;
132
+
133
+ export { UiGrid, type UiGridProps, type UseGridStateResult, type UseVirtualScrollOptions, type UseVirtualScrollResult, useGridState, useVirtualScroll };
@@ -0,0 +1,133 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React$1 from 'react';
3
+ import { GridOptions, UiGridApi, GridCellTemplateContext, GridExpandableTemplateContext, PipelineResult, GridColumnDef, GridLabels, SortState, GridCellPosition, GridBenchmarkResult, GridInfiniteScrollState, DisplayItem, GroupItem, ExpandableItem, RowItem, GridRow } from '@ornery/ui-grid';
4
+ export { DEFAULT_GRID_LABELS, GridBenchmarkResult, GridCellEditableContext, GridCellTemplateContext, GridColumnDef, GridExpandableTemplateContext, GridLabels, GridOptions, GridRecord, GridRow, GridSavedState, SortState, UiGridApi } from '@ornery/ui-grid';
5
+
6
+ interface UiGridProps {
7
+ options: GridOptions;
8
+ onRegisterApi?: (api: UiGridApi) => void;
9
+ cellRenderer?: (context: GridCellTemplateContext) => React$1.ReactNode;
10
+ expandableRenderer?: (context: GridExpandableTemplateContext) => React$1.ReactNode;
11
+ className?: string;
12
+ }
13
+ declare function UiGrid({ options, onRegisterApi, cellRenderer, expandableRenderer, className }: UiGridProps): react_jsx_runtime.JSX.Element;
14
+
15
+ interface UseGridStateResult {
16
+ pipeline: PipelineResult;
17
+ visibleColumns: GridColumnDef[];
18
+ labels: GridLabels;
19
+ gridTemplateColumns: string;
20
+ gridApi: UiGridApi;
21
+ gridContainerRef: React.RefObject<HTMLDivElement | null>;
22
+ activeFilters: Record<string, string>;
23
+ groupByColumns: string[];
24
+ collapsedGroups: Record<string, boolean>;
25
+ sortState: SortState;
26
+ focusedCell: GridCellPosition | null;
27
+ editingCell: GridCellPosition | null;
28
+ editingValue: string;
29
+ expandedRows: Record<string, boolean>;
30
+ expandedTreeRows: Record<string, boolean>;
31
+ currentPage: number;
32
+ pageSize: number;
33
+ benchmarkResult: GridBenchmarkResult | null;
34
+ infiniteScrollState: GridInfiniteScrollState;
35
+ totalRows: number;
36
+ visibleRowCount: number;
37
+ displayItems: DisplayItem[];
38
+ virtualizationEnabled: boolean;
39
+ pipelineMs: number;
40
+ paginationCurrentPage: number;
41
+ paginationTotalPages: number;
42
+ paginationSelectedPageSize: number;
43
+ rowSize: number;
44
+ viewportHeightPx: string;
45
+ headerLabel: (column: GridColumnDef) => string;
46
+ isGroupItem: (item: DisplayItem) => item is GroupItem;
47
+ isExpandableItem: (item: DisplayItem) => item is ExpandableItem;
48
+ isRowItem: (item: DisplayItem) => item is RowItem;
49
+ isOddStripedRow: (item: DisplayItem) => boolean;
50
+ sortButtonLabel: (column: GridColumnDef) => string;
51
+ sortAriaSort: (column: GridColumnDef) => string;
52
+ sortDirection: (column: GridColumnDef) => string;
53
+ groupingButtonLabel: (column: GridColumnDef) => string;
54
+ filterValue: (columnName: string) => string;
55
+ filterPlaceholder: (column: GridColumnDef) => string;
56
+ isFilterInputDisabled: (column: GridColumnDef) => boolean;
57
+ groupDisclosureLabel: (item: GroupItem) => string;
58
+ displayValue: (row: GridRow, column: GridColumnDef) => string;
59
+ isFocusedCell: (row: GridRow, column: GridColumnDef) => boolean;
60
+ isEditingCell: (row: GridRow, column: GridColumnDef) => boolean;
61
+ editorInputType: (column: GridColumnDef) => string;
62
+ cellContext: (row: GridRow, column: GridColumnDef) => GridCellTemplateContext;
63
+ expandedContext: (row: GridRow) => GridExpandableTemplateContext & Record<string, unknown>;
64
+ columnWidth: (column: GridColumnDef) => string;
65
+ isColumnSortable: (column: GridColumnDef) => boolean;
66
+ isColumnFilterable: (column: GridColumnDef) => boolean;
67
+ cellIndent: (row: GridRow, column: GridColumnDef) => string;
68
+ treeToggleLabel: (row: GridRow) => string;
69
+ isTreeRowExpanded: (row: GridRow) => boolean;
70
+ expandToggleLabel: (row: GridRow) => string;
71
+ isGrouped: (column: GridColumnDef) => boolean;
72
+ showTreeToggle: (row: GridRow, column: GridColumnDef) => boolean;
73
+ showExpandToggle: (row: GridRow, column: GridColumnDef) => boolean;
74
+ showPaginationControls: () => boolean;
75
+ paginationSummary: () => string;
76
+ pageSizeOptions: () => number[];
77
+ isCellEditable: (row: GridRow, column: GridColumnDef, triggerEvent?: Event | KeyboardEvent | null) => boolean;
78
+ shouldEditOnFocus: (column: GridColumnDef) => boolean;
79
+ sortingFeature: boolean;
80
+ filteringFeature: boolean;
81
+ groupingFeature: boolean;
82
+ paginationFeature: boolean;
83
+ cellEditFeature: boolean;
84
+ expandableFeature: boolean;
85
+ treeViewFeature: boolean;
86
+ infiniteScrollFeature: boolean;
87
+ columnMovingFeature: boolean;
88
+ csvExportFeature: boolean;
89
+ isGroupingEnabled: () => boolean;
90
+ isFilteringEnabled: () => boolean;
91
+ toggleSort: (column: GridColumnDef) => void;
92
+ updateFilter: (columnName: string, value: string) => void;
93
+ clearAllFilters: () => void;
94
+ toggleGrouping: (column: GridColumnDef, event?: React.MouseEvent) => void;
95
+ toggleGroup: (item: GroupItem) => void;
96
+ focusCell: (row: GridRow, column: GridColumnDef, triggerEvent?: Event | KeyboardEvent | null) => void;
97
+ handleCellKeyDown: (row: GridRow, column: GridColumnDef, event: React.KeyboardEvent) => void;
98
+ handleCellDoubleClick: (row: GridRow, column: GridColumnDef, event: React.MouseEvent) => void;
99
+ updateEditingValue: (value: string) => void;
100
+ handleEditorKeyDown: (event: React.KeyboardEvent) => void;
101
+ handleEditorBlur: (event: React.FocusEvent) => void;
102
+ toggleRowExpansion: (row: GridRow, event?: React.MouseEvent) => void;
103
+ toggleTreeRow: (row: GridRow, event?: React.MouseEvent) => void;
104
+ moveColumn: (fromIndex: number, toIndex: number) => void;
105
+ nextPage: () => void;
106
+ previousPage: () => void;
107
+ onPageSizeChange: (value: string) => void;
108
+ runBenchmark: (iterations?: number) => GridBenchmarkResult;
109
+ exportCsv: () => void;
110
+ onViewportScroll: (startIndex: number) => void;
111
+ }
112
+ declare function useGridState(options: GridOptions, onRegisterApi?: (api: UiGridApi) => void): UseGridStateResult;
113
+
114
+ interface UseVirtualScrollOptions {
115
+ itemCount: number;
116
+ itemSize: number;
117
+ viewportHeight: number;
118
+ overscan?: number;
119
+ }
120
+ interface UseVirtualScrollResult {
121
+ visibleRange: {
122
+ start: number;
123
+ end: number;
124
+ };
125
+ totalHeight: number;
126
+ offsetY: number;
127
+ onScroll: (event: React.UIEvent<HTMLDivElement>) => void;
128
+ viewportRef: React.RefObject<HTMLDivElement | null>;
129
+ scrollTop: number;
130
+ }
131
+ declare function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualScrollResult;
132
+
133
+ export { UiGrid, type UiGridProps, type UseGridStateResult, type UseVirtualScrollOptions, type UseVirtualScrollResult, useGridState, useVirtualScroll };