funda-ui 4.7.711 → 4.7.730
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/DragDropList/index.d.ts +1 -0
- package/DragDropList/index.js +143 -52
- package/DynamicFields/index.d.ts +1 -0
- package/DynamicFields/index.js +108 -8
- package/EventCalendarTimeline/index.css +12 -1
- package/EventCalendarTimeline/index.d.ts +1 -0
- package/EventCalendarTimeline/index.js +99 -6
- package/MultipleSelect/index.js +162 -71
- package/Table/index.css +5 -1
- package/Table/index.js +410 -90
- package/Utils/useBoundedDrag.d.ts +1 -0
- package/Utils/useBoundedDrag.js +124 -39
- package/lib/cjs/DragDropList/index.d.ts +1 -0
- package/lib/cjs/DragDropList/index.js +143 -52
- package/lib/cjs/DynamicFields/index.d.ts +1 -0
- package/lib/cjs/DynamicFields/index.js +108 -8
- package/lib/cjs/EventCalendarTimeline/index.d.ts +1 -0
- package/lib/cjs/EventCalendarTimeline/index.js +99 -6
- package/lib/cjs/MultipleSelect/index.js +162 -71
- package/lib/cjs/Table/index.js +410 -90
- package/lib/cjs/Utils/useBoundedDrag.d.ts +1 -0
- package/lib/cjs/Utils/useBoundedDrag.js +124 -39
- package/lib/css/EventCalendarTimeline/index.css +12 -1
- package/lib/css/Table/index.css +5 -1
- package/lib/esm/DragDropList/index.tsx +23 -16
- package/lib/esm/DynamicFields/index.tsx +107 -8
- package/lib/esm/EventCalendarTimeline/index.scss +15 -1
- package/lib/esm/EventCalendarTimeline/index.tsx +130 -11
- package/lib/esm/ModalDialog/index.tsx +0 -1
- package/lib/esm/Table/Table.tsx +9 -7
- package/lib/esm/Table/TableRow.tsx +9 -3
- package/lib/esm/Table/index.scss +8 -2
- package/lib/esm/Table/utils/DragHandleSprite.tsx +6 -2
- package/lib/esm/Table/utils/func.ts +12 -1
- package/lib/esm/Table/utils/hooks/useTableDraggable.tsx +401 -93
- package/lib/esm/Utils/hooks/useBoundedDrag.tsx +142 -39
- package/package.json +1 -1
package/lib/cjs/Table/index.js
CHANGED
|
@@ -575,6 +575,13 @@ function initOrderProps(rootElem) {
|
|
|
575
575
|
}
|
|
576
576
|
function initRowColProps(rootElem) {
|
|
577
577
|
if (rootElem === null) return;
|
|
578
|
+
|
|
579
|
+
// !!! Important, performance optimization for large data renderings
|
|
580
|
+
// With this protection, it is only performed once
|
|
581
|
+
if (typeof rootElem.dataset.rowColPropsInit !== 'undefined') return;
|
|
582
|
+
rootElem.dataset.rowColPropsInit = '1';
|
|
583
|
+
|
|
584
|
+
//
|
|
578
585
|
var _allRows = allRows(rootElem);
|
|
579
586
|
var _allHeadRows = allHeadRows(rootElem);
|
|
580
587
|
|
|
@@ -662,7 +669,10 @@ function cellMark(row, col) {
|
|
|
662
669
|
}
|
|
663
670
|
function removeCellFocusClassName(root) {
|
|
664
671
|
if (root) {
|
|
665
|
-
|
|
672
|
+
// !!! Important, performance optimization for large data renderings
|
|
673
|
+
// Only query elements with cell-focus classes
|
|
674
|
+
var focusedCells = root.querySelectorAll('td.cell-focus, th.cell-focus');
|
|
675
|
+
focusedCells.forEach(function (el) {
|
|
666
676
|
el.classList.remove('cell-focus');
|
|
667
677
|
});
|
|
668
678
|
}
|
|
@@ -800,6 +810,32 @@ const App = () => {
|
|
|
800
810
|
|
|
801
811
|
*/
|
|
802
812
|
|
|
813
|
+
/**
|
|
814
|
+
* Performance Optimizations for Large Data Sets:
|
|
815
|
+
*
|
|
816
|
+
* This hook has been optimized to handle large datasets (1000+ rows) efficiently.
|
|
817
|
+
* Key optimizations include:
|
|
818
|
+
*
|
|
819
|
+
* 1. RequestAnimationFrame for DOM Updates
|
|
820
|
+
* - DOM operations are batched within requestAnimationFrame callbacks
|
|
821
|
+
* - Browser executes updates before next frame render, reducing visual lag
|
|
822
|
+
* - Pending RAF callbacks are cancelled to prevent accumulation
|
|
823
|
+
*
|
|
824
|
+
* 2. Caching Strategy
|
|
825
|
+
* - tbodyRef: Cached to avoid repeated DOM queries
|
|
826
|
+
* - colCount: Cached to eliminate repeated queries in placeholderGenerator
|
|
827
|
+
* - allRowsCache: Cached with time-based invalidation (100ms)
|
|
828
|
+
*
|
|
829
|
+
* 3. Redundant Operation Prevention
|
|
830
|
+
* - Tracks last hovered row order (lastOverOrder)
|
|
831
|
+
* - Skips placeholder operations when hovering over the same row
|
|
832
|
+
* - Reduces unnecessary DOM manipulations during drag
|
|
833
|
+
*
|
|
834
|
+
* 4. Batch DOM Operations
|
|
835
|
+
* - removePlaceholder: Uses cached tbodyRef and batch removal
|
|
836
|
+
* - handleDragEnd: Uses DocumentFragment for batch DOM updates
|
|
837
|
+
* - Map-based lookups instead of repeated querySelector calls
|
|
838
|
+
*/
|
|
803
839
|
|
|
804
840
|
|
|
805
841
|
function useTableDraggable(_ref, deps) {
|
|
@@ -812,43 +848,126 @@ function useTableDraggable(_ref, deps) {
|
|
|
812
848
|
_useState2 = _slicedToArray(_useState, 2),
|
|
813
849
|
sortData = _useState2[0],
|
|
814
850
|
setSortData = _useState2[1];
|
|
851
|
+
var _useState3 = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useState)(false),
|
|
852
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
853
|
+
isDragging = _useState4[0],
|
|
854
|
+
setIsDragging = _useState4[1];
|
|
855
|
+
|
|
856
|
+
// Performance optimization: cache for drag operations
|
|
857
|
+
var dragCacheRef = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useRef)({
|
|
858
|
+
draggedObj: null,
|
|
859
|
+
overObj: null,
|
|
860
|
+
allRowsCache: null,
|
|
861
|
+
lastUpdateTime: 0,
|
|
862
|
+
tbodyRef: null,
|
|
863
|
+
colCount: 0,
|
|
864
|
+
lastOverOrder: null,
|
|
865
|
+
rafId: null
|
|
866
|
+
});
|
|
815
867
|
|
|
816
868
|
// ================================================================
|
|
817
869
|
// drag & drop
|
|
818
870
|
// ================================================================
|
|
819
871
|
var draggedObj = null;
|
|
820
872
|
var overObj = null;
|
|
873
|
+
|
|
874
|
+
// Helper function to filter out cloned elements and get only real rows
|
|
875
|
+
var getRealRows = function getRealRows(rows) {
|
|
876
|
+
return rows.filter(function (row) {
|
|
877
|
+
return !row.classList.contains('row-obj-clonelast') && !row.classList.contains('row-obj-lastplaceholder');
|
|
878
|
+
});
|
|
879
|
+
};
|
|
821
880
|
var placeholderGenerator = function placeholderGenerator(trHeight) {
|
|
822
|
-
|
|
823
|
-
|
|
881
|
+
// Use cached tbodyRef and colCount for better performance
|
|
882
|
+
var tbodyRef = dragCacheRef.current.tbodyRef;
|
|
883
|
+
if (!tbodyRef) {
|
|
884
|
+
tbodyRef = getTbody(spyElement);
|
|
885
|
+
dragCacheRef.current.tbodyRef = tbodyRef;
|
|
886
|
+
}
|
|
887
|
+
if (tbodyRef === null) return null;
|
|
888
|
+
|
|
889
|
+
// Cache colCount to avoid repeated queries
|
|
890
|
+
var colCount = dragCacheRef.current.colCount;
|
|
891
|
+
if (colCount === 0) {
|
|
892
|
+
var firstRow = tbodyRef.querySelector('tr');
|
|
893
|
+
if (firstRow === null) return null;
|
|
894
|
+
colCount = firstRow.children.length;
|
|
895
|
+
dragCacheRef.current.colCount = colCount;
|
|
896
|
+
}
|
|
824
897
|
|
|
825
898
|
// Insert a row at the "index" of the table
|
|
826
899
|
var newRow = document.createElement('tr');
|
|
827
900
|
newRow.className = 'row-placeholder';
|
|
828
901
|
newRow.dataset.placeholder = 'true';
|
|
829
902
|
newRow.style.height = trHeight + 'px';
|
|
903
|
+
newRow.style.minHeight = trHeight + 'px'; // Ensure minimum height
|
|
830
904
|
|
|
831
905
|
// Insert a cell in the row at index
|
|
832
906
|
var newCell = newRow.insertCell(0);
|
|
833
|
-
newCell.colSpan =
|
|
907
|
+
newCell.colSpan = colCount;
|
|
908
|
+
newCell.style.minHeight = trHeight + 'px'; // Ensure cell has minimum height
|
|
834
909
|
|
|
835
|
-
//
|
|
836
|
-
|
|
837
|
-
newCell.
|
|
910
|
+
// Use non-breaking space to ensure proper height rendering
|
|
911
|
+
// Multiple spaces or a placeholder element helps maintain consistent height
|
|
912
|
+
newCell.innerHTML = ' '; // Use instead of regular space for better height consistency
|
|
913
|
+
|
|
914
|
+
return newRow;
|
|
915
|
+
};
|
|
916
|
+
var lastPlaceholderGenerator = function lastPlaceholderGenerator(trHeight) {
|
|
917
|
+
// Use cached tbodyRef and colCount for better performance
|
|
918
|
+
var tbodyRef = dragCacheRef.current.tbodyRef;
|
|
919
|
+
if (!tbodyRef) {
|
|
920
|
+
tbodyRef = getTbody(spyElement);
|
|
921
|
+
dragCacheRef.current.tbodyRef = tbodyRef;
|
|
922
|
+
}
|
|
923
|
+
if (tbodyRef === null) return null;
|
|
924
|
+
var curEl = tbodyRef.querySelector('.row-obj-lastplaceholder');
|
|
925
|
+
if (curEl !== null) return;
|
|
926
|
+
|
|
927
|
+
// Cache colCount to avoid repeated queries
|
|
928
|
+
var colCount = dragCacheRef.current.colCount;
|
|
929
|
+
if (colCount === 0) {
|
|
930
|
+
var firstRow = tbodyRef.querySelector('tr');
|
|
931
|
+
if (firstRow === null) return null;
|
|
932
|
+
colCount = firstRow.children.length;
|
|
933
|
+
dragCacheRef.current.colCount = colCount;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// Create a dedicated last placeholder row that is kept in DOM but hidden by default
|
|
937
|
+
var newRow = document.createElement('tr');
|
|
938
|
+
newRow.className = 'row-obj row-obj-lastplaceholder';
|
|
939
|
+
// NOTE: Do NOT set data-placeholder here, otherwise it will be removed by removePlaceholder
|
|
940
|
+
newRow.style.height = trHeight + 'px';
|
|
941
|
+
newRow.style.minHeight = trHeight + 'px';
|
|
942
|
+
newRow.style.display = 'none';
|
|
943
|
+
var newCell = newRow.insertCell(0);
|
|
944
|
+
newCell.colSpan = colCount;
|
|
945
|
+
newCell.style.minHeight = trHeight + 'px';
|
|
946
|
+
newCell.innerHTML = ' ';
|
|
947
|
+
|
|
948
|
+
// Insert after the last real row (excluding cloned rows)
|
|
949
|
+
var rows = getRealRows(allRows(spyElement));
|
|
950
|
+
var lastRealRow = rows.length > 0 ? rows[rows.length - 1] : null;
|
|
951
|
+
if (lastRealRow && lastRealRow.parentNode === tbodyRef) {
|
|
952
|
+
insertAfter(newRow, lastRealRow);
|
|
953
|
+
} else {
|
|
954
|
+
tbodyRef.appendChild(newRow);
|
|
955
|
+
}
|
|
838
956
|
return newRow;
|
|
839
957
|
};
|
|
958
|
+
|
|
959
|
+
// An invisible HELPER element used to trigger the touch of the last element
|
|
840
960
|
var lastRowGenerator = function lastRowGenerator(trHeight) {
|
|
841
961
|
var tbodyRef = getTbody(spyElement);
|
|
842
962
|
if (tbodyRef === null || tbodyRef.querySelector('tr') === null) return;
|
|
843
|
-
var
|
|
844
|
-
if (
|
|
963
|
+
var curEl = tbodyRef.querySelector('.row-obj-clonelast');
|
|
964
|
+
if (curEl !== null) return;
|
|
845
965
|
|
|
846
966
|
// Insert a row at the "index" of the table
|
|
847
967
|
var newRow = document.createElement('tr');
|
|
848
968
|
newRow.className = 'row-obj row-obj-clonelast';
|
|
849
969
|
newRow.dataset.order = allRows(spyElement).length.toString();
|
|
850
970
|
newRow.style.height = trHeight + 'px';
|
|
851
|
-
newRow.style.display = 'none';
|
|
852
971
|
|
|
853
972
|
// Insert a cell in the row at index
|
|
854
973
|
var newCell = newRow.insertCell(0);
|
|
@@ -857,17 +976,30 @@ function useTableDraggable(_ref, deps) {
|
|
|
857
976
|
// Append a text node to the cell
|
|
858
977
|
var newText = document.createTextNode(' ');
|
|
859
978
|
newCell.appendChild(newText);
|
|
979
|
+
|
|
980
|
+
//
|
|
981
|
+
lastPlaceholderGenerator(trHeight);
|
|
860
982
|
return newRow;
|
|
861
983
|
};
|
|
862
984
|
var removePlaceholder = function removePlaceholder() {
|
|
863
|
-
|
|
985
|
+
// Use cached tbodyRef
|
|
986
|
+
var tbodyRef = dragCacheRef.current.tbodyRef;
|
|
987
|
+
if (!tbodyRef) {
|
|
988
|
+
tbodyRef = getTbody(spyElement);
|
|
989
|
+
dragCacheRef.current.tbodyRef = tbodyRef;
|
|
990
|
+
}
|
|
864
991
|
if (tbodyRef === null) return;
|
|
865
992
|
|
|
866
|
-
//
|
|
867
|
-
var
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
993
|
+
// Optimize: use querySelectorAll and remove in batch
|
|
994
|
+
var placeholders = tbodyRef.querySelectorAll("[data-placeholder]");
|
|
995
|
+
if (placeholders.length > 0) {
|
|
996
|
+
// Use DocumentFragment for batch removal (though in this case direct removal is fine)
|
|
997
|
+
placeholders.forEach(function (node) {
|
|
998
|
+
if (node.parentNode) {
|
|
999
|
+
node.parentNode.removeChild(node);
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
871
1003
|
};
|
|
872
1004
|
|
|
873
1005
|
// Initialize drag & drop data
|
|
@@ -904,114 +1036,289 @@ function useTableDraggable(_ref, deps) {
|
|
|
904
1036
|
};
|
|
905
1037
|
|
|
906
1038
|
// events fired on the drop targets
|
|
1039
|
+
// Optimized with requestAnimationFrame, throttling and caching
|
|
907
1040
|
var handledragOver = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(function (e) {
|
|
908
|
-
|
|
909
|
-
if (tbodyRef === null) return;
|
|
1041
|
+
// Always prevent default in sync code
|
|
910
1042
|
e.preventDefault();
|
|
911
|
-
|
|
912
|
-
draggedObj
|
|
1043
|
+
|
|
1044
|
+
// Use cached draggedObj and tbodyRef
|
|
1045
|
+
var currentDraggedObj = dragCacheRef.current.draggedObj || draggedObj;
|
|
1046
|
+
if (currentDraggedObj === null) return;
|
|
1047
|
+
var tbodyRef = dragCacheRef.current.tbodyRef;
|
|
1048
|
+
if (!tbodyRef) {
|
|
1049
|
+
tbodyRef = getTbody(spyElement);
|
|
1050
|
+
if (tbodyRef === null) return;
|
|
1051
|
+
dragCacheRef.current.tbodyRef = tbodyRef;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Early return for placeholder targets
|
|
913
1055
|
if (e.target.classList.contains('row-placeholder')) return;
|
|
914
1056
|
var itemsWrapper = e.target.parentNode;
|
|
915
|
-
if (itemsWrapper.classList.contains('row-obj')) {
|
|
916
|
-
|
|
1057
|
+
if (!itemsWrapper || !itemsWrapper.classList || !itemsWrapper.classList.contains('row-obj')) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// Skip cloned elements - they should not be valid drop targets
|
|
1062
|
+
if (itemsWrapper.classList.contains('row-obj-lastplaceholder')) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Check if we're still over the same row (avoid unnecessary operations)
|
|
1067
|
+
var currentOrder = Number(itemsWrapper.dataset.order);
|
|
1068
|
+
if (dragCacheRef.current.lastOverOrder === currentOrder) {
|
|
1069
|
+
return; // Same target, skip
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// console.log(' --> overObj: ', itemsWrapper);
|
|
1073
|
+
|
|
1074
|
+
// Use requestAnimationFrame for smoother DOM updates
|
|
1075
|
+
// Cancel previous frame if pending
|
|
1076
|
+
if (dragCacheRef.current.rafId !== null) {
|
|
1077
|
+
cancelAnimationFrame(dragCacheRef.current.rafId);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// Store references for use in RAF callback
|
|
1081
|
+
var targetWrapper = itemsWrapper;
|
|
1082
|
+
var targetOrder = currentOrder;
|
|
1083
|
+
dragCacheRef.current.rafId = requestAnimationFrame(function () {
|
|
1084
|
+
overObj = targetWrapper;
|
|
1085
|
+
dragCacheRef.current.overObj = targetWrapper;
|
|
1086
|
+
dragCacheRef.current.lastOverOrder = targetOrder;
|
|
1087
|
+
currentDraggedObj.style.display = 'none';
|
|
917
1088
|
removePlaceholder();
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1089
|
+
|
|
1090
|
+
// Cache allRows result to avoid multiple queries
|
|
1091
|
+
var cachedRows = dragCacheRef.current.allRowsCache;
|
|
1092
|
+
var now = Date.now();
|
|
1093
|
+
if (!cachedRows || now - dragCacheRef.current.lastUpdateTime > 100) {
|
|
1094
|
+
cachedRows = allRows(spyElement);
|
|
1095
|
+
dragCacheRef.current.allRowsCache = cachedRows;
|
|
1096
|
+
dragCacheRef.current.lastUpdateTime = now;
|
|
922
1097
|
}
|
|
923
|
-
|
|
924
|
-
|
|
1098
|
+
|
|
1099
|
+
// Filter out cloned elements to get real rows count
|
|
1100
|
+
var realRows = getRealRows(cachedRows);
|
|
1101
|
+
var totalRows = realRows.length;
|
|
1102
|
+
var overOrder = Number(overObj.dataset.order);
|
|
1103
|
+
|
|
1104
|
+
// When hovering over the last real row, use its height for placeholder
|
|
1105
|
+
// Otherwise use the overObj's height
|
|
1106
|
+
var isOverLastRow = overOrder === totalRows - 1 && realRows.length > 0 && realRows[totalRows - 1];
|
|
1107
|
+
var placeholderHeight = isOverLastRow ? realRows[totalRows - 1].clientHeight : overObj.clientHeight;
|
|
1108
|
+
var placeholder = placeholderGenerator(placeholderHeight);
|
|
1109
|
+
if (placeholder) {
|
|
1110
|
+
var draggedOrder = Number(currentDraggedObj.dataset.order);
|
|
1111
|
+
//console.log(' --> drag index list: ', draggedOrder, overOrder, totalRows - 1);
|
|
1112
|
+
tbodyRef.insertBefore(placeholder, overObj);
|
|
1113
|
+
}
|
|
1114
|
+
dragCacheRef.current.rafId = null;
|
|
1115
|
+
});
|
|
1116
|
+
}, [sortData, spyElement]);
|
|
925
1117
|
var handleDragStart = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(function (e) {
|
|
926
1118
|
var tbodyRef = getTbody(spyElement);
|
|
927
1119
|
if (tbodyRef === null) return;
|
|
1120
|
+
setIsDragging(true);
|
|
928
1121
|
draggedObj = e.currentTarget;
|
|
1122
|
+
// Cache draggedObj and tbodyRef for performance
|
|
1123
|
+
dragCacheRef.current.draggedObj = draggedObj;
|
|
1124
|
+
dragCacheRef.current.tbodyRef = tbodyRef;
|
|
1125
|
+
dragCacheRef.current.lastOverOrder = null; // Reset
|
|
1126
|
+
|
|
929
1127
|
e.dataTransfer.effectAllowed = 'move';
|
|
930
1128
|
e.dataTransfer.setData('text/html', draggedObj);
|
|
931
1129
|
draggedObj.classList.add('dragging');
|
|
932
|
-
|
|
1130
|
+
|
|
1131
|
+
// Cache allRows and use cached result
|
|
1132
|
+
var cachedRows = allRows(spyElement);
|
|
1133
|
+
dragCacheRef.current.allRowsCache = cachedRows;
|
|
1134
|
+
dragCacheRef.current.lastUpdateTime = Date.now();
|
|
1135
|
+
|
|
1136
|
+
// Cache colCount if not already cached
|
|
1137
|
+
if (dragCacheRef.current.colCount === 0) {
|
|
1138
|
+
var firstRow = tbodyRef.querySelector('tr');
|
|
1139
|
+
if (firstRow) {
|
|
1140
|
+
dragCacheRef.current.colCount = firstRow.children.length;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
var lastRow = cachedRows[cachedRows.length - 1];
|
|
1144
|
+
if (lastRow && !lastRow.classList.contains('row-obj-lastplaceholder')) {
|
|
1145
|
+
lastRow.style.setProperty('display', 'table-row', "important");
|
|
1146
|
+
}
|
|
933
1147
|
|
|
934
1148
|
// callback
|
|
935
1149
|
var dragStart = function dragStart(callback) {
|
|
936
1150
|
callback.call(null, draggedObj, sortData, sortDataByIndex(sortData, data));
|
|
937
1151
|
};
|
|
938
1152
|
onRowDrag === null || onRowDrag === void 0 ? void 0 : onRowDrag(dragStart, null);
|
|
939
|
-
|
|
940
|
-
// init clone <tr>
|
|
941
|
-
// !!! It needs to be put at the end of the code to fix the location of the clone element
|
|
942
|
-
var cloneEl = tbodyRef.querySelector('.row-obj-clonelast');
|
|
943
|
-
if (cloneEl !== null) {
|
|
944
|
-
cloneEl.style.display = 'none';
|
|
945
|
-
}
|
|
946
|
-
}, [handledragOver]);
|
|
1153
|
+
}, [handledragOver, sortData, data, spyElement, onRowDrag]);
|
|
947
1154
|
var handleDragEnd = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(function (e) {
|
|
948
1155
|
var tbodyRef = getTbody(spyElement);
|
|
949
1156
|
if (tbodyRef === null) return;
|
|
950
|
-
|
|
1157
|
+
setIsDragging(false);
|
|
1158
|
+
|
|
1159
|
+
// Use cached draggedObj if available
|
|
1160
|
+
var currentDraggedObj = dragCacheRef.current.draggedObj || draggedObj;
|
|
1161
|
+
var currentOverObj = dragCacheRef.current.overObj || overObj;
|
|
1162
|
+
if (currentDraggedObj) {
|
|
1163
|
+
currentDraggedObj.style.display = 'table-row';
|
|
1164
|
+
currentDraggedObj.classList.remove('dragging');
|
|
1165
|
+
}
|
|
951
1166
|
removePlaceholder();
|
|
952
|
-
draggedObj.classList.remove('dragging');
|
|
953
1167
|
tbodyRef === null || tbodyRef === void 0 ? void 0 : tbodyRef.classList.remove('drag-trigger-mousedown');
|
|
954
|
-
|
|
1168
|
+
|
|
1169
|
+
// Cancel any pending animation frame
|
|
1170
|
+
if (dragCacheRef.current.rafId !== null) {
|
|
1171
|
+
cancelAnimationFrame(dragCacheRef.current.rafId);
|
|
1172
|
+
dragCacheRef.current.rafId = null;
|
|
1173
|
+
}
|
|
1174
|
+
if (currentOverObj === null) {
|
|
1175
|
+
// Reset cache
|
|
1176
|
+
dragCacheRef.current.draggedObj = null;
|
|
1177
|
+
dragCacheRef.current.overObj = null;
|
|
1178
|
+
dragCacheRef.current.allRowsCache = null;
|
|
1179
|
+
dragCacheRef.current.lastOverOrder = null;
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
955
1182
|
|
|
956
1183
|
// update state
|
|
957
1184
|
var curData = [];
|
|
958
1185
|
curData = JSON.parse(JSON.stringify(sortData));
|
|
959
|
-
var from = Number(
|
|
960
|
-
var to = Number(
|
|
961
|
-
|
|
1186
|
+
var from = Number(currentDraggedObj.dataset.order);
|
|
1187
|
+
var to = Number(currentOverObj.dataset.order);
|
|
1188
|
+
|
|
1189
|
+
// Get real rows to determine the actual last row index
|
|
1190
|
+
var allRowsForLastIndex = allRows(spyElement);
|
|
1191
|
+
var realRows = getRealRows(allRowsForLastIndex);
|
|
1192
|
+
var actualLastRowIndex = realRows.length - 1;
|
|
1193
|
+
|
|
1194
|
+
// Standard drag-and-drop logic:
|
|
1195
|
+
// When dragging from a lower index to a higher index, we need to decrement 'to'
|
|
1196
|
+
// because removing the element at 'from' causes all subsequent elements to shift left by 1
|
|
1197
|
+
// However, when dragging to the last position, we want to swap with the last element
|
|
1198
|
+
// After removing 'from', if we want to swap with the last element, we should insert
|
|
1199
|
+
// at the position that will result in the dragged element being at the last position
|
|
1200
|
+
if (from < to) {
|
|
1201
|
+
// Special case: dragging to the last position
|
|
1202
|
+
// We want to swap with the last element, so after removing 'from',
|
|
1203
|
+
// we should insert at the new last position (which is curData.length - 1)
|
|
1204
|
+
// Since 'to' is the original last index, and we're removing 'from' (which is < 'to'),
|
|
1205
|
+
// the new last position after removal is still 'to' (no shift because 'from' is before 'to')
|
|
1206
|
+
// Wait, that's not right. If we remove 'from', elements from 'from+1' to 'to' shift left by 1
|
|
1207
|
+
// So 'to' becomes 'to-1'. But we want to insert at the last position, which is 'to-1'
|
|
1208
|
+
// So we should decrement 'to' as normal. But then the element will be at 'to-1', not 'to'
|
|
1209
|
+
//
|
|
1210
|
+
// Actually, the issue is: when dragging to the last element, we want to SWAP with it
|
|
1211
|
+
// So the dragged element should end up at the last position, and the last element should
|
|
1212
|
+
// end up at the dragged element's original position
|
|
1213
|
+
//
|
|
1214
|
+
// Let's think step by step with an example: [A, B, C, D, E], from=1 (B), to=4 (E)
|
|
1215
|
+
// We want result: [A, C, D, E, B] (B and E swapped)
|
|
1216
|
+
// Step 1: Remove B -> [A, C, D, E] (indices 0-3)
|
|
1217
|
+
// Step 2: Insert B at position 4 -> [A, C, D, E, B] ✓
|
|
1218
|
+
// So 'to' should be 4 (not decremented) to get the correct result
|
|
1219
|
+
if (to === actualLastRowIndex) {
|
|
1220
|
+
// Don't decrement 'to' when dragging to the last position
|
|
1221
|
+
// This ensures the element is inserted at the last position after removal
|
|
1222
|
+
} else {
|
|
1223
|
+
// Normal case: dragging forward but not to the last position
|
|
1224
|
+
to--;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
// If from >= to, no adjustment needed (dragging backward)
|
|
962
1228
|
|
|
963
|
-
//
|
|
964
|
-
|
|
1229
|
+
// Optimize: simplify the sorting logic (the nested loop was inefficient)
|
|
1230
|
+
curData.splice(to, 0, curData.splice(from, 1)[0]);
|
|
1231
|
+
var newData = useTableDraggable_toConsumableArray(curData); // Direct copy instead of nested loop
|
|
965
1232
|
|
|
966
|
-
|
|
1233
|
+
setSortData(newData);
|
|
967
1234
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1235
|
+
// Performance optimization: batch DOM updates using a map
|
|
1236
|
+
var table = spyElement.querySelector('table');
|
|
1237
|
+
if (!table) return;
|
|
1238
|
+
var tbody = table.querySelector('tbody');
|
|
1239
|
+
if (!tbody) return;
|
|
1240
|
+
|
|
1241
|
+
// Get all rows once and create a map for faster lookups
|
|
1242
|
+
// Support both data-key attribute (user-provided) and data-order fallback
|
|
1243
|
+
var allRowsElements = Array.from(allRows(spyElement));
|
|
1244
|
+
|
|
1245
|
+
// Create a map: original index (from sortData) -> row element
|
|
1246
|
+
var rowMap = new Map();
|
|
1247
|
+
allRowsElements.forEach(function (row) {
|
|
1248
|
+
// First try to use data-key attribute (if user provided it)
|
|
1249
|
+
var dataKey = row.getAttribute('data-key');
|
|
1250
|
+
if (dataKey) {
|
|
1251
|
+
var match = dataKey.match(/row-(\d+)/);
|
|
1252
|
+
if (match) {
|
|
1253
|
+
var index = Number(match[1]);
|
|
1254
|
+
rowMap.set(index, row);
|
|
1255
|
+
return;
|
|
973
1256
|
}
|
|
974
1257
|
}
|
|
975
|
-
}
|
|
976
1258
|
|
|
977
|
-
|
|
978
|
-
|
|
1259
|
+
// Fallback: use data-order to match with sortData indices
|
|
1260
|
+
var currentOrder = Number(row.dataset.order);
|
|
1261
|
+
if (sortData && !isNaN(currentOrder) && currentOrder >= 0 && currentOrder < sortData.length) {
|
|
1262
|
+
var originalIndex = sortData[currentOrder];
|
|
1263
|
+
if (originalIndex !== undefined) {
|
|
1264
|
+
rowMap.set(originalIndex, row);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
979
1268
|
|
|
980
|
-
//
|
|
1269
|
+
// Update order attributes using the map (batch operation)
|
|
981
1270
|
newData.forEach(function (curId, order) {
|
|
982
|
-
var _el =
|
|
983
|
-
if (_el !== null
|
|
1271
|
+
var _el = rowMap.get(curId);
|
|
1272
|
+
if (_el !== null && _el !== undefined) {
|
|
1273
|
+
_el.dataset.order = order.toString();
|
|
1274
|
+
}
|
|
984
1275
|
});
|
|
985
1276
|
|
|
986
|
-
//
|
|
987
|
-
|
|
1277
|
+
// Performance optimization: Use DocumentFragment to batch DOM updates
|
|
1278
|
+
// NOTE: Keep the special last placeholder row (`row-obj-lastplaceholder`)
|
|
1279
|
+
// out of the main sort, otherwise it may jump to the top after each drag.
|
|
1280
|
+
var lastPlaceholderRow = allRowsElements.find(function (row) {
|
|
1281
|
+
return row.classList && row.classList.contains('row-obj-lastplaceholder');
|
|
1282
|
+
});
|
|
1283
|
+
var rowsToSort = lastPlaceholderRow ? allRowsElements.filter(function (row) {
|
|
1284
|
+
return row !== lastPlaceholderRow;
|
|
1285
|
+
}) : allRowsElements;
|
|
988
1286
|
var sorter = function sorter(a, b) {
|
|
989
|
-
var txt1 = Number(a.dataset.order)
|
|
990
|
-
|
|
1287
|
+
var txt1 = Number(a.dataset.order);
|
|
1288
|
+
var txt2 = Number(b.dataset.order);
|
|
991
1289
|
return txt2 < txt1 ? -1 : txt2 > txt1 ? 1 : 0;
|
|
992
1290
|
};
|
|
993
|
-
var sorted =
|
|
1291
|
+
var sorted = useTableDraggable_toConsumableArray(rowsToSort).sort(sorter).reverse();
|
|
1292
|
+
|
|
1293
|
+
// Ensure the last placeholder row always stays at the bottom
|
|
1294
|
+
if (lastPlaceholderRow) {
|
|
1295
|
+
sorted.push(lastPlaceholderRow);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Use DocumentFragment to minimize reflows
|
|
1299
|
+
var fragment = document.createDocumentFragment();
|
|
994
1300
|
sorted.forEach(function (e) {
|
|
995
|
-
return
|
|
1301
|
+
return fragment.appendChild(e);
|
|
996
1302
|
});
|
|
1303
|
+
tbody.appendChild(fragment);
|
|
997
1304
|
|
|
998
1305
|
// callback
|
|
999
1306
|
var dragEnd = function dragEnd(callback) {
|
|
1000
|
-
callback.call(null,
|
|
1307
|
+
callback.call(null, currentDraggedObj, newData, sortDataByIndex(newData, data));
|
|
1001
1308
|
};
|
|
1002
1309
|
onRowDrag === null || onRowDrag === void 0 ? void 0 : onRowDrag(null, dragEnd);
|
|
1003
1310
|
|
|
1004
1311
|
// init clone <tr>
|
|
1005
1312
|
// !!! It needs to be put at the end of the code to fix the location of the clone element
|
|
1006
1313
|
var _allRows = allRows(spyElement);
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}, [sortData]);
|
|
1314
|
+
dragCacheRef.current.allRowsCache = _allRows;
|
|
1315
|
+
dragCacheRef.current.lastUpdateTime = Date.now();
|
|
1316
|
+
|
|
1317
|
+
// Reset cache
|
|
1318
|
+
dragCacheRef.current.draggedObj = null;
|
|
1319
|
+
dragCacheRef.current.overObj = null;
|
|
1320
|
+
dragCacheRef.current.lastOverOrder = null;
|
|
1321
|
+
}, [sortData, spyElement, data, onRowDrag]);
|
|
1015
1322
|
(0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useEffect)(function () {
|
|
1016
1323
|
if (enabled) {
|
|
1017
1324
|
if (Array.isArray(data) && data.length > 0) {
|
|
@@ -1030,9 +1337,12 @@ function useTableDraggable(_ref, deps) {
|
|
|
1030
1337
|
}
|
|
1031
1338
|
}, [data, enabled, spyElement].concat(useTableDraggable_toConsumableArray(deps)));
|
|
1032
1339
|
return {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1340
|
+
isDragging: isDragging,
|
|
1341
|
+
dragHandlers: {
|
|
1342
|
+
handleDragStart: handleDragStart,
|
|
1343
|
+
handleDragOver: handledragOver,
|
|
1344
|
+
handleDragEnd: handleDragEnd
|
|
1345
|
+
},
|
|
1036
1346
|
handleTbodyEnter: handleTbodyEnter,
|
|
1037
1347
|
handleTbodyLeave: handleTbodyLeave
|
|
1038
1348
|
};
|
|
@@ -1361,10 +1671,10 @@ var Table = /*#__PURE__*/(0,external_root_React_commonjs2_react_commonjs_react_a
|
|
|
1361
1671
|
spyElement: rootRef.current,
|
|
1362
1672
|
onRowDrag: onRowDrag
|
|
1363
1673
|
}, [data, rootRef]),
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1674
|
+
isDragging = _useTableDraggable.isDragging,
|
|
1675
|
+
dragHandlers = _useTableDraggable.dragHandlers,
|
|
1676
|
+
handleTbodyEnter = _useTableDraggable.handleTbodyEnter,
|
|
1677
|
+
handleTbodyLeave = _useTableDraggable.handleTbodyLeave;
|
|
1368
1678
|
var tableKeyPress = hooks_useTableKeyPress({
|
|
1369
1679
|
enabled: keyboardFocusable,
|
|
1370
1680
|
data: data,
|
|
@@ -1462,9 +1772,10 @@ var Table = /*#__PURE__*/(0,external_root_React_commonjs2_react_commonjs_react_a
|
|
|
1462
1772
|
onColSort: onColSort,
|
|
1463
1773
|
// drag & drop
|
|
1464
1774
|
rowDraggable: rowDraggable,
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1775
|
+
isRowDragging: isDragging,
|
|
1776
|
+
handleDragStart: dragHandlers.handleDragStart,
|
|
1777
|
+
handleDragEnd: dragHandlers.handleDragEnd,
|
|
1778
|
+
handledragOver: dragHandlers.handleDragOver,
|
|
1468
1779
|
handleTbodyEnter: handleTbodyEnter,
|
|
1469
1780
|
// filter
|
|
1470
1781
|
filterFields: filterFields,
|
|
@@ -1695,11 +2006,17 @@ var TableRow = /*#__PURE__*/(0,external_root_React_commonjs2_react_commonjs_reac
|
|
|
1695
2006
|
// selection
|
|
1696
2007
|
// ================================================================
|
|
1697
2008
|
var _res = convertMapToArr(selectedItems);
|
|
2009
|
+
// Performance optimization: stringify itemData only once instead of N times
|
|
2010
|
+
var itemDataStr = itemData ? JSON.stringify(itemData) : '';
|
|
1698
2011
|
var filteredSelectedItems = _res.map(function (v) {
|
|
1699
2012
|
return Number(v);
|
|
1700
2013
|
}).map(function (rowNum) {
|
|
1701
|
-
|
|
1702
|
-
|
|
2014
|
+
var originItem = originData === null || originData === void 0 ? void 0 : originData[rowNum];
|
|
2015
|
+
// Fast path: reference equality
|
|
2016
|
+
if (itemData === originItem) return originItem;
|
|
2017
|
+
// Fallback: JSON comparison (itemDataStr is cached)
|
|
2018
|
+
if (itemDataStr && itemDataStr === JSON.stringify(originItem)) {
|
|
2019
|
+
return originItem;
|
|
1703
2020
|
}
|
|
1704
2021
|
}).filter(Boolean);
|
|
1705
2022
|
var selectedClassName = activeClassName || 'active';
|
|
@@ -1718,9 +2035,7 @@ var TableRow = /*#__PURE__*/(0,external_root_React_commonjs2_react_commonjs_reac
|
|
|
1718
2035
|
var _item$s, _itemData$s;
|
|
1719
2036
|
return !((_item$s = item[s]) !== null && _item$s !== void 0 && _item$s.toLowerCase().includes((_itemData$s = itemData[s]) === null || _itemData$s === void 0 ? void 0 : _itemData$s.toLowerCase()));
|
|
1720
2037
|
});
|
|
1721
|
-
}) ? 'd-none' : '' : '', " ").concat(itemData && originData
|
|
1722
|
-
return JSON.stringify(itemData) === JSON.stringify(item);
|
|
1723
|
-
}) ? selectedClassName : '' : '')
|
|
2038
|
+
}) ? 'd-none' : '' : '', " ").concat(itemData && originData && filteredSelectedItems.length > 0 ? selectedClassName : '')
|
|
1724
2039
|
}), children));
|
|
1725
2040
|
});
|
|
1726
2041
|
/* harmony default export */ const src_TableRow = (TableRow);
|
|
@@ -2027,11 +2342,16 @@ var DragHandleSprite = /*#__PURE__*/(0,external_root_React_commonjs2_react_commo
|
|
|
2027
2342
|
icon = props.icon;
|
|
2028
2343
|
var _useContext = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useContext)(TableContext),
|
|
2029
2344
|
rowDraggable = _useContext.rowDraggable,
|
|
2030
|
-
handleTbodyEnter = _useContext.handleTbodyEnter
|
|
2345
|
+
handleTbodyEnter = _useContext.handleTbodyEnter,
|
|
2346
|
+
handleTbodyLeave = _useContext.handleTbodyLeave;
|
|
2031
2347
|
return /*#__PURE__*/external_root_React_commonjs2_react_commonjs_react_amd_react_default().createElement((external_root_React_commonjs2_react_commonjs_react_amd_react_default()).Fragment, null, rowDraggable ? /*#__PURE__*/external_root_React_commonjs2_react_commonjs_react_amd_react_default().createElement("span", {
|
|
2032
2348
|
ref: externalRef,
|
|
2033
|
-
className: className || 'drag-trigger'
|
|
2034
|
-
|
|
2349
|
+
className: className || 'drag-trigger'
|
|
2350
|
+
// Only when mousedown happens on this handle will we allow row dragging.
|
|
2351
|
+
,
|
|
2352
|
+
onMouseDown: handleTbodyEnter,
|
|
2353
|
+
onMouseUp: handleTbodyLeave,
|
|
2354
|
+
onMouseLeave: handleTbodyLeave
|
|
2035
2355
|
}, icon || /*#__PURE__*/external_root_React_commonjs2_react_commonjs_react_amd_react_default().createElement("svg", {
|
|
2036
2356
|
width: "1em",
|
|
2037
2357
|
height: "1em",
|