@alaarab/ogrid-react 2.0.22 → 2.1.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 (66) hide show
  1. package/dist/esm/components/ColumnHeaderFilterContent.js +0 -2
  2. package/dist/esm/components/MarchingAntsOverlay.js +2 -3
  3. package/dist/esm/components/SideBar.js +8 -7
  4. package/dist/esm/components/createOGrid.js +1 -4
  5. package/dist/esm/hooks/index.js +10 -0
  6. package/dist/esm/hooks/useActiveCell.js +2 -4
  7. package/dist/esm/hooks/useCellSelection.js +85 -52
  8. package/dist/esm/hooks/useClipboard.js +15 -54
  9. package/dist/esm/hooks/useColumnChooserState.js +25 -13
  10. package/dist/esm/hooks/useColumnHeaderFilterState.js +22 -11
  11. package/dist/esm/hooks/useColumnHeaderMenuState.js +1 -1
  12. package/dist/esm/hooks/useColumnMeta.js +61 -0
  13. package/dist/esm/hooks/useColumnPinning.js +11 -12
  14. package/dist/esm/hooks/useColumnReorder.js +8 -1
  15. package/dist/esm/hooks/useColumnResize.js +6 -2
  16. package/dist/esm/hooks/useDataGridContextMenu.js +24 -0
  17. package/dist/esm/hooks/useDataGridEditing.js +56 -0
  18. package/dist/esm/hooks/useDataGridInteraction.js +109 -0
  19. package/dist/esm/hooks/useDataGridLayout.js +172 -0
  20. package/dist/esm/hooks/useDataGridState.js +83 -318
  21. package/dist/esm/hooks/useDataGridTableOrchestration.js +2 -4
  22. package/dist/esm/hooks/useFillHandle.js +60 -55
  23. package/dist/esm/hooks/useFilterOptions.js +2 -4
  24. package/dist/esm/hooks/useInlineCellEditorState.js +7 -13
  25. package/dist/esm/hooks/useKeyboardNavigation.js +19 -132
  26. package/dist/esm/hooks/useMultiSelectFilterState.js +1 -1
  27. package/dist/esm/hooks/useOGrid.js +159 -301
  28. package/dist/esm/hooks/useOGridDataFetching.js +74 -0
  29. package/dist/esm/hooks/useOGridFilters.js +59 -0
  30. package/dist/esm/hooks/useOGridPagination.js +24 -0
  31. package/dist/esm/hooks/useOGridSorting.js +24 -0
  32. package/dist/esm/hooks/usePaginationControls.js +2 -5
  33. package/dist/esm/hooks/usePeopleFilterState.js +6 -1
  34. package/dist/esm/hooks/useRichSelectState.js +7 -5
  35. package/dist/esm/hooks/useRowSelection.js +6 -26
  36. package/dist/esm/hooks/useSelectState.js +2 -5
  37. package/dist/esm/hooks/useShallowEqualMemo.js +14 -0
  38. package/dist/esm/hooks/useTableLayout.js +3 -11
  39. package/dist/esm/hooks/useUndoRedo.js +16 -10
  40. package/dist/esm/index.js +1 -1
  41. package/dist/esm/utils/index.js +1 -1
  42. package/dist/types/components/ColumnChooserProps.d.ts +2 -0
  43. package/dist/types/components/ColumnHeaderFilterContent.d.ts +0 -2
  44. package/dist/types/hooks/index.d.ts +19 -0
  45. package/dist/types/hooks/useClipboard.d.ts +0 -1
  46. package/dist/types/hooks/useColumnChooserState.d.ts +2 -0
  47. package/dist/types/hooks/useColumnHeaderFilterState.d.ts +0 -2
  48. package/dist/types/hooks/useColumnHeaderMenuState.d.ts +0 -2
  49. package/dist/types/hooks/useColumnMeta.d.ts +34 -0
  50. package/dist/types/hooks/useDataGridContextMenu.d.ts +20 -0
  51. package/dist/types/hooks/useDataGridEditing.d.ts +39 -0
  52. package/dist/types/hooks/useDataGridInteraction.d.ts +95 -0
  53. package/dist/types/hooks/useDataGridLayout.d.ts +45 -0
  54. package/dist/types/hooks/useDataGridState.d.ts +7 -1
  55. package/dist/types/hooks/useDataGridTableOrchestration.d.ts +1 -2
  56. package/dist/types/hooks/useOGrid.d.ts +4 -2
  57. package/dist/types/hooks/useOGridDataFetching.d.ts +29 -0
  58. package/dist/types/hooks/useOGridFilters.d.ts +24 -0
  59. package/dist/types/hooks/useOGridPagination.d.ts +18 -0
  60. package/dist/types/hooks/useOGridSorting.d.ts +23 -0
  61. package/dist/types/hooks/usePaginationControls.d.ts +1 -1
  62. package/dist/types/hooks/useRichSelectState.d.ts +2 -0
  63. package/dist/types/hooks/useShallowEqualMemo.d.ts +7 -0
  64. package/dist/types/index.d.ts +2 -2
  65. package/dist/types/utils/index.d.ts +2 -2
  66. package/package.json +12 -4
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useCallback, useMemo } from 'react';
1
+ import { useState, useEffect, useCallback } from 'react';
2
2
  /**
3
3
  * Load filter options for the given fields from a data source.
4
4
  *
@@ -7,7 +7,6 @@ import { useState, useEffect, useCallback, useMemo } from 'react';
7
7
  export function useFilterOptions(dataSource, fields) {
8
8
  const [filterOptions, setFilterOptions] = useState({});
9
9
  const [loadingOptions, setLoadingOptions] = useState({});
10
- const fieldsKey = useMemo(() => [...fields].sort().join(','), [fields]);
11
10
  const load = useCallback(async () => {
12
11
  const fetcher = 'fetchFilterOptions' in dataSource && typeof dataSource.fetchFilterOptions === 'function'
13
12
  ? dataSource.fetchFilterOptions.bind(dataSource)
@@ -31,8 +30,7 @@ export function useFilterOptions(dataSource, fields) {
31
30
  }));
32
31
  setFilterOptions(results);
33
32
  setLoadingOptions({});
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [dataSource, fieldsKey]);
33
+ }, [dataSource, fields]);
36
34
  useEffect(() => {
37
35
  load().catch(() => { });
38
36
  }, [load]);
@@ -10,35 +10,29 @@ import { useState, useCallback } from 'react';
10
10
  export function useInlineCellEditorState(params) {
11
11
  const { value, editorType, onCommit, onCancel } = params;
12
12
  const [localValue, setLocalValue] = useState(value !== null && value !== undefined ? String(value) : '');
13
- const commit = useCallback((v) => {
14
- onCommit(v);
15
- }, [onCommit]);
16
- const cancel = useCallback(() => {
17
- onCancel();
18
- }, [onCancel]);
19
13
  const handleKeyDown = useCallback((e) => {
20
14
  if (e.key === 'Escape') {
21
15
  e.preventDefault();
22
16
  e.stopPropagation(); // Don't let the grid handler clear selection on Escape
23
- cancel();
17
+ onCancel();
24
18
  }
25
19
  if (e.key === 'Enter' && editorType === 'text') {
26
20
  e.preventDefault();
27
21
  e.stopPropagation(); // Don't let the grid handler re-open an editor
28
- commit(localValue);
22
+ onCommit(localValue);
29
23
  }
30
- }, [cancel, commit, localValue, editorType]);
24
+ }, [onCancel, onCommit, localValue, editorType]);
31
25
  const handleBlur = useCallback(() => {
32
26
  if (editorType === 'text') {
33
- commit(localValue);
27
+ onCommit(localValue);
34
28
  }
35
- }, [editorType, localValue, commit]);
29
+ }, [editorType, localValue, onCommit]);
36
30
  return {
37
31
  localValue,
38
32
  setLocalValue,
39
33
  handleKeyDown,
40
34
  handleBlur,
41
- commit,
42
- cancel,
35
+ commit: onCommit,
36
+ cancel: onCancel,
43
37
  };
44
38
  }
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useRef } from 'react';
2
- import { normalizeSelectionRange } from '../types';
3
- import { getCellValue, parseValue, findCtrlArrowTarget, computeTabNavigation } from '../utils';
2
+ import { getCellValue, computeTabNavigation, computeArrowNavigation, applyCellDeletion } from '../utils';
4
3
  /**
5
4
  * Handles all keyboard navigation, shortcuts, and cell editing triggers for the grid.
6
5
  * @param params - Grouped data, state, handlers, and feature flags for keyboard interactions.
@@ -70,114 +69,23 @@ export function useKeyboardNavigation(params) {
70
69
  void handlePaste();
71
70
  }
72
71
  break;
73
- case 'ArrowDown': {
74
- e.preventDefault();
75
- const ctrl = e.ctrlKey || e.metaKey;
76
- const newRow = ctrl
77
- ? findCtrlArrowTarget(rowIndex, maxRowIndex, 1, (r) => isEmptyAt(r, Math.max(0, dataColIndex)))
78
- : Math.min(rowIndex + 1, maxRowIndex);
79
- if (shift) {
80
- setSelectionRange(normalizeSelectionRange({
81
- startRow: selectionRange?.startRow ?? rowIndex,
82
- startCol: selectionRange?.startCol ?? dataColIndex,
83
- endRow: newRow,
84
- endCol: selectionRange?.endCol ?? dataColIndex,
85
- }));
86
- }
87
- else {
88
- setSelectionRange({
89
- startRow: newRow,
90
- startCol: dataColIndex,
91
- endRow: newRow,
92
- endCol: dataColIndex,
93
- });
94
- }
95
- setActiveCell({ rowIndex: newRow, columnIndex });
96
- break;
97
- }
98
- case 'ArrowUp': {
99
- e.preventDefault();
100
- const ctrl = e.ctrlKey || e.metaKey;
101
- const newRowUp = ctrl
102
- ? findCtrlArrowTarget(rowIndex, 0, -1, (r) => isEmptyAt(r, Math.max(0, dataColIndex)))
103
- : Math.max(rowIndex - 1, 0);
104
- if (shift) {
105
- setSelectionRange(normalizeSelectionRange({
106
- startRow: selectionRange?.startRow ?? rowIndex,
107
- startCol: selectionRange?.startCol ?? dataColIndex,
108
- endRow: newRowUp,
109
- endCol: selectionRange?.endCol ?? dataColIndex,
110
- }));
111
- }
112
- else {
113
- setSelectionRange({
114
- startRow: newRowUp,
115
- startCol: dataColIndex,
116
- endRow: newRowUp,
117
- endCol: dataColIndex,
118
- });
119
- }
120
- setActiveCell({ rowIndex: newRowUp, columnIndex });
121
- break;
122
- }
123
- case 'ArrowRight': {
124
- e.preventDefault();
125
- const ctrl = e.ctrlKey || e.metaKey;
126
- let newCol;
127
- if (ctrl && dataColIndex >= 0) {
128
- newCol = findCtrlArrowTarget(dataColIndex, visibleCols.length - 1, 1, (c) => isEmptyAt(rowIndex, c)) + colOffset;
129
- }
130
- else {
131
- newCol = Math.min(columnIndex + 1, maxColIndex);
132
- }
133
- const newDataCol = newCol - colOffset;
134
- if (shift) {
135
- setSelectionRange(normalizeSelectionRange({
136
- startRow: selectionRange?.startRow ?? rowIndex,
137
- startCol: selectionRange?.startCol ?? dataColIndex,
138
- endRow: selectionRange?.endRow ?? rowIndex,
139
- endCol: newDataCol,
140
- }));
141
- }
142
- else {
143
- setSelectionRange({
144
- startRow: rowIndex,
145
- startCol: newDataCol,
146
- endRow: rowIndex,
147
- endCol: newDataCol,
148
- });
149
- }
150
- setActiveCell({ rowIndex, columnIndex: newCol });
151
- break;
152
- }
72
+ case 'ArrowDown':
73
+ case 'ArrowUp':
74
+ case 'ArrowRight':
153
75
  case 'ArrowLeft': {
154
76
  e.preventDefault();
155
- const ctrl = e.ctrlKey || e.metaKey;
156
- let newColLeft;
157
- if (ctrl && dataColIndex >= 0) {
158
- newColLeft = findCtrlArrowTarget(dataColIndex, 0, -1, (c) => isEmptyAt(rowIndex, c)) + colOffset;
159
- }
160
- else {
161
- newColLeft = Math.max(columnIndex - 1, colOffset);
162
- }
163
- const newDataColLeft = newColLeft - colOffset;
164
- if (shift) {
165
- setSelectionRange(normalizeSelectionRange({
166
- startRow: selectionRange?.startRow ?? rowIndex,
167
- startCol: selectionRange?.startCol ?? dataColIndex,
168
- endRow: selectionRange?.endRow ?? rowIndex,
169
- endCol: newDataColLeft,
170
- }));
171
- }
172
- else {
173
- setSelectionRange({
174
- startRow: rowIndex,
175
- startCol: newDataColLeft,
176
- endRow: rowIndex,
177
- endCol: newDataColLeft,
178
- });
179
- }
180
- setActiveCell({ rowIndex, columnIndex: newColLeft });
77
+ const { newRowIndex, newColumnIndex, newRange } = computeArrowNavigation({
78
+ direction: e.key,
79
+ rowIndex, columnIndex, dataColIndex, colOffset,
80
+ maxRowIndex, maxColIndex,
81
+ visibleColCount: visibleCols.length,
82
+ isCtrl: e.ctrlKey || e.metaKey,
83
+ isShift: shift,
84
+ selectionRange,
85
+ isEmptyAt,
86
+ });
87
+ setSelectionRange(newRange);
88
+ setActiveCell({ rowIndex: newRowIndex, columnIndex: newColumnIndex });
181
89
  break;
182
90
  }
183
91
  case 'Tab': {
@@ -317,30 +225,9 @@ export function useKeyboardNavigation(params) {
317
225
  if (range == null)
318
226
  break;
319
227
  e.preventDefault();
320
- const norm = normalizeSelectionRange(range);
321
- for (let r = norm.startRow; r <= norm.endRow; r++) {
322
- for (let c = norm.startCol; c <= norm.endCol; c++) {
323
- if (r >= items.length || c >= visibleCols.length)
324
- continue;
325
- const item = items[r];
326
- const col = visibleCols[c];
327
- const colEditable = col.editable === true ||
328
- (typeof col.editable === 'function' && col.editable(item));
329
- if (!colEditable)
330
- continue;
331
- const oldValue = getCellValue(item, col);
332
- const result = parseValue('', oldValue, item, col);
333
- if (!result.valid)
334
- continue;
335
- onCellValueChanged({
336
- item,
337
- columnId: col.columnId,
338
- oldValue,
339
- newValue: result.value,
340
- rowIndex: r,
341
- });
342
- }
343
- }
228
+ const deleteEvents = applyCellDeletion(range, items, visibleCols);
229
+ for (const evt of deleteEvents)
230
+ onCellValueChanged(evt);
344
231
  break;
345
232
  }
346
233
  case 'F10':
@@ -38,7 +38,7 @@ export function useMultiSelectFilterState(params) {
38
38
  });
39
39
  }, []);
40
40
  const handleSelectAll = useCallback(() => {
41
- setTempSelected(new Set(filteredOptions));
41
+ setTempSelected((prev) => new Set([...prev, ...filteredOptions]));
42
42
  }, [filteredOptions]);
43
43
  const handleClearSelection = useCallback(() => setTempSelected(new Set()), []);
44
44
  const handleApplyMultiSelect = useCallback(() => {