react-open-source-grid 1.5.3 → 1.5.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.
Files changed (89) hide show
  1. package/dist/lib/App.d.ts +3 -0
  2. package/dist/lib/chunk-FG3FLQAE.js +296 -0
  3. package/dist/lib/components/AccessibilityDemo.d.ts +8 -0
  4. package/dist/lib/components/ApiReferencePage.d.ts +2 -0
  5. package/dist/lib/components/BenchmarkDemo.d.ts +2 -0
  6. package/dist/lib/components/CellRenderersDemo.d.ts +16 -0
  7. package/dist/lib/components/CodeBlock.d.ts +10 -0
  8. package/dist/lib/components/ColumnFiltersDemo.d.ts +5 -0
  9. package/dist/lib/components/CompleteApiReferencePage.d.ts +2 -0
  10. package/dist/lib/components/ContextMenuDemo.d.ts +12 -0
  11. package/dist/lib/components/DataGrid/ARCHITECTURE.md.d.ts +288 -0
  12. package/dist/lib/components/DataGrid/AdvancedFilterBuilder.d.ts +12 -0
  13. package/dist/lib/components/DataGrid/CellRenderers.d.ts +64 -0
  14. package/dist/lib/components/DataGrid/ColumnChooser.d.ts +12 -0
  15. package/dist/lib/components/DataGrid/ColumnFilters.d.ts +16 -0
  16. package/dist/lib/components/DataGrid/ContextMenu.d.ts +10 -0
  17. package/dist/lib/components/DataGrid/DataGrid.d.ts +22 -0
  18. package/dist/lib/components/DataGrid/DensityToggle.d.ts +23 -0
  19. package/dist/lib/components/DataGrid/DragHandle.d.ts +7 -0
  20. package/dist/lib/components/DataGrid/DraggableRow.d.ts +14 -0
  21. package/dist/lib/components/DataGrid/ExportMenu.d.ts +12 -0
  22. package/dist/lib/components/DataGrid/FacetedSearch.d.ts +29 -0
  23. package/dist/lib/components/DataGrid/FilteredSearchBar.d.ts +36 -0
  24. package/dist/lib/components/DataGrid/FocusTrap.d.ts +12 -0
  25. package/dist/lib/components/DataGrid/GridApiDemo.d.ts +6 -0
  26. package/dist/lib/components/DataGrid/GridBody.d.ts +42 -0
  27. package/dist/lib/components/DataGrid/GridFooter.d.ts +18 -0
  28. package/dist/lib/components/DataGrid/GridHeader.d.ts +18 -0
  29. package/dist/lib/components/DataGrid/GridPagination.d.ts +10 -0
  30. package/dist/lib/components/DataGrid/GroupByPanel.d.ts +9 -0
  31. package/dist/lib/components/DataGrid/GroupRow.d.ts +31 -0
  32. package/dist/lib/components/DataGrid/InfiniteScrollDataGrid.d.ts +39 -0
  33. package/dist/lib/components/DataGrid/LayoutPresetsManager.d.ts +11 -0
  34. package/dist/lib/components/DataGrid/MarketDataEngine.d.ts +165 -0
  35. package/dist/lib/components/DataGrid/MarketDataGrid.d.ts +33 -0
  36. package/dist/lib/components/DataGrid/MarketDataGridUtils.d.ts +13 -0
  37. package/dist/lib/components/DataGrid/ScreenReaderAnnouncer.d.ts +8 -0
  38. package/dist/lib/components/DataGrid/ServerSideDataSource.d.ts +136 -0
  39. package/dist/lib/components/DataGrid/ThemeSelector.d.ts +12 -0
  40. package/dist/lib/components/DataGrid/Tooltip.d.ts +15 -0
  41. package/dist/lib/components/DataGrid/TreeRow.d.ts +31 -0
  42. package/dist/lib/components/DataGrid/VirtualScroller.d.ts +35 -0
  43. package/dist/lib/components/DataGrid/WebSocketMockFeed.d.ts +121 -0
  44. package/dist/lib/components/DataGrid/aggregationUtils.d.ts +25 -0
  45. package/dist/lib/components/DataGrid/contextMenuUtils.d.ts +36 -0
  46. package/dist/lib/components/DataGrid/demos/TooltipDemo.d.ts +1 -0
  47. package/dist/lib/components/DataGrid/densityModes.d.ts +42 -0
  48. package/dist/lib/components/DataGrid/dragRowUtils.d.ts +98 -0
  49. package/dist/lib/components/DataGrid/exportUtils.d.ts +30 -0
  50. package/dist/lib/components/DataGrid/filterUtils.d.ts +17 -0
  51. package/dist/lib/components/DataGrid/gridApi.d.ts +142 -0
  52. package/dist/lib/components/DataGrid/gridApi.types.d.ts +348 -0
  53. package/dist/lib/components/DataGrid/gridReducer.d.ts +4 -0
  54. package/dist/lib/components/DataGrid/groupingUtils.d.ts +17 -0
  55. package/dist/lib/components/DataGrid/index.d.ts +41 -0
  56. package/dist/lib/components/DataGrid/layoutPersistence.d.ts +95 -0
  57. package/dist/lib/components/DataGrid/themes.d.ts +113 -0
  58. package/dist/lib/components/DataGrid/treeDataUtils.d.ts +97 -0
  59. package/dist/lib/components/DataGrid/types.d.ts +536 -0
  60. package/dist/lib/components/DataGrid/useContextMenu.d.ts +31 -0
  61. package/dist/lib/components/DataGrid/useDensityMode.d.ts +36 -0
  62. package/dist/lib/components/DataGrid/useFocusTrap.d.ts +14 -0
  63. package/dist/lib/components/DataGrid/useMarketData.d.ts +57 -0
  64. package/dist/lib/components/DataGrid/useScreenReaderAnnouncements.d.ts +23 -0
  65. package/dist/lib/components/DataGrid/useTooltip.d.ts +21 -0
  66. package/dist/lib/components/DemoGridPage.d.ts +2 -0
  67. package/dist/lib/components/DensityModeDemo.d.ts +12 -0
  68. package/dist/lib/components/FacetedSearchDemo.d.ts +8 -0
  69. package/dist/lib/components/FeatureGallery.d.ts +2 -0
  70. package/dist/lib/components/FilteredSearchDemo.d.ts +7 -0
  71. package/dist/lib/components/GridApiDemoPage.d.ts +2 -0
  72. package/dist/lib/components/HomePage.d.ts +1 -0
  73. package/dist/lib/components/InfiniteScrollDemo.d.ts +13 -0
  74. package/dist/lib/components/LayoutPersistenceDemo.d.ts +2 -0
  75. package/dist/lib/components/LiveMarketDemo.d.ts +18 -0
  76. package/dist/lib/components/MarketDataExamples.d.ts +42 -0
  77. package/dist/lib/components/RowDraggingDemo.d.ts +3 -0
  78. package/dist/lib/components/RowPinningDemo.d.ts +12 -0
  79. package/dist/lib/components/ThemesDemo.d.ts +17 -0
  80. package/dist/lib/components/TooltipDemo.d.ts +1 -0
  81. package/dist/lib/components/TreeDataDemo.d.ts +3 -0
  82. package/dist/lib/components/VirtualScrollDemo.d.ts +13 -0
  83. package/dist/lib/index.cjs +12233 -0
  84. package/dist/lib/index.css +465 -0
  85. package/dist/lib/index.d.ts +1 -0
  86. package/dist/lib/index.js +11827 -0
  87. package/dist/lib/layoutPersistence-2MPTAEYI.js +20 -0
  88. package/dist/lib/main.d.ts +1 -0
  89. package/package.json +2 -2
@@ -0,0 +1,3 @@
1
+ import './App.css';
2
+ declare function App(): import("react/jsx-runtime").JSX.Element;
3
+ export default App;
@@ -0,0 +1,296 @@
1
+ // src/components/DataGrid/layoutPersistence.ts
2
+ var LocalStorageAdapter = class {
3
+ async save(key, preset) {
4
+ try {
5
+ const existingData = localStorage.getItem(key);
6
+ const presets = existingData ? JSON.parse(existingData) : [];
7
+ const index = presets.findIndex((p) => p.id === preset.id);
8
+ if (index !== -1) {
9
+ presets[index] = preset;
10
+ } else {
11
+ presets.push(preset);
12
+ }
13
+ localStorage.setItem(key, JSON.stringify(presets));
14
+ } catch (error) {
15
+ console.error("Failed to save preset to localStorage:", error);
16
+ throw error;
17
+ }
18
+ }
19
+ async load(key, presetId) {
20
+ try {
21
+ const data = localStorage.getItem(key);
22
+ if (!data) return null;
23
+ const presets = JSON.parse(data);
24
+ if (presetId) {
25
+ return presets.find((p) => p.id === presetId) || null;
26
+ }
27
+ return presets;
28
+ } catch (error) {
29
+ console.error("Failed to load preset from localStorage:", error);
30
+ throw error;
31
+ }
32
+ }
33
+ async delete(key, presetId) {
34
+ try {
35
+ const data = localStorage.getItem(key);
36
+ if (!data) return;
37
+ const presets = JSON.parse(data);
38
+ const filtered = presets.filter((p) => p.id !== presetId);
39
+ localStorage.setItem(key, JSON.stringify(filtered));
40
+ } catch (error) {
41
+ console.error("Failed to delete preset from localStorage:", error);
42
+ throw error;
43
+ }
44
+ }
45
+ async list(key) {
46
+ try {
47
+ const data = localStorage.getItem(key);
48
+ if (!data) return [];
49
+ return JSON.parse(data);
50
+ } catch (error) {
51
+ console.error("Failed to list presets from localStorage:", error);
52
+ throw error;
53
+ }
54
+ }
55
+ };
56
+ var ServerAdapter = class {
57
+ config;
58
+ constructor(config) {
59
+ this.config = config;
60
+ }
61
+ async save(key, preset) {
62
+ const endpoint = this.config.saveEndpoint || `${this.config.baseUrl}/layouts`;
63
+ try {
64
+ const response = await fetch(endpoint, {
65
+ method: "POST",
66
+ headers: {
67
+ "Content-Type": "application/json",
68
+ ...this.config.headers
69
+ },
70
+ body: JSON.stringify({ key, preset })
71
+ });
72
+ if (!response.ok) {
73
+ throw new Error(`Server responded with ${response.status}`);
74
+ }
75
+ } catch (error) {
76
+ console.error("Failed to save preset to server:", error);
77
+ throw error;
78
+ }
79
+ }
80
+ async load(key, presetId) {
81
+ const endpoint = this.config.loadEndpoint || `${this.config.baseUrl}/layouts`;
82
+ const url = presetId ? `${endpoint}/${key}/${presetId}` : `${endpoint}/${key}`;
83
+ try {
84
+ const response = await fetch(url, {
85
+ method: "GET",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ ...this.config.headers
89
+ }
90
+ });
91
+ if (response.status === 404) {
92
+ return null;
93
+ }
94
+ if (!response.ok) {
95
+ throw new Error(`Server responded with ${response.status}`);
96
+ }
97
+ return await response.json();
98
+ } catch (error) {
99
+ console.error("Failed to load preset from server:", error);
100
+ throw error;
101
+ }
102
+ }
103
+ async delete(key, presetId) {
104
+ const endpoint = this.config.deleteEndpoint || `${this.config.baseUrl}/layouts`;
105
+ const url = `${endpoint}/${key}/${presetId}`;
106
+ try {
107
+ const response = await fetch(url, {
108
+ method: "DELETE",
109
+ headers: this.config.headers
110
+ });
111
+ if (!response.ok) {
112
+ throw new Error(`Server responded with ${response.status}`);
113
+ }
114
+ } catch (error) {
115
+ console.error("Failed to delete preset from server:", error);
116
+ throw error;
117
+ }
118
+ }
119
+ async list(key) {
120
+ const endpoint = this.config.listEndpoint || `${this.config.baseUrl}/layouts`;
121
+ const url = `${endpoint}/${key}`;
122
+ try {
123
+ const response = await fetch(url, {
124
+ method: "GET",
125
+ headers: {
126
+ "Content-Type": "application/json",
127
+ ...this.config.headers
128
+ }
129
+ });
130
+ if (response.status === 404) {
131
+ return [];
132
+ }
133
+ if (!response.ok) {
134
+ throw new Error(`Server responded with ${response.status}`);
135
+ }
136
+ return await response.json();
137
+ } catch (error) {
138
+ console.error("Failed to list presets from server:", error);
139
+ throw error;
140
+ }
141
+ }
142
+ };
143
+ var UserProfileAdapter = class {
144
+ config;
145
+ baseAdapter;
146
+ constructor(config) {
147
+ this.config = config;
148
+ this.baseAdapter = config.adapter || new LocalStorageAdapter();
149
+ }
150
+ getUserKey(key) {
151
+ const profileKey = this.config.profileKey || "user-layouts";
152
+ return `${profileKey}:${this.config.userId}:${key}`;
153
+ }
154
+ async save(key, preset) {
155
+ return this.baseAdapter.save(this.getUserKey(key), preset);
156
+ }
157
+ async load(key, presetId) {
158
+ return this.baseAdapter.load(this.getUserKey(key), presetId);
159
+ }
160
+ async delete(key, presetId) {
161
+ return this.baseAdapter.delete(this.getUserKey(key), presetId);
162
+ }
163
+ async list(key) {
164
+ return this.baseAdapter.list(this.getUserKey(key));
165
+ }
166
+ };
167
+ function getStorageAdapter(config) {
168
+ if (config.customAdapter) {
169
+ return config.customAdapter;
170
+ }
171
+ switch (config.strategy) {
172
+ case "server":
173
+ if (!config.serverConfig) {
174
+ throw new Error("Server configuration is required for server storage strategy");
175
+ }
176
+ return new ServerAdapter(config.serverConfig);
177
+ case "userProfile":
178
+ if (!config.userProfileConfig) {
179
+ throw new Error("User profile configuration is required for userProfile storage strategy");
180
+ }
181
+ return new UserProfileAdapter(config.userProfileConfig);
182
+ case "localStorage":
183
+ default:
184
+ return new LocalStorageAdapter();
185
+ }
186
+ }
187
+ function generatePresetId() {
188
+ return `preset_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
189
+ }
190
+ function createPreset(name, layout, description, id) {
191
+ const now = Date.now();
192
+ return {
193
+ id: id || generatePresetId(),
194
+ name,
195
+ description,
196
+ createdAt: now,
197
+ updatedAt: now,
198
+ layout
199
+ };
200
+ }
201
+ var LayoutPersistenceManager = class {
202
+ adapter;
203
+ storageKey;
204
+ constructor(config) {
205
+ this.adapter = getStorageAdapter(config);
206
+ this.storageKey = config.storageKey;
207
+ }
208
+ /**
209
+ * Save a layout preset
210
+ */
211
+ async savePreset(preset) {
212
+ const updatedPreset = {
213
+ ...preset,
214
+ updatedAt: Date.now()
215
+ };
216
+ await this.adapter.save(this.storageKey, updatedPreset);
217
+ }
218
+ /**
219
+ * Load a specific preset by ID
220
+ */
221
+ async loadPreset(presetId) {
222
+ const result = await this.adapter.load(this.storageKey, presetId);
223
+ if (Array.isArray(result)) {
224
+ return result.find((p) => p.id === presetId) || null;
225
+ }
226
+ return result;
227
+ }
228
+ /**
229
+ * Load the most recently updated preset
230
+ */
231
+ async loadLastPreset() {
232
+ const presets = await this.listPresets();
233
+ if (presets.length === 0) {
234
+ return null;
235
+ }
236
+ return presets.reduce(
237
+ (latest, current) => current.updatedAt > latest.updatedAt ? current : latest
238
+ );
239
+ }
240
+ /**
241
+ * Delete a preset
242
+ */
243
+ async deletePreset(presetId) {
244
+ await this.adapter.delete(this.storageKey, presetId);
245
+ }
246
+ /**
247
+ * List all presets
248
+ */
249
+ async listPresets() {
250
+ return await this.adapter.list(this.storageKey);
251
+ }
252
+ /**
253
+ * Check if a preset exists
254
+ */
255
+ async hasPreset(presetId) {
256
+ const preset = await this.loadPreset(presetId);
257
+ return preset !== null;
258
+ }
259
+ /**
260
+ * Save current layout as auto-save (with special ID)
261
+ */
262
+ async autoSave(layout) {
263
+ const autoSaveId = "__autosave__";
264
+ const preset = createPreset("Auto-saved Layout", layout, "Automatically saved layout", autoSaveId);
265
+ await this.savePreset(preset);
266
+ }
267
+ /**
268
+ * Load auto-saved layout
269
+ */
270
+ async loadAutoSave() {
271
+ return await this.loadPreset("__autosave__");
272
+ }
273
+ };
274
+ function debounce(func, delay) {
275
+ let timeoutId = null;
276
+ return function(...args) {
277
+ if (timeoutId) {
278
+ clearTimeout(timeoutId);
279
+ }
280
+ timeoutId = setTimeout(() => {
281
+ func.apply(this, args);
282
+ timeoutId = null;
283
+ }, delay);
284
+ };
285
+ }
286
+
287
+ export {
288
+ LocalStorageAdapter,
289
+ ServerAdapter,
290
+ UserProfileAdapter,
291
+ getStorageAdapter,
292
+ generatePresetId,
293
+ createPreset,
294
+ LayoutPersistenceManager,
295
+ debounce
296
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * AccessibilityDemo.tsx
3
+ *
4
+ * Comprehensive demonstration of DataGrid accessibility features
5
+ * including keyboard navigation, ARIA support, and screen reader compatibility.
6
+ */
7
+ import React from 'react';
8
+ export declare const AccessibilityDemo: React.FC;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const ApiReferencePage: React.FC;
@@ -0,0 +1,2 @@
1
+ export declare const BenchmarkDemo: () => import("react/jsx-runtime").JSX.Element;
2
+ export default BenchmarkDemo;
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ /**
3
+ * CellRenderersDemo - Showcase of Custom Cell Renderer Framework
4
+ *
5
+ * This demo demonstrates all available custom cell renderers:
6
+ * - StatusChip: Color-coded status badges
7
+ * - ProgressBar: Visual progress indicators
8
+ * - IconCell: Cells with icons
9
+ * - ImageCell: Cells with images/avatars
10
+ * - ButtonCell: Actionable buttons
11
+ * - BadgeCell: Generic badge component
12
+ * - PriorityIndicator: Priority levels
13
+ * - Rating: Star ratings
14
+ * - CurrencyCell: Formatted currency values
15
+ */
16
+ export declare const CellRenderersDemo: React.FC;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface CodeBlockProps {
3
+ code: string;
4
+ language?: string;
5
+ title?: string;
6
+ showLineNumbers?: boolean;
7
+ maxHeight?: string;
8
+ }
9
+ export declare const CodeBlock: React.FC<CodeBlockProps>;
10
+ export default CodeBlock;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ /**
3
+ * Demo component showcasing the Column Filters feature
4
+ */
5
+ export declare const ColumnFiltersDemo: React.FC;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const CompleteApiReferencePage: React.FC;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ /**
3
+ * ContextMenuDemo Component
4
+ *
5
+ * Demonstrates the context menu feature with:
6
+ * - Right-click on cells: Copy, Copy with Headers, Export Selected Range, Filter by Value
7
+ * - Right-click on headers: Pin/Unpin, Auto-size, Resize to Fit, Hide Column, Filter by Value
8
+ * - Custom menu items
9
+ * - Enable/disable context menu options
10
+ */
11
+ export declare const ContextMenuDemo: React.FC;
12
+ export default ContextMenuDemo;
@@ -0,0 +1,288 @@
1
+ /**
2
+ * COMPONENT ARCHITECTURE GUIDE
3
+ *
4
+ * This document explains the internal design and architecture of the DataGrid component.
5
+ */
6
+ /**
7
+ * The DataGrid uses useReducer for centralized state management.
8
+ * This provides several benefits:
9
+ * - Single source of truth for all grid state
10
+ * - Predictable state updates through actions
11
+ * - Easier debugging and testing
12
+ * - Better performance (fewer re-renders)
13
+ *
14
+ * State Structure:
15
+ * - columns: Column configuration
16
+ * - sortConfig: Current sort field and direction
17
+ * - filterConfig: Filter values for each column
18
+ * - currentPage: Active page number (0-indexed)
19
+ * - pageSize: Rows per page
20
+ * - selection: Selected row IDs and tracking
21
+ * - editState: Currently editing cell info
22
+ * - focusState: Keyboard focus position
23
+ * - columnOrder: Display order of columns
24
+ * - columnWidths: Width of each column in pixels
25
+ */
26
+ /**
27
+ * Data flows through the component in the following order:
28
+ *
29
+ * Raw Data (props.rows)
30
+ * ↓
31
+ * Apply Sorting (sortedRows)
32
+ * ↓
33
+ * Apply Filtering (filteredRows)
34
+ * ↓
35
+ * Apply Pagination (paginatedRows)
36
+ * ↓
37
+ * Render in GridBody
38
+ *
39
+ * Each transformation is done with useMemo for performance optimization.
40
+ * The transformations only recalculate when their dependencies change.
41
+ */
42
+ /**
43
+ * DataGrid (Parent)
44
+ * │
45
+ * ├── GridHeader
46
+ * │ ├── Column Headers (sortable, draggable)
47
+ * │ ├── Column Resizers
48
+ * │ └── Filter Inputs
49
+ * │
50
+ * ├── GridBody
51
+ * │ └── Rows
52
+ * │ └── Cells (editable, focusable, selectable)
53
+ * │
54
+ * └── GridPagination
55
+ * ├── Page Size Selector
56
+ * ├── Row Count Info
57
+ * └── Page Navigation Buttons
58
+ */
59
+ /**
60
+ * A) Compound Component Pattern
61
+ * - Main DataGrid orchestrates sub-components
62
+ * - Each sub-component has a specific responsibility
63
+ * - State and dispatch are passed down as props
64
+ *
65
+ * B) Reducer Pattern
66
+ * - All state updates go through the reducer
67
+ * - Actions are dispatched from child components
68
+ * - Reducer handles state transitions
69
+ *
70
+ * C) Controlled Components
71
+ * - Parent component (DataGrid) owns the data
72
+ * - Child components receive data and callbacks
73
+ * - Edits are communicated back via callbacks
74
+ *
75
+ * D) Memoization Strategy
76
+ * - useMemo for expensive computations (sorting, filtering)
77
+ * - useCallback for event handlers passed to children
78
+ * - Prevents unnecessary re-renders
79
+ */
80
+ /**
81
+ * Column resizing uses a custom implementation:
82
+ *
83
+ * 1. Each column has a resize handle (1px div at right edge)
84
+ * 2. On mousedown:
85
+ * - Store starting X position and current width
86
+ * - Set resizing state
87
+ * 3. On mousemove (document level):
88
+ * - Calculate difference from start position
89
+ * - Update column width (with minimum constraint)
90
+ * 4. On mouseup (document level):
91
+ * - Clear resizing state
92
+ * - Clean up event listeners
93
+ *
94
+ * This approach allows dragging outside the column without losing the resize.
95
+ */
96
+ /**
97
+ * Column reordering uses HTML5 Drag & Drop API:
98
+ *
99
+ * 1. Each column header is draggable
100
+ * 2. On dragstart:
101
+ * - Store which column is being dragged
102
+ * - Set drag effect to 'move'
103
+ * 3. On dragover:
104
+ * - Prevent default to allow drop
105
+ * - Set drop effect to 'move'
106
+ * 4. On drop:
107
+ * - Calculate new position
108
+ * - Dispatch REORDER_COLUMNS action
109
+ * - Update columnOrder array in state
110
+ */
111
+ /**
112
+ * Three selection modes:
113
+ *
114
+ * A) Single Selection (regular click)
115
+ * - Clear all selections
116
+ * - Select clicked row
117
+ *
118
+ * B) Multi Selection (Ctrl/Cmd + click)
119
+ * - Toggle clicked row
120
+ * - Preserve other selections
121
+ *
122
+ * C) Range Selection (Shift + click)
123
+ * - Find last selected row
124
+ * - Select all rows between last and current
125
+ * - Add to existing selection
126
+ *
127
+ * Selection state is stored as a Set for O(1) lookups.
128
+ */
129
+ /**
130
+ * Cell editing workflow:
131
+ *
132
+ * 1. Enter Edit Mode:
133
+ * - Double-click cell OR
134
+ * - Press Enter on focused cell
135
+ * - Dispatch START_EDIT action
136
+ * - Replace cell content with input element
137
+ *
138
+ * 2. During Editing:
139
+ * - Input is focused and selected
140
+ * - Value changes update editState
141
+ * - Click outside or press Enter/Escape to exit
142
+ *
143
+ * 3. Exit Edit Mode:
144
+ * - Enter: Save changes, call onCellEdit callback
145
+ * - Escape: Discard changes
146
+ * - Blur: Save changes
147
+ * - Dispatch END_EDIT action
148
+ */
149
+ /**
150
+ * Keyboard navigation with focus tracking:
151
+ *
152
+ * 1. Focus State:
153
+ * - Stored as { rowIndex, columnIndex }
154
+ * - Rendered cell gets tabIndex={0}, others get tabIndex={-1}
155
+ * - Visual indicator (ring) shows focused cell
156
+ *
157
+ * 2. Arrow Key Handling:
158
+ * - Calculate new position
159
+ * - Apply boundary constraints (0 to max)
160
+ * - Update focus state
161
+ * - Focused cell automatically receives keyboard focus
162
+ *
163
+ * 3. Enter Key:
164
+ * - Starts editing if cell is editable
165
+ * - During editing, saves and exits
166
+ *
167
+ * 4. Escape Key:
168
+ * - During editing, cancels and exits
169
+ * - Otherwise, clears focus
170
+ */
171
+ /**
172
+ * A) useMemo for derived data:
173
+ * - sortedRows, filteredRows, paginatedRows
174
+ * - Only recalculate when dependencies change
175
+ *
176
+ * B) useCallback for event handlers:
177
+ * - Prevents child component re-renders
178
+ * - Stable function references
179
+ *
180
+ * C) Early returns in reducer:
181
+ * - No-op actions don't create new state
182
+ *
183
+ * D) Set for selection tracking:
184
+ * - O(1) lookups for "is selected" checks
185
+ *
186
+ * E) Column map in GridHeader/GridBody:
187
+ * - Quick column lookup by field name
188
+ * - Avoids O(n) array.find() in render
189
+ *
190
+ * Future optimization opportunities:
191
+ * - Virtual scrolling for large datasets
192
+ * - Web Workers for sorting/filtering
193
+ * - React.memo for sub-components
194
+ * - Debounced filter updates
195
+ */
196
+ /**
197
+ * Recommended testing approach:
198
+ *
199
+ * A) Unit Tests:
200
+ * - gridReducer.ts: Test all action types
201
+ * - Utility functions: Test sorting, filtering logic
202
+ *
203
+ * B) Component Tests:
204
+ * - GridHeader: Test sorting, filtering, resizing
205
+ * - GridBody: Test cell editing, selection, navigation
206
+ * - GridPagination: Test page changes, size changes
207
+ *
208
+ * C) Integration Tests:
209
+ * - Full DataGrid: Test feature interactions
210
+ * - Example: Sort → Filter → Edit → Page change
211
+ *
212
+ * D) E2E Tests:
213
+ * - User workflows: Select → Edit → Sort → Filter
214
+ * - Keyboard navigation flows
215
+ */
216
+ /**
217
+ * Current accessibility features:
218
+ * - Keyboard navigation (arrow keys, Enter, Escape)
219
+ * - Focus indicators (visible ring)
220
+ * - Semantic HTML where possible
221
+ *
222
+ * Recommended improvements:
223
+ * - ARIA labels for interactive elements
224
+ * - aria-sort on column headers
225
+ * - aria-selected on selected rows
226
+ * - Screen reader announcements for state changes
227
+ * - Focus management when editing
228
+ * - Proper role attributes (grid, row, columnheader, gridcell)
229
+ * - Keyboard shortcuts documentation
230
+ */
231
+ /**
232
+ * How to add new features:
233
+ *
234
+ * A) Add new state:
235
+ * 1. Update GridState interface in types.ts
236
+ * 2. Add to createInitialState in gridReducer.ts
237
+ * 3. Create new action type(s)
238
+ * 4. Handle in reducer switch statement
239
+ *
240
+ * B) Add new column feature:
241
+ * 1. Update Column interface in types.ts
242
+ * 2. Handle in GridHeader.tsx
243
+ * 3. Update rendering logic in GridBody.tsx
244
+ *
245
+ * C) Add new UI component:
246
+ * 1. Create new component file
247
+ * 2. Import in DataGrid.tsx
248
+ * 3. Pass necessary state and dispatch
249
+ * 4. Add to component hierarchy
250
+ *
251
+ * Example: Adding column pinning
252
+ * 1. Add pinnedColumns: string[] to GridState
253
+ * 2. Add PIN_COLUMN/UNPIN_COLUMN actions
254
+ * 3. Update GridHeader with pin button
255
+ * 4. Update GridBody to render pinned columns separately
256
+ * 5. Update column ordering logic
257
+ */
258
+ /**
259
+ * A) Column Lookup Pattern:
260
+ * const columnMap = new Map(columns.map(col => [col.field, col]));
261
+ * const column = columnMap.get(field);
262
+ * // Faster than columns.find(col => col.field === field)
263
+ *
264
+ * B) Conditional Rendering Pattern:
265
+ * if (!column || column.editable === false) return;
266
+ * // Handle missing or disabled features
267
+ *
268
+ * C) Event Handler Pattern:
269
+ * const handleAction = (data) => {
270
+ * dispatch({ type: 'ACTION_TYPE', payload: data });
271
+ * if (onAction) onAction(data);
272
+ * };
273
+ * // Update internal state + notify parent
274
+ *
275
+ * D) Style Computation Pattern:
276
+ * const className = `base-class ${condition ? 'conditional-class' : ''}`;
277
+ * // Dynamic class names based on state
278
+ *
279
+ * E) Ref Usage Pattern:
280
+ * const ref = useRef<HTMLElement>(null);
281
+ * useEffect(() => {
282
+ * if (ref.current) {
283
+ * ref.current.focus();
284
+ * }
285
+ * }, [dependency]);
286
+ * // Imperative DOM operations when needed
287
+ */
288
+ export {};
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { Column, AdvancedFilterValue, Row } from './types';
3
+ interface AdvancedFilterBuilderProps {
4
+ column: Column;
5
+ filterValue: AdvancedFilterValue | null;
6
+ onApply: (value: AdvancedFilterValue | null) => void;
7
+ onClose: () => void;
8
+ rows: Row[];
9
+ anchorEl: HTMLElement | null;
10
+ }
11
+ export declare const AdvancedFilterBuilder: React.FC<AdvancedFilterBuilderProps>;
12
+ export {};