@are-visual/virtual-table 0.0.1 → 0.1.1

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/index.esm.js CHANGED
@@ -87,11 +87,11 @@ function isShallowEqual(value, oldValue) {
87
87
  return false;
88
88
  }
89
89
  if (value instanceof Map && oldValue instanceof Map) {
90
- var keys = [].concat(value.keys());
91
- var oldKeys = [].concat(oldValue.keys());
92
- if (shallowEqualArrays(keys, oldKeys)) {
93
- var values = [].concat(value.values());
94
- var oldValues = [].concat(oldValue.values());
90
+ var keys = Array.from(value.keys());
91
+ var oldKeys = Array.from(oldValue.keys());
92
+ if (isShallowEqual(keys, oldKeys)) {
93
+ var values = Array.from(value.values());
94
+ var oldValues = Array.from(oldValue.values());
95
95
  if (isShallowEqual(values, oldValues)) {
96
96
  return true;
97
97
  }
@@ -288,12 +288,23 @@ var Cell$1 = /*#__PURE__*/memo(Cell);
288
288
 
289
289
  var Colgroup = function Colgroup(props) {
290
290
  var columns = props.columns,
291
- colRef = props.colRef;
291
+ onColumnSizesMeasure = props.onColumnSizesMeasure;
292
+ var enableMeasure = onColumnSizesMeasure != null;
293
+ var columnSizes = useRef(new Map());
294
+ var prevColumnSizes = useRef(new Map());
292
295
  return jsx("colgroup", {
293
- children: columns.map(function (item, index) {
296
+ ref: function ref() {
297
+ if (!enableMeasure) return;
298
+ var result = columnSizes.current;
299
+ onColumnSizesMeasure(result, prevColumnSizes.current);
300
+ prevColumnSizes.current = result;
301
+ columnSizes.current = new Map();
302
+ },
303
+ children: columns.map(function (item) {
294
304
  var key = item.key;
295
305
  if (item.type === 'blank') {
296
306
  return jsx("col", {
307
+ className: "blank",
297
308
  style: {
298
309
  width: item.width
299
310
  }
@@ -301,9 +312,10 @@ var Colgroup = function Colgroup(props) {
301
312
  }
302
313
  var column = item.column;
303
314
  return jsx("col", {
304
- ref: typeof colRef === 'function' ? function (instance) {
305
- colRef(instance, column, index);
306
- } : colRef,
315
+ ref: function ref(node) {
316
+ if (node == null || !enableMeasure) return;
317
+ columnSizes.current.set(key, node.offsetWidth);
318
+ },
307
319
  style: {
308
320
  width: column.width,
309
321
  minWidth: column.minWidth
@@ -312,6 +324,7 @@ var Colgroup = function Colgroup(props) {
312
324
  })
313
325
  });
314
326
  };
327
+ var Colgroup$1 = /*#__PURE__*/memo(Colgroup);
315
328
 
316
329
  var overflowStylePatterns = /auto|scroll|overlay|hidden/;
317
330
  function isElement(node) {
@@ -464,25 +477,34 @@ function HorizontalScrollContext(props) {
464
477
  var children = props.children;
465
478
  var listenerMap = useRef(new Map());
466
479
  var context = useMemo(function () {
480
+ var skipEvent = new Set();
467
481
  return {
468
482
  listen: function listen(key, listener) {
469
- listenerMap.current.set(key, listener);
483
+ listenerMap.current.set(key, function (scrollLeft, node) {
484
+ listener(scrollLeft, node);
485
+ });
470
486
  return function () {
471
487
  listenerMap.current["delete"](key);
472
488
  };
473
489
  },
474
- notify: function notify(key, scrollLeft, node) {
490
+ notify: function notify(key, options) {
491
+ if (skipEvent.has(key)) {
492
+ skipEvent["delete"](key);
493
+ return;
494
+ }
495
+ var scrollLeft = options.scrollLeft,
496
+ node = options.node;
475
497
  var rAF = window.requestAnimationFrame;
476
498
  if (rAF == null) {
477
499
  rAF = function rAF(fn) {
478
500
  fn();
479
501
  };
480
502
  }
481
- rAF(function () {
482
- listenerMap.current.forEach(function (listener, itemKey) {
483
- if (itemKey !== key) {
484
- listener(scrollLeft, node);
485
- }
503
+ listenerMap.current.forEach(function (listener, itemKey) {
504
+ if (key === itemKey) return;
505
+ skipEvent.add(itemKey);
506
+ rAF(function () {
507
+ listener(scrollLeft(), node);
486
508
  });
487
509
  });
488
510
  }
@@ -518,7 +540,7 @@ function useStableFn(callback) {
518
540
  var fn = useRef(null);
519
541
  useLayoutEffect(function () {
520
542
  fn.current = callback;
521
- }, [callback]);
543
+ });
522
544
  var stableFn = useCallback(function () {
523
545
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
524
546
  args[_key] = arguments[_key];
@@ -754,7 +776,7 @@ function Row(props) {
754
776
  ref: function ref(node) {
755
777
  if (node == null) return;
756
778
  // 小心陷阱:当 table 父元素为 display: none 时,依然会触发 updateRowHeight 函数,并设置高度为 0
757
- updateRowHeight(rowIndex, node.offsetHeight);
779
+ updateRowHeight(rowIndex, rowIndex, node.offsetHeight);
758
780
  },
759
781
  children: descriptor.map(function (item, index) {
760
782
  var key = item.key;
@@ -804,16 +826,230 @@ function useMergedRef() {
804
826
  return useCallback(mergeRefs.apply(undefined, refs), refs);
805
827
  }
806
828
 
829
+ function onResize(target, callback) {
830
+ if (isWindow(target)) {
831
+ var listener = function listener() {
832
+ callback({
833
+ width: window.innerWidth,
834
+ height: window.innerHeight
835
+ });
836
+ };
837
+ listener();
838
+ window.addEventListener('resize', listener);
839
+ return function () {
840
+ window.removeEventListener('resize', listener);
841
+ };
842
+ } else {
843
+ var observer = new ResizeObserver(function (entries) {
844
+ var rect = entries[0].contentRect;
845
+ callback({
846
+ width: rect.width,
847
+ height: rect.height
848
+ });
849
+ });
850
+ observer.observe(target);
851
+ return function () {
852
+ observer.disconnect();
853
+ };
854
+ }
855
+ }
856
+
857
+ function anchorQuery$1(rects, scrollTop) {
858
+ var left = 0;
859
+ var right = rects.length - 1;
860
+ var index = -1;
861
+ while (left <= right) {
862
+ var mid = Math.floor((left + right) / 2);
863
+ if (rects[mid].bottom > scrollTop) {
864
+ index = mid;
865
+ right = mid - 1;
866
+ } else {
867
+ left = mid + 1;
868
+ }
869
+ }
870
+ if (index === -1) {
871
+ return undefined;
872
+ }
873
+ return rects[index];
874
+ }
875
+ function useRowVirtualize(options) {
876
+ var getOffsetTop = options.getOffsetTop,
877
+ rawData = options.dataSource,
878
+ getScroller = options.getScroller,
879
+ estimateSize = options.estimateSize,
880
+ overscan = options.overscan;
881
+ var _useState = useState(0),
882
+ startIndex = _useState[0],
883
+ setStartIndex = _useState[1];
884
+ var _useState2 = useState(0),
885
+ endIndex = _useState2[0],
886
+ setEndIndex = _useState2[1];
887
+ var dataSlice = useMemo(function () {
888
+ return rawData.slice(startIndex, endIndex);
889
+ }, [rawData, startIndex, endIndex]);
890
+ // 行高信息(先填充预估高度,DOM渲染后再更新成实际高度)
891
+ var rowHeights = useRef([]);
892
+ var fillRowHeights = function fillRowHeights() {
893
+ var len = rawData.length;
894
+ for (var i = 0; i < len; i++) {
895
+ var target = rowHeights.current[i];
896
+ // 由于 fillRowHeights 是在渲染阶段调用,防止重复渲染时 estimateSize 覆盖了真实 DOM 的高度
897
+ if (target == null) {
898
+ rowHeights.current[i] = estimateSize;
899
+ }
900
+ }
901
+ rowHeights.current = rowHeights.current.slice(0, len);
902
+ };
903
+ fillRowHeights();
904
+ // 布局信息(也就是锚点元素需要的信息,top,bottom,height,index)
905
+ var rowRects = useRef([]);
906
+ var updateRowRectList = function updateRowRectList(shouldSkip) {
907
+ if (shouldSkip === undefined) {
908
+ shouldSkip = false;
909
+ }
910
+ if (shouldSkip && rowRects.current.length > 0) {
911
+ return;
912
+ }
913
+ var _rowHeights$current$r = rowHeights.current.reduce(function (result, height, index) {
914
+ var nextTop = result.top + height;
915
+ result.rects.push({
916
+ index: index,
917
+ top: result.top,
918
+ height: height,
919
+ bottom: nextTop
920
+ });
921
+ result.top = nextTop;
922
+ return result;
923
+ }, {
924
+ top: 0,
925
+ rects: []
926
+ }),
927
+ rects = _rowHeights$current$r.rects;
928
+ rowRects.current = rects;
929
+ };
930
+ var setRowHeight = function setRowHeight(index, height) {
931
+ rowHeights.current[index] = height;
932
+ };
933
+ // 锚点元素,当前虚拟列表中,最接近滚动容器顶部的元素
934
+ var anchorRef = useRef({
935
+ index: 0,
936
+ height: estimateSize,
937
+ top: 0,
938
+ bottom: estimateSize
939
+ });
940
+ // 用来判断滚动方向
941
+ var scrollTopRef = useRef(0);
942
+ var initial = useRef(false);
943
+ useEffect(function () {
944
+ var container = getScroller();
945
+ if (container == null) return;
946
+ var count = 0;
947
+ var getScrollTop = function getScrollTop() {
948
+ var offsetTop = getOffsetTop();
949
+ var result = 0;
950
+ if (isWindow(container) || isRoot(container)) {
951
+ result = window.scrollY;
952
+ } else {
953
+ var element = getScrollElement(container);
954
+ result = element.scrollTop;
955
+ }
956
+ return Math.max(result - offsetTop, 0);
957
+ };
958
+ var calcCount = function calcCount(scrollerContainerHeight) {
959
+ var prevCount = count;
960
+ count = Math.ceil(scrollerContainerHeight / estimateSize);
961
+ return {
962
+ prevCount: prevCount
963
+ };
964
+ };
965
+ var updateBoundary = function updateBoundary(scrollTop) {
966
+ var anchor = anchorQuery$1(rowRects.current, scrollTop);
967
+ if (anchor != null) {
968
+ anchorRef.current = anchor;
969
+ setStartIndex(Math.max(0, anchor.index - overscan));
970
+ setEndIndex(anchor.index + count + overscan);
971
+ }
972
+ };
973
+ var onScroll = function onScroll(e) {
974
+ var offsetTop = getOffsetTop();
975
+ var scrollElement = getScrollElement(e.target);
976
+ var scrollTop = Math.max(0, scrollElement.scrollTop - offsetTop);
977
+ // 是否为向下滚动
978
+ var isScrollDown = scrollTop > scrollTopRef.current;
979
+ if (isScrollDown) {
980
+ // 如果滚动距离比较小,没有超出锚点元素的边界,就不需要计算 startIndex、endIndex 了
981
+ if (scrollTop > anchorRef.current.bottom) {
982
+ updateBoundary(scrollTop);
983
+ }
984
+ } else {
985
+ if (scrollTop < anchorRef.current.top) {
986
+ updateBoundary(scrollTop);
987
+ }
988
+ }
989
+ scrollTopRef.current = scrollTop;
990
+ };
991
+ var prevHeight = 0;
992
+ var stopListen = onResize(container, function (rect) {
993
+ // 处理父元素 display:none 容器高度丢失,导致显示 row 不准确
994
+ if (rect.height === prevHeight || rect.height === 0) {
995
+ return;
996
+ }
997
+ prevHeight = rect.height;
998
+ calcCount(rect.height);
999
+ var scrollTop = getScrollTop();
1000
+ if (!initial.current) {
1001
+ initial.current = true;
1002
+ var nextStartIndex = 0;
1003
+ // 判断一下当前滚动位置,计算 startIndex(场景:SPA 页面切换且渲染非异步数据)
1004
+ if (scrollTop >= estimateSize) {
1005
+ nextStartIndex = Math.max(Math.floor(scrollTop / estimateSize) - 1 - overscan, 0);
1006
+ }
1007
+ var nextEndIndex = nextStartIndex + count + overscan;
1008
+ setStartIndex(nextStartIndex);
1009
+ setEndIndex(nextEndIndex);
1010
+ } else {
1011
+ updateBoundary(scrollTop);
1012
+ }
1013
+ });
1014
+ container.addEventListener('scroll', onScroll);
1015
+ return function () {
1016
+ stopListen();
1017
+ container.removeEventListener('scroll', onScroll);
1018
+ };
1019
+ }, [estimateSize, getOffsetTop, getScroller, overscan]);
1020
+ var sum = function sum(startIndex, endIndex) {
1021
+ return rowHeights.current.slice(startIndex, endIndex).reduce(function (a, b) {
1022
+ return a + b;
1023
+ }, 0);
1024
+ };
1025
+ // TODO: React Compiler 测试 topBlank 和 bottomBlank
1026
+ var topBlank = sum(0, startIndex);
1027
+ var bottomBlank = sum(endIndex);
1028
+ return {
1029
+ startIndex: startIndex,
1030
+ endIndex: endIndex,
1031
+ rowHeightList: rowHeights,
1032
+ updateRowRectList: updateRowRectList,
1033
+ setRowHeight: setRowHeight,
1034
+ topBlank: topBlank,
1035
+ bottomBlank: bottomBlank,
1036
+ dataSlice: dataSlice
1037
+ };
1038
+ }
1039
+
807
1040
  function TableBody(props) {
808
1041
  var bodyWrapperRef = props.bodyWrapperRef,
809
1042
  bodyRootRef = props.bodyRootRef,
810
1043
  bodyRef = props.bodyRef,
811
1044
  className = props.className,
812
1045
  style = props.style,
813
- dataSource = props.dataSource,
1046
+ rawData = props.dataSource,
814
1047
  columnDescriptor = props.columns,
815
1048
  rowKey = props.rowKey,
816
- startIndex = props.startIndex,
1049
+ overscan = props.overscan,
1050
+ estimateSize = props.estimateSize,
1051
+ getScroller = props.getScroller,
1052
+ getOffsetTop = props.getOffsetTop,
817
1053
  rowClassName = props.rowClassName,
818
1054
  onRow = props.onRow,
819
1055
  renderBodyWrapper = props.renderBodyWrapper,
@@ -821,23 +1057,53 @@ function TableBody(props) {
821
1057
  renderBody = props.renderBody,
822
1058
  renderRow = props.renderRow,
823
1059
  renderCell = props.renderCell;
1060
+ var _useRowVirtualize = useRowVirtualize({
1061
+ getOffsetTop: getOffsetTop,
1062
+ dataSource: rawData,
1063
+ getScroller: getScroller,
1064
+ estimateSize: estimateSize,
1065
+ overscan: overscan
1066
+ }),
1067
+ startIndex = _useRowVirtualize.startIndex,
1068
+ dataSource = _useRowVirtualize.dataSlice,
1069
+ setRowHeight = _useRowVirtualize.setRowHeight,
1070
+ updateRowRectList = _useRowVirtualize.updateRowRectList,
1071
+ rowHeightList = _useRowVirtualize.rowHeightList,
1072
+ topBlank = _useRowVirtualize.topBlank,
1073
+ bottomBlank = _useRowVirtualize.bottomBlank;
1074
+ var rowHeights = useRef(new Map());
1075
+ var updateRowHeight = useCallback(function (index, key, height) {
1076
+ var _rowHeights$current$g;
1077
+ var target = (_rowHeights$current$g = rowHeights.current.get(index)) != null ? _rowHeights$current$g : new Map();
1078
+ target.set(key, height);
1079
+ rowHeights.current.set(index, target);
1080
+ }, []);
1081
+ var rowManageState = useMemo(function () {
1082
+ return {
1083
+ updateRowHeight: updateRowHeight,
1084
+ getRowHeightList: function getRowHeightList() {
1085
+ return rowHeightList.current;
1086
+ }
1087
+ };
1088
+ }, [rowHeightList, updateRowHeight]);
824
1089
  var columns = columnDescriptor.columns,
825
1090
  descriptor = columnDescriptor.descriptor;
826
- var _useHorizontalScrollC = useHorizontalScrollContext(),
827
- listen = _useHorizontalScrollC.listen,
828
- notify = _useHorizontalScrollC.notify;
829
- var _useColumnSizes = useColumnSizes(),
830
- widthList = _useColumnSizes.widthList,
831
- setWidthList = _useColumnSizes.setWidthList;
832
- var columnWidthsRef = useRef(new Map());
833
- useLayoutEffect(function () {
834
- var snap = widthList;
835
- if (!isShallowEqual(snap, columnWidthsRef.current)) {
836
- setWidthList(new Map(columnWidthsRef.current));
837
- }
1091
+ var tbodyRef = useMergedRef(bodyRef, function (elm) {
1092
+ if (elm == null) return;
1093
+ var bodyHeight = elm.offsetHeight;
1094
+ if (bodyHeight === 0) return;
1095
+ var heights = rowHeights.current;
1096
+ heights.forEach(function (row, rowIndex) {
1097
+ var height = Array.from(row.values()).reduce(function (res, x) {
1098
+ return res + x;
1099
+ }, 0);
1100
+ setRowHeight(rowIndex, height);
1101
+ });
1102
+ updateRowRectList();
1103
+ rowHeights.current.clear();
838
1104
  });
839
1105
  var bodyNode = pipelineRender(jsx("tbody", {
840
- ref: bodyRef,
1106
+ ref: tbodyRef,
841
1107
  children: dataSource.map(function (e, rowIndex) {
842
1108
  var _rowKey = e[rowKey];
843
1109
  return jsx(Row$1, {
@@ -854,30 +1120,43 @@ function TableBody(props) {
854
1120
  columns: columns,
855
1121
  columnDescriptor: descriptor
856
1122
  });
1123
+ var _useColumnSizes = useColumnSizes(),
1124
+ setWidthList = _useColumnSizes.setWidthList;
1125
+ var onColumnSizesMeasure = useCallback(function (columnSizes, oldValue) {
1126
+ if (!isShallowEqual(oldValue, columnSizes)) {
1127
+ setWidthList(columnSizes);
1128
+ }
1129
+ }, [setWidthList]);
857
1130
  var tableNode = pipelineRender(jsxs("table", {
858
1131
  className: clsx(className, 'virtual-table-body'),
859
- style: style,
1132
+ style: _extends({}, style, {
1133
+ paddingBottom: bottomBlank,
1134
+ paddingTop: topBlank
1135
+ }),
860
1136
  ref: bodyRootRef,
861
- children: [jsx(Colgroup, {
1137
+ children: [jsx(Colgroup$1, {
862
1138
  columns: descriptor,
863
- colRef: function colRef(node, column) {
864
- if (node == null) return;
865
- var key = getKey(column);
866
- columnWidthsRef.current.set(key, node.offsetWidth);
867
- }
1139
+ onColumnSizesMeasure: onColumnSizesMeasure
868
1140
  }), bodyNode]
869
1141
  }), renderBodyRoot, {
870
1142
  columns: columns,
871
1143
  columnDescriptor: descriptor
872
1144
  });
1145
+ var _useHorizontalScrollC = useHorizontalScrollContext(),
1146
+ listen = _useHorizontalScrollC.listen,
1147
+ notify = _useHorizontalScrollC.notify;
873
1148
  var wrapperRef = useRef(null);
874
1149
  useEffect(function () {
875
1150
  var node = wrapperRef.current;
876
1151
  if (node == null) return;
877
1152
  var key = 'virtual-table-body';
878
1153
  var onScroll = function onScroll() {
879
- var nextScrollLeft = node.scrollLeft;
880
- notify(key, nextScrollLeft, node);
1154
+ notify(key, {
1155
+ scrollLeft: function scrollLeft() {
1156
+ return node.scrollLeft;
1157
+ },
1158
+ node: node
1159
+ });
881
1160
  };
882
1161
  var dispose = listen(key, function (scrollLeft) {
883
1162
  node.scrollLeft = scrollLeft;
@@ -889,13 +1168,16 @@ function TableBody(props) {
889
1168
  };
890
1169
  }, [listen, notify]);
891
1170
  var mergedRef = useMergedRef(wrapperRef, bodyWrapperRef);
892
- return pipelineRender(jsx("div", {
893
- ref: mergedRef,
894
- className: "virtual-table-body-wrapper",
895
- children: tableNode
896
- }), renderBodyWrapper, {
897
- columns: columns,
898
- columnDescriptor: descriptor
1171
+ return jsx(TableRowManager.Provider, {
1172
+ value: rowManageState,
1173
+ children: pipelineRender(jsx("div", {
1174
+ ref: mergedRef,
1175
+ className: "virtual-table-body-wrapper",
1176
+ children: tableNode
1177
+ }), renderBodyWrapper, {
1178
+ columns: columns,
1179
+ columnDescriptor: descriptor
1180
+ })
899
1181
  });
900
1182
  }
901
1183
 
@@ -913,6 +1195,7 @@ var TableHeader = function TableHeader(props) {
913
1195
  renderHeaderCell = props.renderHeaderCell;
914
1196
  var columns = columnDescriptor.columns,
915
1197
  descriptor = columnDescriptor.descriptor;
1198
+ var lastColumn = columns[columns.length - 1];
916
1199
  var _useColumnSizes = useColumnSizes(),
917
1200
  widthList = _useColumnSizes.widthList;
918
1201
  var _useTableSticky = useTableSticky(),
@@ -938,8 +1221,12 @@ var TableHeader = function TableHeader(props) {
938
1221
  if (node == null) return;
939
1222
  var key = 'virtual-table-header';
940
1223
  var onScroll = function onScroll() {
941
- var nextScrollLeft = node.scrollLeft;
942
- notify(key, nextScrollLeft, node);
1224
+ notify(key, {
1225
+ scrollLeft: function scrollLeft() {
1226
+ return node.scrollLeft;
1227
+ },
1228
+ node: node
1229
+ });
943
1230
  };
944
1231
  var dispose = listen(key, function (scrollLeft) {
945
1232
  node.scrollLeft = scrollLeft;
@@ -955,12 +1242,15 @@ var TableHeader = function TableHeader(props) {
955
1242
  var _column$onHeaderCell;
956
1243
  var key = item.key;
957
1244
  if (item.type === 'blank') {
958
- return jsx("th", {}, key);
1245
+ return jsx("th", {
1246
+ "data-blank": true
1247
+ }, key);
959
1248
  }
960
1249
  var column = item.column;
961
1250
  if (column.colSpan === 0) {
962
1251
  return null;
963
1252
  }
1253
+ var isLast = getKey(lastColumn) === key;
964
1254
  var _ref = (_column$onHeaderCell = column.onHeaderCell == null ? undefined : column.onHeaderCell(column, index)) != null ? _column$onHeaderCell : {},
965
1255
  thClassName = _ref.className,
966
1256
  thStyle = _ref.style,
@@ -970,7 +1260,7 @@ var TableHeader = function TableHeader(props) {
970
1260
  scope: 'col'
971
1261
  }, rest, {
972
1262
  colSpan: column.colSpan,
973
- className: clsx('virtual-table-header-cell', column.align != null && "virtual-table-align-" + column.align, isValidFixed(column.fixed) && 'virtual-table-sticky-cell', lastFixedLeftColumnIndex === index && 'virtual-table-cell-fix-left-last', firstFixedRightColumnIndex === index && 'virtual-table-cell-fix-right-first', column.className, thClassName),
1263
+ className: clsx('virtual-table-header-cell', isLast && 'no-split', column.align != null && "virtual-table-align-" + column.align, isValidFixed(column.fixed) && 'virtual-table-sticky-cell', lastFixedLeftColumnIndex === index && 'virtual-table-cell-fix-left-last', firstFixedRightColumnIndex === index && 'virtual-table-cell-fix-right-first', column.className, thClassName),
974
1264
  style: _extends({}, thStyle, {
975
1265
  left: isValidFixedLeft(column.fixed) ? stickySizes.get(key) : undefined,
976
1266
  right: isValidFixedRight(column.fixed) ? stickySizes.get(key) : undefined
@@ -996,7 +1286,7 @@ var TableHeader = function TableHeader(props) {
996
1286
  });
997
1287
  var tableNode = pipelineRender(jsxs("table", {
998
1288
  style: style,
999
- children: [jsx(Colgroup, {
1289
+ children: [jsx(Colgroup$1, {
1000
1290
  columns: descriptor
1001
1291
  }), theadNode]
1002
1292
  }), renderHeaderRoot, {
@@ -1019,35 +1309,7 @@ var TableHeader = function TableHeader(props) {
1019
1309
  });
1020
1310
  };
1021
1311
 
1022
- function onResize(target, callback) {
1023
- if (isWindow(target)) {
1024
- var listener = function listener() {
1025
- callback({
1026
- width: window.innerWidth,
1027
- height: window.innerHeight
1028
- });
1029
- };
1030
- listener();
1031
- window.addEventListener('resize', listener);
1032
- return function () {
1033
- window.removeEventListener('resize', listener);
1034
- };
1035
- } else {
1036
- var observer = new ResizeObserver(function (entries) {
1037
- var rect = entries[0].contentRect;
1038
- callback({
1039
- width: rect.width,
1040
- height: rect.height
1041
- });
1042
- });
1043
- observer.observe(target);
1044
- return function () {
1045
- observer.disconnect();
1046
- };
1047
- }
1048
- }
1049
-
1050
- function anchorQuery$1(rects, scrollLeft) {
1312
+ function anchorQuery(rects, scrollLeft) {
1051
1313
  var left = 0;
1052
1314
  var right = rects.length - 1;
1053
1315
  var index = -1;
@@ -1128,7 +1390,7 @@ function useColumnVirtualize(options) {
1128
1390
  right: estimateSize
1129
1391
  });
1130
1392
  var findAnchorRef = useStableFn(function (scrollLeft) {
1131
- return anchorQuery$1(rects, scrollLeft);
1393
+ return anchorQuery(rects, scrollLeft);
1132
1394
  });
1133
1395
  var updateBoundary = useStableFn(function (scrollLeft, count) {
1134
1396
  var anchor = findAnchorRef(scrollLeft);
@@ -1204,34 +1466,56 @@ function useColumnVirtualize(options) {
1204
1466
  });
1205
1467
  }, [disabled, rawColumns, startIndex, endIndex, lastFixedLeftIndex, firstFixedRightIndex]);
1206
1468
  var descriptor = useMemo(function () {
1207
- return columnSlice.reduce(function (result, column) {
1469
+ return columnSlice.reduce(function (result, column, index) {
1208
1470
  var key = getKey(column);
1209
1471
  if (key === leftKey) {
1210
1472
  result.push({
1211
- key: key,
1212
1473
  type: 'normal',
1474
+ key: key,
1213
1475
  column: column
1214
1476
  });
1215
1477
  result.push({
1478
+ type: 'blank',
1216
1479
  key: '_blank_left',
1480
+ width: leftBlank
1481
+ });
1482
+ } else if (leftKey == null && index === 0) {
1483
+ result.push({
1217
1484
  type: 'blank',
1485
+ key: '_blank_left',
1218
1486
  width: leftBlank
1219
1487
  });
1488
+ result.push({
1489
+ type: 'normal',
1490
+ key: key,
1491
+ column: column
1492
+ });
1220
1493
  } else if (key === rightKey) {
1221
1494
  result.push({
1222
- key: '_blank_right',
1223
1495
  type: 'blank',
1496
+ key: '_blank_right',
1224
1497
  width: rightBlank
1225
1498
  });
1226
1499
  result.push({
1500
+ type: 'normal',
1227
1501
  key: key,
1502
+ column: column
1503
+ });
1504
+ } else if (rightKey == null && index === columnSlice.length - 1) {
1505
+ result.push({
1228
1506
  type: 'normal',
1507
+ key: key,
1229
1508
  column: column
1230
1509
  });
1510
+ result.push({
1511
+ type: 'blank',
1512
+ key: '_blank_right',
1513
+ width: rightBlank
1514
+ });
1231
1515
  } else {
1232
1516
  result.push({
1233
- key: key,
1234
1517
  type: 'normal',
1518
+ key: key,
1235
1519
  column: column
1236
1520
  });
1237
1521
  }
@@ -1252,229 +1536,6 @@ function useColumnVirtualize(options) {
1252
1536
  };
1253
1537
  }
1254
1538
 
1255
- function useRowRectManager(options) {
1256
- var itemCount = options.itemCount,
1257
- estimateSize = options.estimateSize,
1258
- onChange = options.onChange;
1259
- var rowHeightList = useRef([]);
1260
- var calc = function calc() {
1261
- for (var i = 0; i < itemCount; i += 1) {
1262
- var target = rowHeightList.current[i];
1263
- if (target == null) {
1264
- rowHeightList.current[i] = estimateSize;
1265
- }
1266
- }
1267
- rowHeightList.current = rowHeightList.current.slice(0, itemCount);
1268
- };
1269
- // eslint-disable-next-line react-compiler/react-compiler
1270
- calc();
1271
- // const initialCount = useRef(itemCount)
1272
- // const [, forceUpdate] = useReducer((x) => !x, false)
1273
- // useLayoutEffect(() => {
1274
- // for (let i = 0; i < itemCount; i += 1) {
1275
- // const target = rowHeightList.current[i]
1276
- // if (target == null) {
1277
- // rowHeightList.current[i] = estimatedRowHeight
1278
- // }
1279
- // }
1280
- // // 数据量骤减时如果 row 数量不匹配则会导致容器高度错误
1281
- // rowHeightList.current = rowHeightList.current.slice(0, itemCount)
1282
- // // 这里的 useLayoutEffect 是为了在第一次渲染时,根据数据条数预先填充 row 的高度,这样内容足够高,容器才能滚动
1283
- // // 但是 dataSource 一般是异步获取的,第一次渲染时,length 是空的,所以无法进行填充,这样可能导致容器不能滚动
1284
- // // 所以 dataSource 有数据后,再填充一次,但是因为 useLayoutEffect 是渲染结束后才调用的,此时填充数据还是导致容器不能滚动,
1285
- // // 所以,只在第一次 dataSource 不为空时强制触发一次更新
1286
- // // 可能正因为这一次强制渲染,所以 VirtualTable 内部很多组件可能多次渲染。尝试优化为 calc 函数
1287
- // if (initialCount.current === 0 && itemCount > 0) {
1288
- // initialCount.current = itemCount
1289
- // forceUpdate()
1290
- // }
1291
- // }, [itemCount, estimatedRowHeight])
1292
- var rectList = useRef([]);
1293
- var updateRectList = function updateRectList() {
1294
- var result = [];
1295
- var top = 0;
1296
- rowHeightList.current.forEach(function (item, index) {
1297
- if (index !== 0) {
1298
- top += item;
1299
- }
1300
- result.push({
1301
- index: index,
1302
- height: item,
1303
- top: top,
1304
- bottom: top + item
1305
- });
1306
- });
1307
- rectList.current = result;
1308
- };
1309
- // DOM 渲染结束后,进行高度测量,再修改 rowHeightList
1310
- // 小心陷阱:当 table 父元素为 display: none 时,依然会触发 updateRowHeight 函数,并设置高度为 0
1311
- var updateRowHeight = useStableFn(function (index, height) {
1312
- rowHeightList.current[index] = height;
1313
- updateRectList();
1314
- onChange == null || onChange(index, height, rectList.current);
1315
- });
1316
- var sum = function sum(startIndex, endIndex) {
1317
- return rowHeightList.current.slice(startIndex, endIndex).reduce(function (a, b) {
1318
- return a + b;
1319
- }, 0);
1320
- };
1321
- return {
1322
- rowHeightList: rowHeightList,
1323
- updateRowHeight: updateRowHeight,
1324
- sum: sum,
1325
- rects: useCallback(function () {
1326
- return rectList.current;
1327
- }, [])
1328
- };
1329
- }
1330
-
1331
- function anchorQuery(rects, scrollTop) {
1332
- var left = 0;
1333
- var right = rects.length - 1;
1334
- var index = -1;
1335
- while (left <= right) {
1336
- var mid = Math.floor((left + right) / 2);
1337
- if (rects[mid].bottom > scrollTop) {
1338
- index = mid;
1339
- right = mid - 1;
1340
- } else {
1341
- left = mid + 1;
1342
- }
1343
- }
1344
- if (index === -1) {
1345
- return undefined;
1346
- }
1347
- return rects[index];
1348
- }
1349
- function useRowVirtualize(options) {
1350
- var getOffsetTop = options.getOffsetTop,
1351
- rawData = options.dataSource,
1352
- getScroller = options.getScroller,
1353
- estimateSize = options.estimateSize,
1354
- overscan = options.overscan;
1355
- var _useState = useState(0),
1356
- startIndex = _useState[0],
1357
- setStartIndex = _useState[1];
1358
- var _useState2 = useState(0),
1359
- endIndex = _useState2[0],
1360
- setEndIndex = _useState2[1];
1361
- // 锚点元素,当前虚拟列表中,最接近滚动容器顶部的元素
1362
- var anchorRef = useRef({
1363
- index: 0,
1364
- height: estimateSize,
1365
- top: 0,
1366
- bottom: estimateSize
1367
- });
1368
- var _useRowRectManager = useRowRectManager({
1369
- itemCount: rawData.length,
1370
- estimateSize: estimateSize,
1371
- onChange: function onChange(index, _height, rowRects) {
1372
- if (anchorRef.current.index === index) {
1373
- anchorRef.current = rowRects[index];
1374
- }
1375
- }
1376
- }),
1377
- rowHeightList = _useRowRectManager.rowHeightList,
1378
- rects = _useRowRectManager.rects,
1379
- updateRowHeight = _useRowRectManager.updateRowHeight,
1380
- sum = _useRowRectManager.sum;
1381
- // 用来判断滚动方向
1382
- var scrollTopRef = useRef(0);
1383
- var initial = useRef(false);
1384
- useEffect(function () {
1385
- var container = getScroller();
1386
- if (container == null) return;
1387
- var count = 0;
1388
- var getScrollTop = function getScrollTop() {
1389
- var offsetTop = getOffsetTop();
1390
- var result = 0;
1391
- if (isWindow(container) || isRoot(container)) {
1392
- result = window.scrollY;
1393
- } else {
1394
- var element = getScrollElement(container);
1395
- result = element.scrollTop;
1396
- }
1397
- return Math.max(result - offsetTop, 0);
1398
- };
1399
- var calcCount = function calcCount(scrollerContainerHeight) {
1400
- var prevCount = count;
1401
- count = Math.ceil(scrollerContainerHeight / estimateSize);
1402
- return {
1403
- prevCount: prevCount
1404
- };
1405
- };
1406
- var updateBoundary = function updateBoundary(scrollTop) {
1407
- var anchor = anchorQuery(rects(), scrollTop);
1408
- if (anchor != null) {
1409
- anchorRef.current = anchor;
1410
- setStartIndex(Math.max(0, anchor.index - overscan));
1411
- setEndIndex(anchor.index + count + overscan);
1412
- }
1413
- };
1414
- var onScroll = function onScroll(e) {
1415
- var offsetTop = getOffsetTop();
1416
- var scrollElement = getScrollElement(e.target);
1417
- var scrollTop = Math.max(0, scrollElement.scrollTop - offsetTop);
1418
- // 是否为向下滚动
1419
- var isScrollDown = scrollTop > scrollTopRef.current;
1420
- if (isScrollDown) {
1421
- // 如果滚动距离比较小,没有超出锚点元素的边界,就不需要计算 startIndex、endIndex 了
1422
- if (scrollTop > anchorRef.current.bottom) {
1423
- updateBoundary(scrollTop);
1424
- }
1425
- } else {
1426
- if (scrollTop < anchorRef.current.top) {
1427
- updateBoundary(scrollTop);
1428
- }
1429
- }
1430
- scrollTopRef.current = scrollTop;
1431
- };
1432
- var prevHeight = 0;
1433
- var stopListen = onResize(container, function (rect) {
1434
- // 处理父元素 display:none 容器高度丢失,导致显示 row 不准确
1435
- if (rect.height === prevHeight || rect.height === 0) {
1436
- return;
1437
- }
1438
- prevHeight = rect.height;
1439
- calcCount(rect.height);
1440
- var scrollTop = getScrollTop();
1441
- if (!initial.current) {
1442
- initial.current = true;
1443
- var nextStartIndex = 0;
1444
- // 判断一下当前滚动位置,计算 startIndex(场景:SPA 页面切换且渲染非异步数据)
1445
- if (scrollTop >= estimateSize) {
1446
- nextStartIndex = Math.max(Math.floor(scrollTop / estimateSize) - 1 - overscan, 0);
1447
- }
1448
- var nextEndIndex = nextStartIndex + count + overscan;
1449
- setStartIndex(nextStartIndex);
1450
- setEndIndex(nextEndIndex);
1451
- } else {
1452
- updateBoundary(scrollTop);
1453
- }
1454
- });
1455
- container.addEventListener('scroll', onScroll);
1456
- return function () {
1457
- stopListen();
1458
- container.removeEventListener('scroll', onScroll);
1459
- };
1460
- }, [estimateSize, getOffsetTop, getScroller, overscan, rects]);
1461
- // TODO: React Compiler 测试 topBlank 和 bottomBlank
1462
- var topBlank = sum(0, startIndex);
1463
- var bottomBlank = sum(endIndex);
1464
- var dataSlice = useMemo(function () {
1465
- return rawData.slice(startIndex, endIndex);
1466
- }, [rawData, startIndex, endIndex]);
1467
- return {
1468
- startIndex: startIndex,
1469
- endIndex: endIndex,
1470
- rowHeightList: rowHeightList,
1471
- updateRowHeight: updateRowHeight,
1472
- topBlank: topBlank,
1473
- bottomBlank: bottomBlank,
1474
- dataSlice: dataSlice
1475
- };
1476
- }
1477
-
1478
1539
  function TableRoot(props, ref) {
1479
1540
  var className = props.className,
1480
1541
  style = props.style,
@@ -1549,7 +1610,7 @@ function VirtualTableCore(props, ref) {
1549
1610
  onRow = props.onRow,
1550
1611
  getOffsetTopImpl = props.getOffsetTop,
1551
1612
  _props$virtualHeader = props.virtualHeader,
1552
- virtualHeader = _props$virtualHeader === undefined ? false : _props$virtualHeader;
1613
+ virtualHeader = _props$virtualHeader === undefined ? true : _props$virtualHeader;
1553
1614
  var rootNode = useRef(null);
1554
1615
  var headerWrapperRef = useRef(null);
1555
1616
  var bodyWrapperRef = useRef(null);
@@ -1614,29 +1675,16 @@ function VirtualTableCore(props, ref) {
1614
1675
  columnWidths = _useState[0],
1615
1676
  setColumnWidths = _useState[1];
1616
1677
  var columnWidthsRef = useRef(columnWidths);
1617
- var updateColumnWidths = function updateColumnWidths(value) {
1678
+ var updateColumnWidths = useCallback(function (value) {
1618
1679
  columnWidthsRef.current = value;
1619
1680
  setColumnWidths(value);
1620
- };
1681
+ }, []);
1621
1682
  var tableColumnsContext = useMemo(function () {
1622
1683
  return {
1623
1684
  widthList: columnWidths,
1624
1685
  setWidthList: updateColumnWidths
1625
1686
  };
1626
- }, [columnWidths]);
1627
- var _useRowVirtualize = useRowVirtualize({
1628
- getOffsetTop: getOffsetTop,
1629
- dataSource: dataSource,
1630
- getScroller: getScroller,
1631
- estimateSize: estimatedRowHeight,
1632
- overscan: overscanRows
1633
- }),
1634
- startIndex = _useRowVirtualize.startIndex,
1635
- dataSlice = _useRowVirtualize.dataSlice,
1636
- updateRowHeight = _useRowVirtualize.updateRowHeight,
1637
- rowHeightList = _useRowVirtualize.rowHeightList,
1638
- topBlank = _useRowVirtualize.topBlank,
1639
- bottomBlank = _useRowVirtualize.bottomBlank;
1687
+ }, [columnWidths, updateColumnWidths]);
1640
1688
  var _useColumnVirtualize = useColumnVirtualize({
1641
1689
  estimateSize: estimatedColumnWidth != null ? estimatedColumnWidth : 100,
1642
1690
  overscan: overscanColumns,
@@ -1669,14 +1717,6 @@ function VirtualTableCore(props, ref) {
1669
1717
  var hasFixedRightColumn = pipelineColumns.some(function (x) {
1670
1718
  return isValidFixedRight(x.fixed);
1671
1719
  });
1672
- var rowManager = useMemo(function () {
1673
- return {
1674
- getRowHeightList: function getRowHeightList() {
1675
- return rowHeightList.current;
1676
- },
1677
- updateRowHeight: updateRowHeight
1678
- };
1679
- }, [rowHeightList, updateRowHeight]);
1680
1720
  var fullHeaderColumns = useMemo(function () {
1681
1721
  return {
1682
1722
  columns: pipelineColumns,
@@ -1711,14 +1751,14 @@ function VirtualTableCore(props, ref) {
1711
1751
  bodyRootRef: mergedBodyRootRef,
1712
1752
  bodyRef: bodyRef,
1713
1753
  className: tableBodyClassName,
1714
- style: _extends({}, tableBodyStyle, {
1715
- paddingBottom: bottomBlank,
1716
- paddingTop: topBlank
1717
- }),
1754
+ style: tableBodyStyle,
1718
1755
  columns: columns,
1719
1756
  rowKey: rowKey,
1720
- dataSource: dataSlice,
1721
- startIndex: startIndex,
1757
+ dataSource: dataSource,
1758
+ overscan: overscanRows,
1759
+ estimateSize: estimatedRowHeight,
1760
+ getScroller: getScroller,
1761
+ getOffsetTop: getOffsetTop,
1722
1762
  rowClassName: onRowClassName,
1723
1763
  onRow: onRowProps,
1724
1764
  renderBodyWrapper: renderBodyWrapper,
@@ -1745,18 +1785,15 @@ function VirtualTableCore(props, ref) {
1745
1785
  columns: columns.columns,
1746
1786
  columnDescriptor: columns.descriptor
1747
1787
  });
1748
- return jsx(TableRowManager.Provider, {
1749
- value: rowManager,
1750
- children: jsx(ColumnSizes.Provider, {
1751
- value: tableColumnsContext,
1752
- children: jsx(StickyContext, {
1753
- columns: pipelineColumns,
1754
- children: jsx(ContainerSizeContext, {
1755
- getScroller: getScroller,
1756
- root: rootNode,
1757
- children: jsx(HorizontalScrollContext, {
1758
- children: table
1759
- })
1788
+ return jsx(ColumnSizes.Provider, {
1789
+ value: tableColumnsContext,
1790
+ children: jsx(StickyContext, {
1791
+ columns: pipelineColumns,
1792
+ children: jsx(ContainerSizeContext, {
1793
+ getScroller: getScroller,
1794
+ root: rootNode,
1795
+ children: jsx(HorizontalScrollContext, {
1796
+ children: table
1760
1797
  })
1761
1798
  })
1762
1799
  })
@@ -1767,5 +1804,5 @@ if (process.env.NODE_ENV === 'development') {
1767
1804
  }
1768
1805
  var table = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(VirtualTableCore));
1769
1806
 
1770
- export { Colgroup, table as VirtualTable, Cell$1 as VirtualTableCell, Row$1 as VirtualTableRow, createMiddleware, findLastIndex, getKey, isValidFixed, isValidFixedLeft, isValidFixedRight, mergeRefs, onResize, useColumnSizes, useContainerSize, useHorizontalScrollContext, useMergedRef, useShallowMemo, useStableFn, useTablePipeline, useTableRowManager, useTableSticky };
1807
+ export { Colgroup$1 as Colgroup, table as VirtualTable, Cell$1 as VirtualTableCell, Row$1 as VirtualTableRow, createMiddleware, findLastIndex, getKey, isValidFixed, isValidFixedLeft, isValidFixedRight, mergeRefs, onResize, useColumnSizes, useContainerSize, useHorizontalScrollContext, useMergedRef, useShallowMemo, useStableFn, useTablePipeline, useTableRowManager, useTableSticky };
1771
1808
  //# sourceMappingURL=index.esm.js.map