@onehat/ui 0.4.81 → 0.4.83
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/package.json +7 -6
- package/src/Components/Container/Container.js +4 -4
- package/src/Components/Form/Field/Combo/Combo.js +88 -16
- package/src/Components/Form/Field/Combo/MeterTypesCombo.js +1 -0
- package/src/Components/Form/Field/Date.js +1 -1
- package/src/Components/Form/Field/Json.js +2 -1
- package/src/Components/Form/Field/Select/PageSizeSelect.js +6 -1
- package/src/Components/Form/Field/Select/Select.js +14 -38
- package/src/Components/Form/Field/Tag/Tag.js +234 -14
- package/src/Components/Form/Field/Tag/ValueBox.js +20 -1
- package/src/Components/Form/Form.js +26 -13
- package/src/Components/Grid/Grid.js +316 -106
- package/src/Components/Grid/GridHeaderRow.js +42 -22
- package/src/Components/Grid/GridRow.js +16 -6
- package/src/Components/Grid/RowHandle.js +16 -4
- package/src/Components/Hoc/Secondary/withSecondaryEditor.js +137 -43
- package/src/Components/Hoc/Secondary/withSecondarySideEditor.js +1 -1
- package/src/Components/Hoc/withData.js +7 -0
- package/src/Components/Hoc/withEditor.js +19 -4
- package/src/Components/Hoc/withPresetButtons.js +1 -1
- package/src/Components/Hoc/withSideEditor.js +1 -1
- package/src/Components/Icons/Join.js +10 -0
- package/src/Components/Layout/AsyncOperation.js +61 -14
- package/src/Components/Layout/CenterBox.js +1 -1
- package/src/Components/Screens/Manager.js +1 -1
- package/src/Components/Toolbar/Pagination.js +108 -106
- package/src/Components/Toolbar/PaginationToolbar.js +3 -1
- package/src/Components/Toolbar/Toolbar.js +10 -6
- package/src/Components/Tree/TreeNode.js +39 -9
- package/src/Components/Viewer/Viewer.js +7 -2
- package/src/Constants/Progress.js +2 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect, useRef, useMemo, useCallback, } from 'react';
|
|
1
|
+
import { useState, useEffect, useRef, useMemo, useCallback, createRef, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Box,
|
|
4
4
|
FlatList,
|
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
SELECTION_MODE_SINGLE,
|
|
17
17
|
SELECTION_MODE_MULTI,
|
|
18
18
|
} from '../../Constants/Selection.js';
|
|
19
|
+
import {
|
|
20
|
+
EDITOR_TYPE__SIDE,
|
|
21
|
+
} from '../../Constants/Editor.js';
|
|
19
22
|
import {
|
|
20
23
|
EDIT,
|
|
21
24
|
VIEW,
|
|
@@ -104,9 +107,10 @@ const
|
|
|
104
107
|
SINGLE_CLICK = 1,
|
|
105
108
|
DOUBLE_CLICK = 2,
|
|
106
109
|
TRIPLE_CLICK = 3,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
PHASES__INITIAL = 'initial',
|
|
111
|
+
PHASES__MEASURING = 'measuring',
|
|
112
|
+
PHASES__OPTIMIZED = 'optimized',
|
|
113
|
+
DEBUG = false;
|
|
110
114
|
|
|
111
115
|
function GridComponent(props) {
|
|
112
116
|
const {
|
|
@@ -129,6 +133,7 @@ function GridComponent(props) {
|
|
|
129
133
|
flatListProps = {},
|
|
130
134
|
onRowPress,
|
|
131
135
|
onRender,
|
|
136
|
+
onLayout,
|
|
132
137
|
disableLoadOnRender = false,
|
|
133
138
|
forceLoadOnRender = false,
|
|
134
139
|
pullToRefresh = true,
|
|
@@ -145,6 +150,7 @@ function GridComponent(props) {
|
|
|
145
150
|
canColumnsSort = true,
|
|
146
151
|
canColumnsReorder = true,
|
|
147
152
|
canColumnsResize = true,
|
|
153
|
+
areCellsScrollable = true,
|
|
148
154
|
allowToggleSelection = false, // i.e. single click with no shift key toggles the selection of the item clicked on
|
|
149
155
|
disableBottomToolbar = false,
|
|
150
156
|
disablePagination = false,
|
|
@@ -205,6 +211,8 @@ function GridComponent(props) {
|
|
|
205
211
|
onContextMenu,
|
|
206
212
|
isAdding,
|
|
207
213
|
isEditorViewOnly,
|
|
214
|
+
getIsEditorShown,
|
|
215
|
+
editorType,
|
|
208
216
|
|
|
209
217
|
// withData
|
|
210
218
|
Repository,
|
|
@@ -255,20 +263,42 @@ function GridComponent(props) {
|
|
|
255
263
|
return !isSerializable(columnsConfig); // (runs only once, when the component is first created)
|
|
256
264
|
}),
|
|
257
265
|
forceUpdate = useForceUpdate(),
|
|
266
|
+
isAddingRaw = useRef(),
|
|
267
|
+
measurementPhaseRaw = useRef(PHASES__INITIAL),
|
|
268
|
+
measuredRowHeightRaw = useRef(null),
|
|
258
269
|
containerRef = useRef(),
|
|
259
270
|
gridRef = useRef(),
|
|
260
271
|
gridContainerRef = useRef(),
|
|
261
|
-
isAddingRef = useRef(),
|
|
262
272
|
expandedRowsRef = useRef({}),
|
|
263
273
|
cachedDragElements = useRef(),
|
|
264
274
|
dragSelectionRef = useRef([]),
|
|
265
275
|
previousSelectorId = useRef(),
|
|
276
|
+
headerRowRef = useRef(null),
|
|
277
|
+
topToolbarRef = useRef(null),
|
|
278
|
+
measuredRowsRef = useRef([]),
|
|
279
|
+
footerToolbarRef = useRef(null),
|
|
280
|
+
rowRefs = useRef([]),
|
|
266
281
|
[isInited, setIsInited] = useState(false),
|
|
267
282
|
[isReady, setIsReady] = useState(false),
|
|
268
283
|
[isLoading, setIsLoading] = useState(false),
|
|
269
284
|
[localColumnsConfig, setLocalColumnsConfigRaw] = useState([]),
|
|
270
285
|
[isReorderMode, setIsReorderMode] = useState(false),
|
|
271
286
|
showRowHandle = showSelectHandle || areRowsDragSource || (canRowsReorder && isReorderMode),
|
|
287
|
+
[lastMeasuredContainerHeight, setLastMeasuredContainerHeight] = useState(0),
|
|
288
|
+
getMeasurementPhase = () => {
|
|
289
|
+
return measurementPhaseRaw.current;
|
|
290
|
+
},
|
|
291
|
+
setMeasurementPhase = (phase) => {
|
|
292
|
+
measurementPhaseRaw.current = phase;
|
|
293
|
+
forceUpdate();
|
|
294
|
+
},
|
|
295
|
+
getMeasuredRowHeight = () => {
|
|
296
|
+
return measuredRowHeightRaw.current;
|
|
297
|
+
},
|
|
298
|
+
setMeasuredRowHeight = (height) => {
|
|
299
|
+
measuredRowHeightRaw.current = height;
|
|
300
|
+
forceUpdate();
|
|
301
|
+
},
|
|
272
302
|
getIsExpanded = (index) => {
|
|
273
303
|
return !!expandedRowsRef.current[index];
|
|
274
304
|
},
|
|
@@ -639,14 +669,20 @@ function GridComponent(props) {
|
|
|
639
669
|
|
|
640
670
|
}
|
|
641
671
|
|
|
642
|
-
//
|
|
672
|
+
// assign ref for row height measurement during measurement phase
|
|
643
673
|
let rowRef = null;
|
|
644
|
-
if (autoAdjustPageSizeToHeight &&
|
|
645
|
-
!isHeaderRow && index >= 1
|
|
674
|
+
if (autoAdjustPageSizeToHeight && getMeasurementPhase() === PHASES__MEASURING &&
|
|
675
|
+
!isHeaderRow && index >= 1) { // Sample all data rows (index 1+)
|
|
646
676
|
const refIndex = index - 1; // Convert to 0-based index
|
|
647
|
-
|
|
648
|
-
if
|
|
649
|
-
|
|
677
|
+
|
|
678
|
+
// Create ref if it doesn't exist
|
|
679
|
+
if (!rowRefs.current[refIndex]) {
|
|
680
|
+
rowRefs.current[refIndex] = createRef();
|
|
681
|
+
}
|
|
682
|
+
rowRef = rowRefs.current[refIndex];
|
|
683
|
+
|
|
684
|
+
if (rowRef && !measuredRowsRef.current.includes(rowRef)) {
|
|
685
|
+
measuredRowsRef.current.push(rowRef);
|
|
650
686
|
}
|
|
651
687
|
}
|
|
652
688
|
|
|
@@ -661,6 +697,7 @@ function GridComponent(props) {
|
|
|
661
697
|
isRowHoverable={isRowHoverable}
|
|
662
698
|
isSelected={isSelected}
|
|
663
699
|
isHovered={hovered}
|
|
700
|
+
areCellsScrollable={areCellsScrollable}
|
|
664
701
|
showHovers={showHovers}
|
|
665
702
|
showRowHandle={showRowHandle}
|
|
666
703
|
rowCanSelect={rowCanSelect}
|
|
@@ -858,25 +895,17 @@ function GridComponent(props) {
|
|
|
858
895
|
marker.remove();
|
|
859
896
|
cachedDragElements.current = null;
|
|
860
897
|
},
|
|
861
|
-
// Refs for measuring actual row heights
|
|
862
|
-
headerRowRef = useRef(null),
|
|
863
|
-
paginationToolbarRef = useRef(null),
|
|
864
|
-
sampleRowsRef = useRef([]),
|
|
865
|
-
|
|
866
|
-
// Pre-create refs for first 5 rows for measurement
|
|
867
|
-
rowRefs = [useRef(null), useRef(null), useRef(null), useRef(null), useRef(null)],
|
|
868
|
-
|
|
869
|
-
// State for tracking measurement phases
|
|
870
|
-
[measurementPhase, setMeasurementPhase] = useState(PHASES_INITIAL), //
|
|
871
|
-
[lastMeasuredContainerHeight, setLastMeasuredContainerHeight] = useState(0),
|
|
872
|
-
[measuredRowHeight, setMeasuredRowHeight] = useState(null),
|
|
873
898
|
calculatePageSize = (containerHeight, useActualMeasurements = false) => {
|
|
899
|
+
if (DEBUG) {
|
|
900
|
+
console.log(`${getMeasurementPhase()}, calculatePageSize A containerHeight=${containerHeight}, useActualMeasurements=${useActualMeasurements}, measuredRowHeight=${getMeasuredRowHeight()}`);
|
|
901
|
+
}
|
|
874
902
|
// Phase 1: Initial calculation using estimated heights
|
|
875
|
-
if (!useActualMeasurements ||
|
|
903
|
+
if (!useActualMeasurements || getMeasurementPhase() === PHASES__INITIAL) {
|
|
876
904
|
const
|
|
877
|
-
|
|
905
|
+
headerRowHeight = showHeaders ? 50 : 0,
|
|
906
|
+
topToolbarHeight = topToolbar ? 50 : 0, // Estimate top toolbar height
|
|
878
907
|
footerHeight = !disablePagination ? 50 : 0,
|
|
879
|
-
availableHeight = containerHeight -
|
|
908
|
+
availableHeight = containerHeight - topToolbarHeight - headerRowHeight - footerHeight,
|
|
880
909
|
maxClassNormal = styles.GRID_ROW_MAX_HEIGHT_NORMAL, // e.g. max-h-[40px]
|
|
881
910
|
rowNormalHeight = parseInt(maxClassNormal.match(/\d+/)[0]);
|
|
882
911
|
|
|
@@ -886,111 +915,251 @@ function GridComponent(props) {
|
|
|
886
915
|
if (pageSize < 1) {
|
|
887
916
|
pageSize = 1;
|
|
888
917
|
}
|
|
918
|
+
if (DEBUG) {
|
|
919
|
+
console.log(`${getMeasurementPhase()}, calculatePageSize B using ESTIMATED heights, pageSize=${pageSize}`);
|
|
920
|
+
}
|
|
889
921
|
return pageSize;
|
|
890
922
|
}
|
|
891
923
|
|
|
892
924
|
// Phase 3: Optimized calculation using actual measurements
|
|
893
|
-
if (useActualMeasurements &&
|
|
894
|
-
let
|
|
895
|
-
|
|
896
|
-
|
|
925
|
+
if (useActualMeasurements && getMeasurementPhase() === PHASES__OPTIMIZED && getMeasuredRowHeight()) {
|
|
926
|
+
let actualTopToolbarHeight = 0,
|
|
927
|
+
actualHeaderHeight = 0,
|
|
928
|
+
actualFooterHeight = 0,
|
|
929
|
+
actualRowHeight = getMeasuredRowHeight();
|
|
897
930
|
|
|
898
|
-
|
|
931
|
+
if (topToolbar && topToolbarRef.current) {
|
|
932
|
+
actualTopToolbarHeight = topToolbarRef.current.offsetHeight || topToolbarRef.current.clientHeight || 50;
|
|
933
|
+
}
|
|
899
934
|
if (showHeaders && headerRowRef.current) {
|
|
900
935
|
actualHeaderHeight = headerRowRef.current.offsetHeight || headerRowRef.current.clientHeight || 50;
|
|
901
936
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
if (!disablePagination && paginationToolbarRef.current) {
|
|
905
|
-
actualFooterHeight = paginationToolbarRef.current.offsetHeight || paginationToolbarRef.current.clientHeight || 50;
|
|
937
|
+
if (!disablePagination && footerToolbarRef.current) {
|
|
938
|
+
actualFooterHeight = footerToolbarRef.current.offsetHeight || footerToolbarRef.current.clientHeight || 50;
|
|
906
939
|
}
|
|
907
940
|
|
|
908
|
-
const availableHeight = containerHeight - actualHeaderHeight - actualFooterHeight;
|
|
941
|
+
const availableHeight = containerHeight - actualTopToolbarHeight - actualHeaderHeight - actualFooterHeight;
|
|
909
942
|
let pageSize = Math.floor(availableHeight / actualRowHeight);
|
|
910
943
|
|
|
911
944
|
if (pageSize < 1) {
|
|
912
945
|
pageSize = 1;
|
|
913
946
|
}
|
|
947
|
+
if (DEBUG) {
|
|
948
|
+
console.log(`${getMeasurementPhase()}, calculatePageSize C using ACTUAL heights, pageSize=${pageSize}`);
|
|
949
|
+
}
|
|
914
950
|
return pageSize;
|
|
915
951
|
}
|
|
916
952
|
|
|
917
953
|
// Fallback to Phase 1 logic
|
|
954
|
+
if (DEBUG) {
|
|
955
|
+
console.log(`${getMeasurementPhase()}, calculatePageSize D fallback to ESTIMATED heights by calling calculatePageSize(${containerHeight}, false)`);
|
|
956
|
+
}
|
|
918
957
|
return calculatePageSize(containerHeight, false);
|
|
919
958
|
},
|
|
920
959
|
measureActualRowHeights = () => {
|
|
921
|
-
if (
|
|
922
|
-
return;
|
|
960
|
+
if (!gridContainerRef.current) {
|
|
961
|
+
return null;
|
|
923
962
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
963
|
+
if (DEBUG) {
|
|
964
|
+
console.log(`${getMeasurementPhase()}, measureActualRowHeights A`);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
const measuredRows = measuredRowsRef.current.filter(ref => ref && ref.current);
|
|
968
|
+
if (measuredRows.length === 0) {
|
|
969
|
+
if (DEBUG) {
|
|
970
|
+
console.log(`${getMeasurementPhase()}, measureActualRowHeights B no rows to measure`);
|
|
971
|
+
}
|
|
972
|
+
return null;
|
|
929
973
|
}
|
|
930
974
|
|
|
931
975
|
let totalHeight = 0;
|
|
932
976
|
let measuredCount = 0;
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
|
|
977
|
+
|
|
978
|
+
if (CURRENT_MODE === UI_MODE_WEB) {
|
|
979
|
+
// Web: Use DOM measurement APIs
|
|
980
|
+
_.each(measuredRows, (rowRef) => {
|
|
981
|
+
if (rowRef.current) {
|
|
982
|
+
const height = rowRef.current.offsetHeight || rowRef.current.clientHeight;
|
|
983
|
+
if (height > 0) {
|
|
984
|
+
totalHeight += height;
|
|
985
|
+
measuredCount++;
|
|
986
|
+
}
|
|
940
987
|
}
|
|
941
|
-
}
|
|
942
|
-
})
|
|
988
|
+
});
|
|
989
|
+
} else if (CURRENT_MODE === UI_MODE_NATIVE) {
|
|
990
|
+
// React Native: Use measure API with promises
|
|
991
|
+
return new Promise((resolve) => {
|
|
992
|
+
let completed = 0;
|
|
993
|
+
const measurements = [];
|
|
994
|
+
|
|
995
|
+
_.each(measuredRows, (rowRef) => {
|
|
996
|
+
if (rowRef.current && rowRef.current.measure) {
|
|
997
|
+
rowRef.current.measure((x, y, width, height) => {
|
|
998
|
+
if (height > 0) {
|
|
999
|
+
measurements.push(height);
|
|
1000
|
+
}
|
|
1001
|
+
completed++;
|
|
1002
|
+
|
|
1003
|
+
if (completed === measuredRows.length) {
|
|
1004
|
+
if (measurements.length > 0) {
|
|
1005
|
+
const averageHeight = measurements.reduce((sum, h) => sum + h, 0) / measurements.length;
|
|
1006
|
+
if (DEBUG) {
|
|
1007
|
+
console.log(`[Grid] Measured actual row height: ${averageHeight}px from ${measurements.length} measured rows`);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Clear measured refs for next measurement cycle
|
|
1011
|
+
measuredRowsRef.current = [];
|
|
1012
|
+
|
|
1013
|
+
resolve(averageHeight);
|
|
1014
|
+
} else {
|
|
1015
|
+
resolve(null);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
} else {
|
|
1020
|
+
completed++;
|
|
1021
|
+
if (completed === measuredRows.length && measurements.length === 0) {
|
|
1022
|
+
resolve(null);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
// Timeout fallback
|
|
1028
|
+
setTimeout(() => {
|
|
1029
|
+
if (measurements.length > 0) {
|
|
1030
|
+
const averageHeight = measurements.reduce((sum, h) => sum + h, 0) / measurements.length;
|
|
1031
|
+
if (DEBUG) {
|
|
1032
|
+
log(`[Grid] Measured actual row height (timeout): ${averageHeight}px from ${measurements.length} measured rows`);
|
|
1033
|
+
}
|
|
1034
|
+
measuredRowsRef.current = [];
|
|
1035
|
+
resolve(averageHeight);
|
|
1036
|
+
} else {
|
|
1037
|
+
resolve(null);
|
|
1038
|
+
}
|
|
1039
|
+
}, 200);
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
943
1042
|
|
|
944
1043
|
if (measuredCount > 0) {
|
|
945
1044
|
const averageHeight = totalHeight / measuredCount;
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1045
|
+
|
|
1046
|
+
if (DEBUG) {
|
|
1047
|
+
console.log(`${getMeasurementPhase()}, measureActualRowHeights C averageHeight=${averageHeight}, measuredCount=${measuredCount}`);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// Clear measured refs for next measurement cycle
|
|
1051
|
+
measuredRowsRef.current = [];
|
|
949
1052
|
|
|
950
|
-
|
|
951
|
-
|
|
1053
|
+
return averageHeight;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (DEBUG) {
|
|
1057
|
+
console.log(`${getMeasurementPhase()}, measureActualRowHeights D measuredCount=0`);
|
|
1058
|
+
}
|
|
1059
|
+
return null;
|
|
1060
|
+
},
|
|
1061
|
+
applyMeasuredRowHeight = (averageHeight) => {
|
|
1062
|
+
if (DEBUG) {
|
|
1063
|
+
console.log(`${getMeasurementPhase()}, applyMeasuredRowHeight A averageHeight=${averageHeight}, lastMeasuredContainerHeight=${lastMeasuredContainerHeight}, setMeasurementPhase(${PHASES__OPTIMIZED})`);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Always transition to optimized phase, even if measurement failed
|
|
1067
|
+
setMeasurementPhase(PHASES__OPTIMIZED);
|
|
1068
|
+
|
|
1069
|
+
if (averageHeight) {
|
|
1070
|
+
setMeasuredRowHeight(averageHeight);
|
|
952
1071
|
|
|
953
1072
|
// Recalculate pageSize with actual measurements
|
|
954
1073
|
if (lastMeasuredContainerHeight > 0) {
|
|
1074
|
+
if (DEBUG) {
|
|
1075
|
+
console.log(`${getMeasurementPhase()}, applyMeasuredRowHeight B call calculatePageSize(${lastMeasuredContainerHeight}, true)`);
|
|
1076
|
+
}
|
|
955
1077
|
const newPageSize = calculatePageSize(lastMeasuredContainerHeight, true);
|
|
956
|
-
console.log(`[Grid] Optimized pageSize: ${newPageSize} (was ${Repository.pageSize})`);
|
|
957
1078
|
if (newPageSize !== Repository.pageSize) {
|
|
1079
|
+
if (DEBUG) {
|
|
1080
|
+
console.log(`${getMeasurementPhase()}, applyMeasuredRowHeight B Repository.setPageSize(${newPageSize})`);
|
|
1081
|
+
}
|
|
958
1082
|
Repository.setPageSize(newPageSize);
|
|
959
1083
|
}
|
|
960
1084
|
}
|
|
1085
|
+
} else {
|
|
1086
|
+
if (DEBUG) {
|
|
1087
|
+
console.log(`[Grid] Row height measurement failed or unavailable - using estimated pageSize`);
|
|
1088
|
+
}
|
|
1089
|
+
// Keep the current estimated pageSize, just hide the loading overlay
|
|
961
1090
|
}
|
|
962
1091
|
},
|
|
963
1092
|
adjustPageSizeToHeight = (e) => {
|
|
964
|
-
if (CURRENT_MODE !== UI_MODE_WEB) { // TODO: Remove this conditional, and don't even do the double render for RN
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
1093
|
if (!Repository || Repository.isDestroyed) { // This method gets delayed, so it's possible for Repository to have been destroyed. Check for this
|
|
968
1094
|
return;
|
|
969
1095
|
}
|
|
1096
|
+
if (onLayout) {
|
|
1097
|
+
onLayout(e);
|
|
1098
|
+
}
|
|
1099
|
+
if (DEBUG) {
|
|
1100
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A`);
|
|
1101
|
+
}
|
|
970
1102
|
|
|
971
1103
|
let doAdjustment = autoAdjustPageSizeToHeight;
|
|
972
1104
|
if (!_.isNil(UiGlobals.autoAdjustPageSizeToHeight) && !UiGlobals.autoAdjustPageSizeToHeight) {
|
|
973
1105
|
// allow global override to prevent this auto adjustment
|
|
974
1106
|
doAdjustment = false;
|
|
975
1107
|
}
|
|
976
|
-
if (
|
|
977
|
-
|
|
978
|
-
|
|
1108
|
+
if (DEBUG) {
|
|
1109
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A2 doAdjustment=${doAdjustment}, autoAdjustPageSizeToHeight=${autoAdjustPageSizeToHeight}, UiGlobals.autoAdjustPageSizeToHeight=${UiGlobals.autoAdjustPageSizeToHeight}`);
|
|
1110
|
+
}
|
|
1111
|
+
const containerHeight = e.nativeEvent.layout.height;
|
|
1112
|
+
if (DEBUG) {
|
|
1113
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A3 containerHeight=${containerHeight}`);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Only proceed if height changed significantly
|
|
1117
|
+
const
|
|
1118
|
+
heightChanged = Math.abs(containerHeight - lastMeasuredContainerHeight) > 5, // 5px tolerance
|
|
1119
|
+
isFirstMeasurement = lastMeasuredContainerHeight === 0;
|
|
1120
|
+
if (containerHeight > 0 && (isFirstMeasurement || heightChanged)) {
|
|
1121
|
+
if (editorType === EDITOR_TYPE__SIDE && getIsEditorShown()) {
|
|
1122
|
+
// When side editor is shown, skip adjustment to avoid layout thrashing
|
|
1123
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A4 height changed significantly, but side editor is shown, skipping remeasurement`);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
if (DEBUG) {
|
|
1127
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A4 height changed significantly, proceeding with remeasurement`);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (doAdjustment) {
|
|
979
1131
|
setLastMeasuredContainerHeight(containerHeight);
|
|
980
1132
|
|
|
981
1133
|
// Phase 1: Initial calculation with buffer
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1134
|
+
if (DEBUG) {
|
|
1135
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight B call calculatePageSize(${containerHeight}, false)`);
|
|
1136
|
+
}
|
|
1137
|
+
const
|
|
1138
|
+
useActualMeasurements = (getMeasurementPhase() === PHASES__OPTIMIZED && getMeasuredRowHeight()),
|
|
1139
|
+
pageSize = calculatePageSize(containerHeight, useActualMeasurements);
|
|
1140
|
+
if (DEBUG) {
|
|
1141
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight C containerHeight=${containerHeight}, pageSize=${pageSize}, currentPageSize=${Repository.pageSize}`);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
985
1144
|
if (pageSize !== Repository.pageSize) {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
// Trigger Phase 2: Enable measurement mode after render
|
|
989
|
-
if (measurementPhase === PHASES_INITIAL) {
|
|
990
|
-
setMeasurementPhase(PHASES_MEASURING);
|
|
1145
|
+
if (DEBUG) {
|
|
1146
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight D Repository.setPageSize(${pageSize})`);
|
|
991
1147
|
}
|
|
1148
|
+
Repository.setPageSize(pageSize);
|
|
992
1149
|
}
|
|
993
1150
|
}
|
|
1151
|
+
|
|
1152
|
+
// Trigger Phase 2: Enable measurement mode after render
|
|
1153
|
+
if (getMeasurementPhase() === PHASES__INITIAL) {
|
|
1154
|
+
if (DEBUG) {
|
|
1155
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight E setMeasurementPhase(${PHASES__MEASURING})`);
|
|
1156
|
+
}
|
|
1157
|
+
setMeasurementPhase(PHASES__MEASURING);
|
|
1158
|
+
}
|
|
1159
|
+
} else {
|
|
1160
|
+
if (DEBUG) {
|
|
1161
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A5 height unchanged, skipping remeasurement`);
|
|
1162
|
+
}
|
|
994
1163
|
}
|
|
995
1164
|
},
|
|
996
1165
|
debouncedAdjustPageSizeToHeight = useCallback(_.debounce(adjustPageSizeToHeight, 200), []),
|
|
@@ -1130,22 +1299,24 @@ function GridComponent(props) {
|
|
|
1130
1299
|
|
|
1131
1300
|
useEffect(() => {
|
|
1132
1301
|
if (!isInited) {
|
|
1133
|
-
// first call
|
|
1302
|
+
// first call, Repository.pauseEvents, while we render placeholder so we get container dimensions
|
|
1134
1303
|
if (Repository) {
|
|
1135
1304
|
if (Repository.isRemote) {
|
|
1136
1305
|
Repository.isAutoLoad = false;
|
|
1137
1306
|
}
|
|
1307
|
+
if (DEBUG) {
|
|
1308
|
+
console.log(`${getMeasurementPhase()}, useEffect 1 - first call, Repository.pauseEvents, while we render placeholder to get container dimensions`);
|
|
1309
|
+
}
|
|
1138
1310
|
Repository.pauseEvents();
|
|
1139
1311
|
}
|
|
1140
|
-
if (onRender) {
|
|
1141
|
-
onRender(self)
|
|
1142
|
-
}
|
|
1143
1312
|
return () => {};
|
|
1144
1313
|
}
|
|
1145
1314
|
|
|
1146
1315
|
(async () => {
|
|
1147
|
-
|
|
1148
|
-
|
|
1316
|
+
if (DEBUG) {
|
|
1317
|
+
console.log(`${getMeasurementPhase()}, useEffect 1 - second call, do other necessary column setup`);
|
|
1318
|
+
}
|
|
1319
|
+
// second call, do other necessary column setup
|
|
1149
1320
|
let columnsConfigVariable = columnsConfig,
|
|
1150
1321
|
localColumnsConfig = [],
|
|
1151
1322
|
savedLocalColumnsConfig,
|
|
@@ -1231,6 +1402,9 @@ function GridComponent(props) {
|
|
|
1231
1402
|
|
|
1232
1403
|
setLocalColumnsConfig(localColumnsConfig);
|
|
1233
1404
|
|
|
1405
|
+
if (onRender) {
|
|
1406
|
+
onRender(self)
|
|
1407
|
+
}
|
|
1234
1408
|
setIsReady(true);
|
|
1235
1409
|
})();
|
|
1236
1410
|
|
|
@@ -1243,23 +1417,12 @@ function GridComponent(props) {
|
|
|
1243
1417
|
setTrue = () => setIsLoading(true),
|
|
1244
1418
|
setFalse = () => setIsLoading(false),
|
|
1245
1419
|
onChangeFilters = () => {
|
|
1420
|
+
if (DEBUG) {
|
|
1421
|
+
console.log('onChangeFilters, reload and re-measure');
|
|
1422
|
+
}
|
|
1246
1423
|
if (!Repository.isAutoLoad) {
|
|
1247
1424
|
Repository.reload();
|
|
1248
1425
|
}
|
|
1249
|
-
|
|
1250
|
-
// Reset measurement phase and recalculate pageSize if auto-adjust is enabled
|
|
1251
|
-
if (autoAdjustPageSizeToHeight && lastMeasuredContainerHeight > 0) {
|
|
1252
|
-
console.log(`[Grid] Filters changed - resetting pageSize measurement`);
|
|
1253
|
-
setMeasurementPhase(PHASES_INITIAL);
|
|
1254
|
-
setMeasuredRowHeight(null);
|
|
1255
|
-
sampleRowsRef.current = [];
|
|
1256
|
-
|
|
1257
|
-
// Recalculate pageSize with fresh measurements
|
|
1258
|
-
const pageSize = calculatePageSize(lastMeasuredContainerHeight, false);
|
|
1259
|
-
if (pageSize !== Repository.pageSize) {
|
|
1260
|
-
Repository.setPageSize(pageSize);
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
1426
|
},
|
|
1264
1427
|
onChangeSorters = () => {
|
|
1265
1428
|
if (!Repository.isAutoLoad) {
|
|
@@ -1283,9 +1446,16 @@ function GridComponent(props) {
|
|
|
1283
1446
|
Repository.on('changePage', onChangePage);
|
|
1284
1447
|
|
|
1285
1448
|
applySelectorSelected();
|
|
1449
|
+
|
|
1450
|
+
if (DEBUG) {
|
|
1451
|
+
console.log(`${getMeasurementPhase()}, useEffect 1 - Repository.resumeEvents()`);
|
|
1452
|
+
}
|
|
1286
1453
|
Repository.resumeEvents();
|
|
1287
1454
|
|
|
1288
1455
|
if (((Repository.isRemote && !Repository.isLoaded && !Repository.isLoading) || forceLoadOnRender) && !disableLoadOnRender) { // default remote repositories to load on render, optionally force or disable load on render
|
|
1456
|
+
if (DEBUG) {
|
|
1457
|
+
console.log(`${getMeasurementPhase()}, useEffect 1 - Repository.load()`);
|
|
1458
|
+
}
|
|
1289
1459
|
Repository.load();
|
|
1290
1460
|
}
|
|
1291
1461
|
|
|
@@ -1307,27 +1477,47 @@ function GridComponent(props) {
|
|
|
1307
1477
|
return () => {};
|
|
1308
1478
|
}
|
|
1309
1479
|
|
|
1480
|
+
if (DEBUG) {
|
|
1481
|
+
console.log(`useEffect 2 - applySelectorSelected()`);
|
|
1482
|
+
}
|
|
1310
1483
|
applySelectorSelected();
|
|
1311
1484
|
|
|
1312
1485
|
}, [selectorId, selectorSelected]);
|
|
1313
1486
|
|
|
1314
1487
|
// Effect to trigger row height measurement after render
|
|
1315
1488
|
useEffect(() => {
|
|
1316
|
-
if (
|
|
1317
|
-
// Small delay to ensure
|
|
1318
|
-
const timer = setTimeout(() => {
|
|
1319
|
-
|
|
1320
|
-
|
|
1489
|
+
if (getMeasurementPhase() === PHASES__MEASURING) {
|
|
1490
|
+
// Small delay to ensure elements are fully rendered
|
|
1491
|
+
const timer = setTimeout(async () => {
|
|
1492
|
+
try {
|
|
1493
|
+
if (DEBUG) {
|
|
1494
|
+
console.log(`${getMeasurementPhase()}, useEffect 3 call measureActualRowHeights()`);
|
|
1495
|
+
}
|
|
1496
|
+
const averageHeight = await measureActualRowHeights();
|
|
1497
|
+
if (DEBUG) {
|
|
1498
|
+
console.log(`${getMeasurementPhase()}, useEffect 3 averageHeight=${averageHeight}, call applyMeasuredRowHeight()`);
|
|
1499
|
+
}
|
|
1500
|
+
applyMeasuredRowHeight(averageHeight);
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
if (DEBUG) {
|
|
1503
|
+
console.warn('useEffect 3 - error', error);
|
|
1504
|
+
}
|
|
1505
|
+
// Fallback: use default height estimation
|
|
1506
|
+
applyMeasuredRowHeight(null);
|
|
1507
|
+
}
|
|
1508
|
+
}, 1000);
|
|
1321
1509
|
return () => clearTimeout(timer);
|
|
1322
1510
|
}
|
|
1323
|
-
}, [
|
|
1511
|
+
}, [getMeasurementPhase(), data]);
|
|
1324
1512
|
|
|
1325
|
-
// Effect to reset measurement state when autoAdjustPageSizeToHeight changes
|
|
1326
1513
|
useEffect(() => {
|
|
1327
|
-
if (autoAdjustPageSizeToHeight) {
|
|
1328
|
-
|
|
1514
|
+
if (autoAdjustPageSizeToHeight && getMeasurementPhase() !== PHASES__INITIAL) {
|
|
1515
|
+
if (DEBUG) {
|
|
1516
|
+
console.log(`${getMeasurementPhase()}, useEffect 4 setMeasurementPhase(${PHASES__INITIAL})`);
|
|
1517
|
+
}
|
|
1518
|
+
setMeasurementPhase(PHASES__INITIAL);
|
|
1329
1519
|
setMeasuredRowHeight(null);
|
|
1330
|
-
|
|
1520
|
+
measuredRowsRef.current = [];
|
|
1331
1521
|
}
|
|
1332
1522
|
}, [autoAdjustPageSizeToHeight]);
|
|
1333
1523
|
|
|
@@ -1340,7 +1530,7 @@ function GridComponent(props) {
|
|
|
1340
1530
|
self.gridRef = gridRef;
|
|
1341
1531
|
}
|
|
1342
1532
|
|
|
1343
|
-
|
|
1533
|
+
isAddingRaw.current = isAdding;
|
|
1344
1534
|
|
|
1345
1535
|
const footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons, isReorderMode]);
|
|
1346
1536
|
|
|
@@ -1348,7 +1538,13 @@ function GridComponent(props) {
|
|
|
1348
1538
|
// first time through, render a placeholder so we can get container dimensions
|
|
1349
1539
|
return <VStackNative
|
|
1350
1540
|
onLayout={(e) => {
|
|
1541
|
+
if (DEBUG) {
|
|
1542
|
+
console.log(`${getMeasurementPhase()}, placeholder onLayout, call adjustPageSizeToHeight()`);
|
|
1543
|
+
}
|
|
1351
1544
|
adjustPageSizeToHeight(e);
|
|
1545
|
+
if (DEBUG) {
|
|
1546
|
+
console.log(`${getMeasurementPhase()}, placeholder onLayout, call setIsInited(true)`);
|
|
1547
|
+
}
|
|
1352
1548
|
setIsInited(true);
|
|
1353
1549
|
}}
|
|
1354
1550
|
className="w-full flex-1"
|
|
@@ -1383,7 +1579,7 @@ function GridComponent(props) {
|
|
|
1383
1579
|
showMoreOnly = true;
|
|
1384
1580
|
}
|
|
1385
1581
|
listFooterComponent = <PaginationToolbar
|
|
1386
|
-
ref={
|
|
1582
|
+
ref={footerToolbarRef}
|
|
1387
1583
|
Repository={Repository}
|
|
1388
1584
|
self={self}
|
|
1389
1585
|
toolbarItems={footerToolbarItemComponents}
|
|
@@ -1392,7 +1588,9 @@ function GridComponent(props) {
|
|
|
1392
1588
|
{..._paginationToolbarProps}
|
|
1393
1589
|
/>;
|
|
1394
1590
|
} else if (footerToolbarItemComponents.length) {
|
|
1395
|
-
listFooterComponent = <Toolbar
|
|
1591
|
+
listFooterComponent = <Toolbar
|
|
1592
|
+
ref={footerToolbarRef}
|
|
1593
|
+
>
|
|
1396
1594
|
<ReloadButton Repository={Repository} self={self} />
|
|
1397
1595
|
{footerToolbarItemComponents}
|
|
1398
1596
|
</Toolbar>;
|
|
@@ -1490,7 +1688,10 @@ function GridComponent(props) {
|
|
|
1490
1688
|
className={className}
|
|
1491
1689
|
style={style}
|
|
1492
1690
|
>
|
|
1493
|
-
{topToolbar
|
|
1691
|
+
{topToolbar &&
|
|
1692
|
+
<VStack ref={topToolbarRef}>
|
|
1693
|
+
{topToolbar}
|
|
1694
|
+
</VStack>}
|
|
1494
1695
|
|
|
1495
1696
|
<VStack
|
|
1496
1697
|
ref={gridContainerRef}
|
|
@@ -1505,10 +1706,19 @@ function GridComponent(props) {
|
|
|
1505
1706
|
// 'h-full',
|
|
1506
1707
|
'flex-1',
|
|
1507
1708
|
'min-h-[40px]',
|
|
1709
|
+
'relative', // Enable positioning for overlay
|
|
1508
1710
|
gridContainerBorderClassName,
|
|
1509
1711
|
)}
|
|
1510
1712
|
>
|
|
1511
1713
|
{grid}
|
|
1714
|
+
{/* Loading overlay during measurement phases to prevent visual flashing */}
|
|
1715
|
+
{autoAdjustPageSizeToHeight &&
|
|
1716
|
+
(getMeasurementPhase() === PHASES__INITIAL || getMeasurementPhase() === PHASES__MEASURING) &&
|
|
1717
|
+
entities?.length > 0 && (
|
|
1718
|
+
<VStack className="absolute inset-0 z-10 bg-white">
|
|
1719
|
+
<Loading isScreen={true} />
|
|
1720
|
+
</VStack>
|
|
1721
|
+
)}
|
|
1512
1722
|
</VStack>
|
|
1513
1723
|
|
|
1514
1724
|
{listFooterComponent}
|