@alaarab/ogrid-core 1.9.0 → 2.0.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 (87) hide show
  1. package/README.md +6 -20
  2. package/dist/esm/index.js +5 -15
  3. package/dist/esm/types/index.js +2 -1
  4. package/dist/esm/utils/clientSideData.js +1 -1
  5. package/dist/esm/utils/gridRowComparator.js +11 -1
  6. package/dist/esm/utils/index.js +1 -2
  7. package/dist/types/index.d.ts +3 -23
  8. package/dist/types/types/columnTypes.d.ts +3 -6
  9. package/dist/types/types/dataGridTypes.d.ts +1 -150
  10. package/dist/types/types/index.d.ts +3 -3
  11. package/dist/types/utils/gridRowComparator.d.ts +8 -0
  12. package/dist/types/utils/index.d.ts +1 -3
  13. package/package.json +6 -24
  14. package/dist/esm/components/BaseInlineCellEditor.js +0 -112
  15. package/dist/esm/components/CellErrorBoundary.js +0 -43
  16. package/dist/esm/components/EmptyState.js +0 -19
  17. package/dist/esm/components/GridContextMenu.js +0 -35
  18. package/dist/esm/components/MarchingAntsOverlay.js +0 -110
  19. package/dist/esm/components/OGridLayout.js +0 -91
  20. package/dist/esm/components/SideBar.js +0 -122
  21. package/dist/esm/components/StatusBar.js +0 -6
  22. package/dist/esm/hooks/index.js +0 -25
  23. package/dist/esm/hooks/useActiveCell.js +0 -62
  24. package/dist/esm/hooks/useCellEditing.js +0 -15
  25. package/dist/esm/hooks/useCellSelection.js +0 -324
  26. package/dist/esm/hooks/useClipboard.js +0 -162
  27. package/dist/esm/hooks/useColumnChooserState.js +0 -62
  28. package/dist/esm/hooks/useColumnHeaderFilterState.js +0 -180
  29. package/dist/esm/hooks/useColumnResize.js +0 -92
  30. package/dist/esm/hooks/useContextMenu.js +0 -21
  31. package/dist/esm/hooks/useDataGridState.js +0 -314
  32. package/dist/esm/hooks/useDateFilterState.js +0 -34
  33. package/dist/esm/hooks/useDebounce.js +0 -35
  34. package/dist/esm/hooks/useFillHandle.js +0 -196
  35. package/dist/esm/hooks/useFilterOptions.js +0 -40
  36. package/dist/esm/hooks/useInlineCellEditorState.js +0 -44
  37. package/dist/esm/hooks/useKeyboardNavigation.js +0 -420
  38. package/dist/esm/hooks/useLatestRef.js +0 -11
  39. package/dist/esm/hooks/useMultiSelectFilterState.js +0 -59
  40. package/dist/esm/hooks/useOGrid.js +0 -467
  41. package/dist/esm/hooks/usePeopleFilterState.js +0 -68
  42. package/dist/esm/hooks/useRichSelectState.js +0 -58
  43. package/dist/esm/hooks/useRowSelection.js +0 -78
  44. package/dist/esm/hooks/useSideBarState.js +0 -39
  45. package/dist/esm/hooks/useTableLayout.js +0 -77
  46. package/dist/esm/hooks/useTextFilterState.js +0 -25
  47. package/dist/esm/hooks/useUndoRedo.js +0 -83
  48. package/dist/esm/storybook/index.js +0 -1
  49. package/dist/esm/storybook/mockData.js +0 -73
  50. package/dist/esm/utils/dataGridViewModel.js +0 -233
  51. package/dist/types/components/BaseInlineCellEditor.d.ts +0 -33
  52. package/dist/types/components/CellErrorBoundary.d.ts +0 -25
  53. package/dist/types/components/EmptyState.d.ts +0 -26
  54. package/dist/types/components/GridContextMenu.d.ts +0 -18
  55. package/dist/types/components/MarchingAntsOverlay.d.ts +0 -15
  56. package/dist/types/components/OGridLayout.d.ts +0 -37
  57. package/dist/types/components/SideBar.d.ts +0 -30
  58. package/dist/types/components/StatusBar.d.ts +0 -24
  59. package/dist/types/hooks/index.d.ts +0 -48
  60. package/dist/types/hooks/useActiveCell.d.ts +0 -13
  61. package/dist/types/hooks/useCellEditing.d.ts +0 -16
  62. package/dist/types/hooks/useCellSelection.d.ts +0 -22
  63. package/dist/types/hooks/useClipboard.d.ts +0 -30
  64. package/dist/types/hooks/useColumnChooserState.d.ts +0 -27
  65. package/dist/types/hooks/useColumnHeaderFilterState.d.ts +0 -73
  66. package/dist/types/hooks/useColumnResize.d.ts +0 -23
  67. package/dist/types/hooks/useContextMenu.d.ts +0 -19
  68. package/dist/types/hooks/useDataGridState.d.ts +0 -137
  69. package/dist/types/hooks/useDateFilterState.d.ts +0 -19
  70. package/dist/types/hooks/useDebounce.d.ts +0 -9
  71. package/dist/types/hooks/useFillHandle.d.ts +0 -33
  72. package/dist/types/hooks/useFilterOptions.d.ts +0 -16
  73. package/dist/types/hooks/useInlineCellEditorState.d.ts +0 -24
  74. package/dist/types/hooks/useKeyboardNavigation.d.ts +0 -47
  75. package/dist/types/hooks/useLatestRef.d.ts +0 -6
  76. package/dist/types/hooks/useMultiSelectFilterState.d.ts +0 -24
  77. package/dist/types/hooks/useOGrid.d.ts +0 -52
  78. package/dist/types/hooks/usePeopleFilterState.d.ts +0 -25
  79. package/dist/types/hooks/useRichSelectState.d.ts +0 -22
  80. package/dist/types/hooks/useRowSelection.d.ts +0 -22
  81. package/dist/types/hooks/useSideBarState.d.ts +0 -20
  82. package/dist/types/hooks/useTableLayout.d.ts +0 -27
  83. package/dist/types/hooks/useTextFilterState.d.ts +0 -16
  84. package/dist/types/hooks/useUndoRedo.d.ts +0 -23
  85. package/dist/types/storybook/index.d.ts +0 -2
  86. package/dist/types/storybook/mockData.d.ts +0 -37
  87. package/dist/types/utils/dataGridViewModel.d.ts +0 -169
@@ -1,196 +0,0 @@
1
- import { useState, useCallback, useRef, useEffect } from 'react';
2
- import { normalizeSelectionRange } from '../types';
3
- import { getCellValue } from '../utils';
4
- import { parseValue } from '../utils/valueParsers';
5
- /** DOM attribute name for fill-drag range highlighting (same as cell selection drag). */
6
- const DRAG_ATTR = 'data-drag-range';
7
- /**
8
- * Manages Excel-style fill handle drag-to-fill for cell ranges.
9
- * @param params - Items, columns, selection range, editability, and value change callback.
10
- * @returns Fill drag state, setter, and mousedown handler for the fill handle.
11
- */
12
- export function useFillHandle(params) {
13
- const { items, visibleCols, editable, onCellValueChanged, selectionRange, setSelectionRange, setActiveCell, colOffset, wrapperRef, beginBatch, endBatch, } = params;
14
- const [fillDrag, setFillDrag] = useState(null);
15
- const fillDragEndRef = useRef({ endRow: 0, endCol: 0 });
16
- const rafRef = useRef(0);
17
- const liveFillRangeRef = useRef(null);
18
- useEffect(() => {
19
- if (!fillDrag || editable === false || !onCellValueChanged || !wrapperRef.current)
20
- return;
21
- fillDragEndRef.current = { endRow: fillDrag.startRow, endCol: fillDrag.startCol };
22
- liveFillRangeRef.current = null;
23
- const colOff = colOffset;
24
- const applyDragAttrs = (range) => {
25
- const wrapper = wrapperRef.current;
26
- if (!wrapper)
27
- return;
28
- const minR = Math.min(range.startRow, range.endRow);
29
- const maxR = Math.max(range.startRow, range.endRow);
30
- const minC = Math.min(range.startCol, range.endCol);
31
- const maxC = Math.max(range.startCol, range.endCol);
32
- const cells = wrapper.querySelectorAll('[data-row-index][data-col-index]');
33
- for (let i = 0; i < cells.length; i++) {
34
- const el = cells[i];
35
- const r = parseInt(el.getAttribute('data-row-index'), 10);
36
- const c = parseInt(el.getAttribute('data-col-index'), 10) - colOff;
37
- const inRange = r >= minR && r <= maxR && c >= minC && c <= maxC;
38
- if (inRange) {
39
- if (!el.hasAttribute(DRAG_ATTR))
40
- el.setAttribute(DRAG_ATTR, '');
41
- }
42
- else {
43
- if (el.hasAttribute(DRAG_ATTR))
44
- el.removeAttribute(DRAG_ATTR);
45
- }
46
- }
47
- };
48
- const clearDragAttrs = () => {
49
- const wrapper = wrapperRef.current;
50
- if (!wrapper)
51
- return;
52
- const marked = wrapper.querySelectorAll(`[${DRAG_ATTR}]`);
53
- for (let i = 0; i < marked.length; i++)
54
- marked[i].removeAttribute(DRAG_ATTR);
55
- };
56
- let lastFillMousePos = null;
57
- const resolveRange = (cx, cy) => {
58
- const target = document.elementFromPoint(cx, cy);
59
- const cell = target?.closest?.('[data-row-index][data-col-index]');
60
- if (!cell || !wrapperRef.current?.contains(cell))
61
- return null;
62
- const r = parseInt(cell.getAttribute('data-row-index') ?? '', 10);
63
- const c = parseInt(cell.getAttribute('data-col-index') ?? '', 10);
64
- if (Number.isNaN(r) || Number.isNaN(c) || c < colOff)
65
- return null;
66
- const dataCol = c - colOff;
67
- return normalizeSelectionRange({
68
- startRow: fillDrag.startRow,
69
- startCol: fillDrag.startCol,
70
- endRow: r,
71
- endCol: dataCol,
72
- });
73
- };
74
- const onMove = (e) => {
75
- lastFillMousePos = { cx: e.clientX, cy: e.clientY };
76
- if (rafRef.current)
77
- cancelAnimationFrame(rafRef.current);
78
- rafRef.current = requestAnimationFrame(() => {
79
- rafRef.current = 0;
80
- if (!lastFillMousePos)
81
- return;
82
- const newRange = resolveRange(lastFillMousePos.cx, lastFillMousePos.cy);
83
- if (!newRange)
84
- return;
85
- // Skip if unchanged
86
- const prev = liveFillRangeRef.current;
87
- if (prev &&
88
- prev.startRow === newRange.startRow &&
89
- prev.startCol === newRange.startCol &&
90
- prev.endRow === newRange.endRow &&
91
- prev.endCol === newRange.endCol) {
92
- return;
93
- }
94
- liveFillRangeRef.current = newRange;
95
- fillDragEndRef.current = { endRow: newRange.endRow, endCol: newRange.endCol };
96
- applyDragAttrs(newRange);
97
- });
98
- };
99
- const onUp = () => {
100
- if (rafRef.current) {
101
- cancelAnimationFrame(rafRef.current);
102
- rafRef.current = 0;
103
- }
104
- // Flush: resolve final position if RAF hasn't executed yet
105
- if (lastFillMousePos) {
106
- const flushed = resolveRange(lastFillMousePos.cx, lastFillMousePos.cy);
107
- if (flushed) {
108
- liveFillRangeRef.current = flushed;
109
- fillDragEndRef.current = { endRow: flushed.endRow, endCol: flushed.endCol };
110
- }
111
- }
112
- clearDragAttrs();
113
- const end = fillDragEndRef.current;
114
- const norm = normalizeSelectionRange({
115
- startRow: fillDrag.startRow,
116
- startCol: fillDrag.startCol,
117
- endRow: end.endRow,
118
- endCol: end.endCol,
119
- });
120
- // Commit range to React state
121
- setSelectionRange(norm);
122
- setActiveCell({ rowIndex: end.endRow, columnIndex: end.endCol + colOff });
123
- // Apply fill values
124
- const startItem = items[norm.startRow];
125
- const startColDef = visibleCols[norm.startCol];
126
- if (startItem && startColDef) {
127
- const startValue = getCellValue(startItem, startColDef);
128
- beginBatch?.();
129
- for (let row = norm.startRow; row <= norm.endRow; row++) {
130
- for (let col = norm.startCol; col <= norm.endCol; col++) {
131
- if (row === fillDrag.startRow && col === fillDrag.startCol)
132
- continue;
133
- if (row >= items.length || col >= visibleCols.length)
134
- continue;
135
- const item = items[row];
136
- const colDef = visibleCols[col];
137
- const colEditable = colDef.editable === true ||
138
- (typeof colDef.editable === 'function' && colDef.editable(item));
139
- if (!colEditable)
140
- continue;
141
- const oldValue = getCellValue(item, colDef);
142
- const result = parseValue(startValue, oldValue, item, colDef);
143
- if (!result.valid)
144
- continue;
145
- onCellValueChanged({
146
- item,
147
- columnId: colDef.columnId,
148
- oldValue,
149
- newValue: result.value,
150
- rowIndex: row,
151
- });
152
- }
153
- }
154
- endBatch?.();
155
- }
156
- setFillDrag(null);
157
- liveFillRangeRef.current = null;
158
- };
159
- window.addEventListener('mousemove', onMove, true);
160
- window.addEventListener('mouseup', onUp, true);
161
- return () => {
162
- window.removeEventListener('mousemove', onMove, true);
163
- window.removeEventListener('mouseup', onUp, true);
164
- if (rafRef.current)
165
- cancelAnimationFrame(rafRef.current);
166
- };
167
- // eslint-disable-next-line react-hooks/exhaustive-deps
168
- }, [
169
- fillDrag,
170
- editable,
171
- colOffset,
172
- items,
173
- visibleCols,
174
- setSelectionRange,
175
- setActiveCell,
176
- onCellValueChanged,
177
- // wrapperRef excluded — refs are stable across renders
178
- beginBatch,
179
- endBatch,
180
- ]);
181
- // Ref mirror — keeps handleFillHandleMouseDown stable across selection changes
182
- const selectionRangeRef = useRef(selectionRange);
183
- selectionRangeRef.current = selectionRange;
184
- const handleFillHandleMouseDown = useCallback((e) => {
185
- e.preventDefault();
186
- e.stopPropagation();
187
- const range = selectionRangeRef.current;
188
- if (!range)
189
- return;
190
- setFillDrag({
191
- startRow: range.startRow,
192
- startCol: range.startCol,
193
- });
194
- }, []);
195
- return { fillDrag, setFillDrag, handleFillHandleMouseDown };
196
- }
@@ -1,40 +0,0 @@
1
- import { useState, useEffect, useCallback, useMemo } from 'react';
2
- /**
3
- * Load filter options for the given fields from a data source.
4
- *
5
- * Accepts `IDataSource<T>` or a plain `{ fetchFilterOptions }` object.
6
- */
7
- export function useFilterOptions(dataSource, fields) {
8
- const [filterOptions, setFilterOptions] = useState({});
9
- const [loadingOptions, setLoadingOptions] = useState({});
10
- const fieldsKey = useMemo(() => [...fields].sort().join(','), [fields]);
11
- const load = useCallback(async () => {
12
- const fetcher = 'fetchFilterOptions' in dataSource && typeof dataSource.fetchFilterOptions === 'function'
13
- ? dataSource.fetchFilterOptions.bind(dataSource)
14
- : undefined;
15
- if (!fetcher) {
16
- setFilterOptions({});
17
- setLoadingOptions({});
18
- return;
19
- }
20
- const loading = {};
21
- fields.forEach((f) => { loading[f] = true; });
22
- setLoadingOptions(loading);
23
- const results = {};
24
- await Promise.all(fields.map(async (field) => {
25
- try {
26
- results[field] = await fetcher(field);
27
- }
28
- catch {
29
- results[field] = [];
30
- }
31
- }));
32
- setFilterOptions(results);
33
- setLoadingOptions({});
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [dataSource, fieldsKey]);
36
- useEffect(() => {
37
- load().catch(() => { });
38
- }, [load]);
39
- return { filterOptions, loadingOptions };
40
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * Headless inline cell editor state for Fluent, Material, and Radix InlineCellEditor.
3
- * UI packages use this hook and render only the framework input (Input, TextField, select, Checkbox).
4
- */
5
- import { useState, useCallback } from 'react';
6
- /**
7
- * Returns localValue/setLocalValue (for text), handleKeyDown (Escape cancel, Enter commit for text),
8
- * handleBlur (commit on blur for text), commit(value), cancel(). UI renders only the input.
9
- */
10
- export function useInlineCellEditorState(params) {
11
- const { value, editorType, onCommit, onCancel } = params;
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
- const handleKeyDown = useCallback((e) => {
20
- if (e.key === 'Escape') {
21
- e.preventDefault();
22
- e.stopPropagation(); // Don't let the grid handler clear selection on Escape
23
- cancel();
24
- }
25
- if (e.key === 'Enter' && editorType === 'text') {
26
- e.preventDefault();
27
- e.stopPropagation(); // Don't let the grid handler re-open an editor
28
- commit(localValue);
29
- }
30
- }, [cancel, commit, localValue, editorType]);
31
- const handleBlur = useCallback(() => {
32
- if (editorType === 'text') {
33
- commit(localValue);
34
- }
35
- }, [editorType, localValue, commit]);
36
- return {
37
- localValue,
38
- setLocalValue,
39
- handleKeyDown,
40
- handleBlur,
41
- commit,
42
- cancel,
43
- };
44
- }