@alaarab/ogrid-core 1.8.2 → 2.0.0-beta

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 (74) hide show
  1. package/README.md +28 -31
  2. package/dist/esm/constants.js +11 -0
  3. package/dist/esm/index.js +6 -11
  4. package/dist/esm/types/index.js +2 -1
  5. package/dist/esm/utils/clientSideData.js +25 -12
  6. package/dist/esm/utils/columnUtils.js +6 -0
  7. package/dist/esm/utils/gridRowComparator.js +78 -0
  8. package/dist/esm/utils/index.js +1 -1
  9. package/dist/esm/utils/ogridHelpers.js +2 -1
  10. package/dist/esm/utils/paginationHelpers.js +7 -1
  11. package/dist/types/constants.d.ts +11 -0
  12. package/dist/types/index.d.ts +3 -16
  13. package/dist/types/types/columnTypes.d.ts +5 -9
  14. package/dist/types/types/dataGridTypes.d.ts +12 -133
  15. package/dist/types/types/index.d.ts +3 -3
  16. package/dist/types/utils/gridRowComparator.d.ts +57 -0
  17. package/dist/types/utils/index.d.ts +2 -2
  18. package/package.json +6 -24
  19. package/dist/esm/components/GridContextMenu.js +0 -34
  20. package/dist/esm/components/MarchingAntsOverlay.js +0 -109
  21. package/dist/esm/components/OGridLayout.js +0 -90
  22. package/dist/esm/components/SideBar.js +0 -100
  23. package/dist/esm/components/StatusBar.js +0 -6
  24. package/dist/esm/hooks/index.js +0 -19
  25. package/dist/esm/hooks/useActiveCell.js +0 -46
  26. package/dist/esm/hooks/useCellEditing.js +0 -11
  27. package/dist/esm/hooks/useCellSelection.js +0 -318
  28. package/dist/esm/hooks/useClipboard.js +0 -162
  29. package/dist/esm/hooks/useColumnChooserState.js +0 -62
  30. package/dist/esm/hooks/useColumnHeaderFilterState.js +0 -228
  31. package/dist/esm/hooks/useColumnResize.js +0 -69
  32. package/dist/esm/hooks/useContextMenu.js +0 -17
  33. package/dist/esm/hooks/useDataGridState.js +0 -366
  34. package/dist/esm/hooks/useDebounce.js +0 -35
  35. package/dist/esm/hooks/useFillHandle.js +0 -191
  36. package/dist/esm/hooks/useFilterOptions.js +0 -40
  37. package/dist/esm/hooks/useInlineCellEditorState.js +0 -44
  38. package/dist/esm/hooks/useKeyboardNavigation.js +0 -436
  39. package/dist/esm/hooks/useOGrid.js +0 -414
  40. package/dist/esm/hooks/useRichSelectState.js +0 -53
  41. package/dist/esm/hooks/useRowSelection.js +0 -68
  42. package/dist/esm/hooks/useSideBarState.js +0 -34
  43. package/dist/esm/hooks/useUndoRedo.js +0 -82
  44. package/dist/esm/storybook/index.js +0 -1
  45. package/dist/esm/storybook/mockData.js +0 -73
  46. package/dist/esm/utils/dataGridViewModel.js +0 -233
  47. package/dist/types/components/GridContextMenu.d.ts +0 -18
  48. package/dist/types/components/MarchingAntsOverlay.d.ts +0 -15
  49. package/dist/types/components/OGridLayout.d.ts +0 -37
  50. package/dist/types/components/SideBar.d.ts +0 -30
  51. package/dist/types/components/StatusBar.d.ts +0 -24
  52. package/dist/types/hooks/index.d.ts +0 -37
  53. package/dist/types/hooks/useActiveCell.d.ts +0 -13
  54. package/dist/types/hooks/useCellEditing.d.ts +0 -12
  55. package/dist/types/hooks/useCellSelection.d.ts +0 -17
  56. package/dist/types/hooks/useClipboard.d.ts +0 -25
  57. package/dist/types/hooks/useColumnChooserState.d.ts +0 -27
  58. package/dist/types/hooks/useColumnHeaderFilterState.d.ts +0 -72
  59. package/dist/types/hooks/useColumnResize.d.ts +0 -18
  60. package/dist/types/hooks/useContextMenu.d.ts +0 -15
  61. package/dist/types/hooks/useDataGridState.d.ts +0 -136
  62. package/dist/types/hooks/useDebounce.d.ts +0 -9
  63. package/dist/types/hooks/useFillHandle.d.ts +0 -28
  64. package/dist/types/hooks/useFilterOptions.d.ts +0 -16
  65. package/dist/types/hooks/useInlineCellEditorState.d.ts +0 -24
  66. package/dist/types/hooks/useKeyboardNavigation.d.ts +0 -34
  67. package/dist/types/hooks/useOGrid.d.ts +0 -31
  68. package/dist/types/hooks/useRichSelectState.d.ts +0 -17
  69. package/dist/types/hooks/useRowSelection.d.ts +0 -17
  70. package/dist/types/hooks/useSideBarState.d.ts +0 -15
  71. package/dist/types/hooks/useUndoRedo.d.ts +0 -21
  72. package/dist/types/storybook/index.d.ts +0 -2
  73. package/dist/types/storybook/mockData.d.ts +0 -37
  74. package/dist/types/utils/dataGridViewModel.d.ts +0 -169
@@ -1,436 +0,0 @@
1
- import { useCallback } from 'react';
2
- import { normalizeSelectionRange } from '../types';
3
- import { getCellValue } from '../utils';
4
- import { parseValue } from '../utils/valueParsers';
5
- /**
6
- * Excel-style Ctrl+Arrow: find the target position along a 1D axis.
7
- * - Non-empty current + non-empty next → scan through non-empties, stop at last before empty/edge.
8
- * - Otherwise → skip empties, land on next non-empty or edge.
9
- */
10
- function findCtrlTarget(pos, edge, step, isEmpty) {
11
- if (pos === edge)
12
- return pos;
13
- const next = pos + step;
14
- if (!isEmpty(pos) && !isEmpty(next)) {
15
- let p = next;
16
- while (p !== edge) {
17
- if (isEmpty(p + step))
18
- return p;
19
- p += step;
20
- }
21
- return edge;
22
- }
23
- let p = next;
24
- while (p !== edge) {
25
- if (!isEmpty(p))
26
- return p;
27
- p += step;
28
- }
29
- return edge;
30
- }
31
- export function useKeyboardNavigation(params) {
32
- const { items, visibleCols, colOffset, hasCheckboxCol, visibleColumnCount, activeCell, setActiveCell, selectionRange, setSelectionRange, editable, onCellValueChanged, getRowId, editingCell, setEditingCell, rowSelection, selectedRowIds, handleRowCheckboxChange, handleCopy, handleCut, handlePaste, setContextMenu, wrapperRef, onUndo, onRedo, clearClipboardRanges, } = params;
33
- const maxRowIndex = items.length - 1;
34
- const maxColIndex = visibleColumnCount - 1 + colOffset;
35
- const handleGridKeyDown = useCallback((e) => {
36
- if (items.length === 0)
37
- return;
38
- if (activeCell === null) {
39
- if ([
40
- 'ArrowDown',
41
- 'ArrowUp',
42
- 'ArrowLeft',
43
- 'ArrowRight',
44
- 'Tab',
45
- 'Enter',
46
- 'Home',
47
- 'End',
48
- ].includes(e.key)) {
49
- setActiveCell({ rowIndex: 0, columnIndex: colOffset });
50
- e.preventDefault();
51
- }
52
- return;
53
- }
54
- const { rowIndex, columnIndex } = activeCell;
55
- const dataColIndex = columnIndex - colOffset;
56
- const shift = e.shiftKey;
57
- const isEmptyAt = (r, c) => {
58
- if (r < 0 || r >= items.length || c < 0 || c >= visibleCols.length)
59
- return true;
60
- const v = getCellValue(items[r], visibleCols[c]);
61
- return v == null || v === '';
62
- };
63
- switch (e.key) {
64
- case 'c':
65
- if (e.ctrlKey || e.metaKey) {
66
- if (editingCell != null)
67
- break; // let the input handle copy
68
- e.preventDefault();
69
- handleCopy();
70
- }
71
- break;
72
- case 'x':
73
- if (e.ctrlKey || e.metaKey) {
74
- if (editingCell != null)
75
- break; // let the input handle cut
76
- e.preventDefault();
77
- handleCut();
78
- }
79
- break;
80
- case 'v':
81
- if (e.ctrlKey || e.metaKey) {
82
- if (editingCell != null)
83
- break; // let the input handle paste
84
- e.preventDefault();
85
- void handlePaste();
86
- }
87
- break;
88
- case 'ArrowDown': {
89
- e.preventDefault();
90
- const ctrl = e.ctrlKey || e.metaKey;
91
- const newRow = ctrl
92
- ? findCtrlTarget(rowIndex, maxRowIndex, 1, (r) => isEmptyAt(r, Math.max(0, dataColIndex)))
93
- : Math.min(rowIndex + 1, maxRowIndex);
94
- if (shift) {
95
- setSelectionRange(normalizeSelectionRange({
96
- startRow: selectionRange?.startRow ?? rowIndex,
97
- startCol: selectionRange?.startCol ?? dataColIndex,
98
- endRow: newRow,
99
- endCol: selectionRange?.endCol ?? dataColIndex,
100
- }));
101
- }
102
- else {
103
- setSelectionRange({
104
- startRow: newRow,
105
- startCol: dataColIndex,
106
- endRow: newRow,
107
- endCol: dataColIndex,
108
- });
109
- }
110
- setActiveCell({ rowIndex: newRow, columnIndex });
111
- break;
112
- }
113
- case 'ArrowUp': {
114
- e.preventDefault();
115
- const ctrl = e.ctrlKey || e.metaKey;
116
- const newRowUp = ctrl
117
- ? findCtrlTarget(rowIndex, 0, -1, (r) => isEmptyAt(r, Math.max(0, dataColIndex)))
118
- : Math.max(rowIndex - 1, 0);
119
- if (shift) {
120
- setSelectionRange(normalizeSelectionRange({
121
- startRow: selectionRange?.startRow ?? rowIndex,
122
- startCol: selectionRange?.startCol ?? dataColIndex,
123
- endRow: newRowUp,
124
- endCol: selectionRange?.endCol ?? dataColIndex,
125
- }));
126
- }
127
- else {
128
- setSelectionRange({
129
- startRow: newRowUp,
130
- startCol: dataColIndex,
131
- endRow: newRowUp,
132
- endCol: dataColIndex,
133
- });
134
- }
135
- setActiveCell({ rowIndex: newRowUp, columnIndex });
136
- break;
137
- }
138
- case 'ArrowRight': {
139
- e.preventDefault();
140
- const ctrl = e.ctrlKey || e.metaKey;
141
- let newCol;
142
- if (ctrl && dataColIndex >= 0) {
143
- newCol = findCtrlTarget(dataColIndex, visibleCols.length - 1, 1, (c) => isEmptyAt(rowIndex, c)) + colOffset;
144
- }
145
- else {
146
- newCol = Math.min(columnIndex + 1, maxColIndex);
147
- }
148
- const newDataCol = newCol - colOffset;
149
- if (shift) {
150
- setSelectionRange(normalizeSelectionRange({
151
- startRow: selectionRange?.startRow ?? rowIndex,
152
- startCol: selectionRange?.startCol ?? dataColIndex,
153
- endRow: selectionRange?.endRow ?? rowIndex,
154
- endCol: newDataCol,
155
- }));
156
- }
157
- else {
158
- setSelectionRange({
159
- startRow: rowIndex,
160
- startCol: newDataCol,
161
- endRow: rowIndex,
162
- endCol: newDataCol,
163
- });
164
- }
165
- setActiveCell({ rowIndex, columnIndex: newCol });
166
- break;
167
- }
168
- case 'ArrowLeft': {
169
- e.preventDefault();
170
- const ctrl = e.ctrlKey || e.metaKey;
171
- let newColLeft;
172
- if (ctrl && dataColIndex >= 0) {
173
- newColLeft = findCtrlTarget(dataColIndex, 0, -1, (c) => isEmptyAt(rowIndex, c)) + colOffset;
174
- }
175
- else {
176
- newColLeft = Math.max(columnIndex - 1, colOffset);
177
- }
178
- const newDataColLeft = newColLeft - colOffset;
179
- if (shift) {
180
- setSelectionRange(normalizeSelectionRange({
181
- startRow: selectionRange?.startRow ?? rowIndex,
182
- startCol: selectionRange?.startCol ?? dataColIndex,
183
- endRow: selectionRange?.endRow ?? rowIndex,
184
- endCol: newDataColLeft,
185
- }));
186
- }
187
- else {
188
- setSelectionRange({
189
- startRow: rowIndex,
190
- startCol: newDataColLeft,
191
- endRow: rowIndex,
192
- endCol: newDataColLeft,
193
- });
194
- }
195
- setActiveCell({ rowIndex, columnIndex: newColLeft });
196
- break;
197
- }
198
- case 'Tab': {
199
- e.preventDefault();
200
- let newRowTab = rowIndex;
201
- let newColTab = columnIndex;
202
- if (e.shiftKey) {
203
- if (columnIndex > colOffset) {
204
- newColTab = columnIndex - 1;
205
- }
206
- else if (rowIndex > 0) {
207
- newRowTab = rowIndex - 1;
208
- newColTab = maxColIndex;
209
- }
210
- }
211
- else {
212
- if (columnIndex < maxColIndex) {
213
- newColTab = columnIndex + 1;
214
- }
215
- else if (rowIndex < maxRowIndex) {
216
- newRowTab = rowIndex + 1;
217
- newColTab = colOffset;
218
- }
219
- }
220
- const newDataColTab = newColTab - colOffset;
221
- setSelectionRange({
222
- startRow: newRowTab,
223
- startCol: newDataColTab,
224
- endRow: newRowTab,
225
- endCol: newDataColTab,
226
- });
227
- setActiveCell({ rowIndex: newRowTab, columnIndex: newColTab });
228
- break;
229
- }
230
- case 'Home': {
231
- e.preventDefault();
232
- const newRowHome = e.ctrlKey ? 0 : rowIndex;
233
- setSelectionRange({
234
- startRow: newRowHome,
235
- startCol: 0,
236
- endRow: newRowHome,
237
- endCol: 0,
238
- });
239
- setActiveCell({ rowIndex: newRowHome, columnIndex: colOffset });
240
- break;
241
- }
242
- case 'End': {
243
- e.preventDefault();
244
- const newRowEnd = e.ctrlKey ? maxRowIndex : rowIndex;
245
- setSelectionRange({
246
- startRow: newRowEnd,
247
- startCol: visibleColumnCount - 1,
248
- endRow: newRowEnd,
249
- endCol: visibleColumnCount - 1,
250
- });
251
- setActiveCell({ rowIndex: newRowEnd, columnIndex: maxColIndex });
252
- break;
253
- }
254
- case 'Enter':
255
- case 'F2': {
256
- e.preventDefault();
257
- if (dataColIndex >= 0 && dataColIndex < visibleCols.length) {
258
- const col = visibleCols[dataColIndex];
259
- const item = items[rowIndex];
260
- if (item && col) {
261
- const colEditable = col.editable === true ||
262
- (typeof col.editable === 'function' && col.editable(item));
263
- if (editable !== false &&
264
- colEditable &&
265
- onCellValueChanged != null) {
266
- setEditingCell({ rowId: getRowId(item), columnId: col.columnId });
267
- }
268
- }
269
- }
270
- break;
271
- }
272
- case 'Escape':
273
- e.preventDefault();
274
- if (editingCell != null) {
275
- setEditingCell(null);
276
- }
277
- else {
278
- clearClipboardRanges?.();
279
- setActiveCell(null);
280
- setSelectionRange(null);
281
- }
282
- break;
283
- case ' ':
284
- if (rowSelection !== 'none' &&
285
- columnIndex === 0 &&
286
- hasCheckboxCol) {
287
- e.preventDefault();
288
- const item = items[rowIndex];
289
- if (item) {
290
- const id = getRowId(item);
291
- const isSelected = selectedRowIds.has(id);
292
- handleRowCheckboxChange(id, !isSelected, rowIndex, e.shiftKey);
293
- }
294
- }
295
- break;
296
- case 'z':
297
- if (e.ctrlKey || e.metaKey) {
298
- if (editingCell == null) {
299
- if (e.shiftKey && onRedo) {
300
- e.preventDefault();
301
- onRedo();
302
- }
303
- else if (!e.shiftKey && onUndo) {
304
- e.preventDefault();
305
- onUndo();
306
- }
307
- }
308
- }
309
- break;
310
- case 'y':
311
- if (e.ctrlKey || e.metaKey) {
312
- if (editingCell == null && onRedo) {
313
- e.preventDefault();
314
- onRedo();
315
- }
316
- }
317
- break;
318
- case 'a':
319
- if (e.ctrlKey || e.metaKey) {
320
- if (editingCell != null)
321
- break; // let the input handle select-all
322
- e.preventDefault();
323
- if (items.length > 0 && visibleColumnCount > 0) {
324
- setSelectionRange({
325
- startRow: 0,
326
- startCol: 0,
327
- endRow: items.length - 1,
328
- endCol: visibleColumnCount - 1,
329
- });
330
- setActiveCell({ rowIndex: 0, columnIndex: colOffset });
331
- }
332
- }
333
- break;
334
- case 'Delete':
335
- case 'Backspace': {
336
- if (editingCell != null)
337
- break;
338
- if (editable === false)
339
- break;
340
- if (onCellValueChanged == null)
341
- break;
342
- const range = selectionRange ??
343
- (activeCell != null
344
- ? {
345
- startRow: activeCell.rowIndex,
346
- startCol: activeCell.columnIndex - colOffset,
347
- endRow: activeCell.rowIndex,
348
- endCol: activeCell.columnIndex - colOffset,
349
- }
350
- : null);
351
- if (range == null)
352
- break;
353
- e.preventDefault();
354
- const norm = normalizeSelectionRange(range);
355
- for (let r = norm.startRow; r <= norm.endRow; r++) {
356
- for (let c = norm.startCol; c <= norm.endCol; c++) {
357
- if (r >= items.length || c >= visibleCols.length)
358
- continue;
359
- const item = items[r];
360
- const col = visibleCols[c];
361
- const colEditable = col.editable === true ||
362
- (typeof col.editable === 'function' && col.editable(item));
363
- if (!colEditable)
364
- continue;
365
- const oldValue = getCellValue(item, col);
366
- const result = parseValue('', oldValue, item, col);
367
- if (!result.valid)
368
- continue;
369
- onCellValueChanged({
370
- item,
371
- columnId: col.columnId,
372
- field: col.columnId,
373
- oldValue,
374
- newValue: result.value,
375
- rowIndex: r,
376
- });
377
- }
378
- }
379
- break;
380
- }
381
- case 'F10':
382
- if (e.shiftKey) {
383
- e.preventDefault();
384
- if (activeCell != null && wrapperRef.current) {
385
- const sel = `[data-row-index="${activeCell.rowIndex}"][data-col-index="${activeCell.columnIndex}"]`;
386
- const cell = wrapperRef.current.querySelector(sel);
387
- if (cell) {
388
- const rect = cell.getBoundingClientRect();
389
- setContextMenu({
390
- x: rect.left + rect.width / 2,
391
- y: rect.top + rect.height / 2,
392
- });
393
- }
394
- else {
395
- setContextMenu({ x: 100, y: 100 });
396
- }
397
- }
398
- else {
399
- setContextMenu({ x: 100, y: 100 });
400
- }
401
- }
402
- break;
403
- default:
404
- break;
405
- }
406
- }, [
407
- items,
408
- activeCell,
409
- hasCheckboxCol,
410
- visibleColumnCount,
411
- visibleCols,
412
- colOffset,
413
- editable,
414
- onCellValueChanged,
415
- getRowId,
416
- editingCell,
417
- rowSelection,
418
- selectedRowIds,
419
- handleRowCheckboxChange,
420
- handleCopy,
421
- handleCut,
422
- handlePaste,
423
- selectionRange,
424
- setActiveCell,
425
- setSelectionRange,
426
- maxRowIndex,
427
- maxColIndex,
428
- setEditingCell,
429
- setContextMenu,
430
- wrapperRef,
431
- onUndo,
432
- onRedo,
433
- clearClipboardRanges,
434
- ]);
435
- return { handleGridKeyDown };
436
- }