beautiful-grid 1.0.1 → 1.0.3
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/README.md +1 -1
- package/cjs/components/Table.js +114 -107
- package/cjs/components/selection/CellSelectionOverlayLayer.js +5 -5
- package/cjs/utils/coordinate.js +10 -10
- package/cjs/utils/index.js +1 -0
- package/cjs/utils/virtualScrollWindow.js +67 -0
- package/esm/components/Table.js +113 -107
- package/esm/components/selection/CellSelectionOverlayLayer.js +5 -5
- package/esm/utils/coordinate.js +4 -4
- package/esm/utils/index.js +1 -0
- package/esm/utils/virtualScrollWindow.js +59 -0
- package/package.json +1 -1
- package/types/components/selection/CellSelectionOverlay.d.ts +1 -0
- package/types/components/selection/CellSelectionOverlayLayer.d.ts +2 -1
- package/types/utils/coordinate.d.ts +5 -1
- package/types/utils/index.d.ts +1 -0
- package/types/utils/virtualScrollWindow.d.ts +24 -0
package/esm/components/Table.js
CHANGED
|
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useRef } from 'react';
|
|
|
3
3
|
import { useShallow } from 'zustand/react/shallow';
|
|
4
4
|
import { useAppStore } from '../store';
|
|
5
5
|
import { BGridDataItemStatus, } from '../types';
|
|
6
|
-
import { getCellValueByRowKey, getFrozenColumnsWidth, getVisibleScrollableRowRange, isCheckboxValueChecked, markCellEdited, markCellValueChanged, resolveLogicalCell, shouldRenderBottomBar, } from '../utils';
|
|
6
|
+
import { getCellValueByRowKey, getFrozenColumnsWidth, getVisibleScrollableRowRange, getVirtualScrollWindowMetrics, getVirtualScrollWindowPosition, isCheckboxValueChecked, markCellEdited, markCellValueChanged, rebaseVirtualScrollWindow, resolveLogicalCell, shouldRenderBottomBar, } from '../utils';
|
|
7
7
|
import { clamp, ensureCellVisible } from '../utils/coordinate';
|
|
8
8
|
import Loading from './Loading';
|
|
9
9
|
import TableBody from './TableBody';
|
|
@@ -183,6 +183,23 @@ function Table(props) {
|
|
|
183
183
|
const trHeight = itemHeight + itemPadding * 2;
|
|
184
184
|
const scrollableBodyHeight = Math.max(contentBodyHeight - frozenRowsHeight, 0);
|
|
185
185
|
const mainViewportWidth = Math.max(width - (frozenColumnsWidth ?? 0), 0);
|
|
186
|
+
const logicalBodyContentHeight = data.length * trHeight;
|
|
187
|
+
const virtualScrollWindowMetrics = React.useMemo(() => getVirtualScrollWindowMetrics({
|
|
188
|
+
logicalContentHeight: logicalBodyContentHeight,
|
|
189
|
+
viewportHeight: contentBodyHeight,
|
|
190
|
+
enabled: scrollbar.variant !== 'native',
|
|
191
|
+
}), [contentBodyHeight, logicalBodyContentHeight, scrollbar.variant]);
|
|
192
|
+
const [virtualScrollBase, setVirtualScrollBase] = React.useState(0);
|
|
193
|
+
const virtualScrollBaseRef = useRef(0);
|
|
194
|
+
const containerRef = useRef(null);
|
|
195
|
+
const searchPopoverRef = useRef(null);
|
|
196
|
+
const editorPortalRef = useRef(null);
|
|
197
|
+
const bodyContainerRef = useRef(null);
|
|
198
|
+
const scrollContainerRef = useRef(null);
|
|
199
|
+
const logicalVerticalScrollState = React.useMemo(() => ({
|
|
200
|
+
scrollTop,
|
|
201
|
+
scrollHeight: virtualScrollWindowMetrics.logicalContentHeight,
|
|
202
|
+
}), [scrollTop, virtualScrollWindowMetrics.logicalContentHeight]);
|
|
186
203
|
const hasMultiCellSelection = React.useMemo(() => cellSelectionRanges.length > 1 ||
|
|
187
204
|
cellSelectionRanges.some(range => {
|
|
188
205
|
const normalized = normalizeCellSelectionRange(range);
|
|
@@ -273,7 +290,7 @@ function Table(props) {
|
|
|
273
290
|
top: topQuadrant ? 0 : scrollTop,
|
|
274
291
|
width: leftQuadrant ? frozenColumnsWidth ?? 0 : mainViewportWidth,
|
|
275
292
|
height: topQuadrant ? frozenRowsHeight : scrollableBodyHeight,
|
|
276
|
-
} }));
|
|
293
|
+
}, offsetTop: !topQuadrant && virtualScrollWindowMetrics.enabled ? virtualScrollBase : 0 }));
|
|
277
294
|
};
|
|
278
295
|
const visibleScrollableRows = React.useMemo(() => getVisibleScrollableRowRange({
|
|
279
296
|
scrollTop,
|
|
@@ -288,15 +305,14 @@ function Table(props) {
|
|
|
288
305
|
startRowIndex: visibleScrollableRows.startRowIndex,
|
|
289
306
|
endRowIndex: visibleScrollableRows.endRowIndex,
|
|
290
307
|
}), [visibleScrollableRows.endRowIndex, visibleScrollableRows.startRowIndex]);
|
|
291
|
-
const frozenScrollableBodyStyle = React.useMemo(() => ({
|
|
292
|
-
|
|
293
|
-
|
|
308
|
+
const frozenScrollableBodyStyle = React.useMemo(() => ({
|
|
309
|
+
top: virtualScrollWindowMetrics.enabled
|
|
310
|
+
? visibleScrollableRows.paddingTop - virtualScrollBase
|
|
311
|
+
: visibleScrollableRows.paddingTop,
|
|
312
|
+
}), [virtualScrollBase, virtualScrollWindowMetrics.enabled, visibleScrollableRows.paddingTop]);
|
|
294
313
|
const warnedContextMenuIdsRef = useRef(new Set());
|
|
295
314
|
const warnedContextMenuFactoryRef = useRef(false);
|
|
296
|
-
const editorPortalRef = useRef(null);
|
|
297
315
|
const editorPortalContext = React.useMemo(() => ({ gridRef: containerRef, portalRef: editorPortalRef }), []);
|
|
298
|
-
const bodyContainerRef = useRef(null);
|
|
299
|
-
const scrollContainerRef = useRef(null);
|
|
300
316
|
const rowReorderController = useRowReorderController({
|
|
301
317
|
containerRef,
|
|
302
318
|
bodyContainerRef,
|
|
@@ -404,7 +420,8 @@ function Table(props) {
|
|
|
404
420
|
const stickyBottomHeight = summary?.position === 'bottom' ? summaryHeight : 0;
|
|
405
421
|
const stickyFixedHeight = stickyTopHeight + stickyBottomHeight;
|
|
406
422
|
const scrollViewportHeight = contentBodyHeight + stickyFixedHeight;
|
|
407
|
-
const
|
|
423
|
+
const physicalScrollableRowsHeight = Math.max(virtualScrollWindowMetrics.physicalContentHeight - frozenRowsHeight, 0);
|
|
424
|
+
const scrollPlaneHeight = stickyFixedHeight + virtualScrollWindowMetrics.physicalContentHeight;
|
|
408
425
|
const scrollPlaneContentWidth = (frozenColumnsWidth ?? 0) + scrollableColumnsWidth;
|
|
409
426
|
const scrollPlaneWidth = Math.max(width, scrollPlaneContentWidth);
|
|
410
427
|
const customVerticalScrollbarGutter = scrollbar.vertical.visible && scrollbar.variant === 'classic'
|
|
@@ -415,7 +432,18 @@ function Table(props) {
|
|
|
415
432
|
const scrollPlaneMinWidth = customVerticalScrollbarGutter
|
|
416
433
|
? `max(100%, calc(${scrollPlaneContentWidth}px + ${customVerticalScrollbarGutter}))`
|
|
417
434
|
: scrollPlaneWidth;
|
|
418
|
-
const
|
|
435
|
+
const measuredScrollbarMetrics = useScrollbarMetrics(scrollContainerRef, [data.length, itemHeight, itemPadding, contentBodyHeight, width], scrollPlaneContentWidth, stickyFixedHeight);
|
|
436
|
+
const scrollbarMetrics = React.useMemo(() => virtualScrollWindowMetrics.enabled
|
|
437
|
+
? {
|
|
438
|
+
...measuredScrollbarMetrics,
|
|
439
|
+
vertical: {
|
|
440
|
+
viewportSize: contentBodyHeight,
|
|
441
|
+
contentSize: virtualScrollWindowMetrics.logicalContentHeight,
|
|
442
|
+
maxScroll: virtualScrollWindowMetrics.logicalMaxScroll,
|
|
443
|
+
hasOverflow: virtualScrollWindowMetrics.logicalMaxScroll > 1,
|
|
444
|
+
},
|
|
445
|
+
}
|
|
446
|
+
: measuredScrollbarMetrics, [contentBodyHeight, measuredScrollbarMetrics, virtualScrollWindowMetrics]);
|
|
419
447
|
const measuredVerticalScrollbarGutter = customVerticalScrollbarGutter && scrollbarMetrics.horizontal.hasOverflow
|
|
420
448
|
? Math.max(scrollbarMetrics.horizontal.contentSize - scrollPlaneContentWidth, 0)
|
|
421
449
|
: 0;
|
|
@@ -435,11 +463,6 @@ function Table(props) {
|
|
|
435
463
|
scrollContainerRef.current.scrollLeft = offset;
|
|
436
464
|
}
|
|
437
465
|
}, []);
|
|
438
|
-
const handleScrollTopChange = useCallback((offset) => {
|
|
439
|
-
if (scrollContainerRef.current) {
|
|
440
|
-
scrollContainerRef.current.scrollTop = offset;
|
|
441
|
-
}
|
|
442
|
-
}, []);
|
|
443
466
|
const latestScrollRef = useRef({ top: scrollTop, left: scrollLeft });
|
|
444
467
|
const latestCommittedScrollRef = useRef({ top: scrollTop, left: scrollLeft });
|
|
445
468
|
const scrollRafRef = useRef(null);
|
|
@@ -456,6 +479,7 @@ function Table(props) {
|
|
|
456
479
|
frozenRowCount,
|
|
457
480
|
frozenColumnsWidth: frozenColumnsWidth ?? 0,
|
|
458
481
|
frozenRowsHeight,
|
|
482
|
+
scrollTop,
|
|
459
483
|
trHeight,
|
|
460
484
|
});
|
|
461
485
|
useEffect(() => {
|
|
@@ -466,9 +490,10 @@ function Table(props) {
|
|
|
466
490
|
frozenRowCount,
|
|
467
491
|
frozenColumnsWidth: frozenColumnsWidth ?? 0,
|
|
468
492
|
frozenRowsHeight,
|
|
493
|
+
scrollTop,
|
|
469
494
|
trHeight,
|
|
470
495
|
};
|
|
471
|
-
}, [columns, data.length, props.frozenColumnIndex, frozenColumnsWidth, frozenRowCount, frozenRowsHeight, trHeight]);
|
|
496
|
+
}, [columns, data.length, props.frozenColumnIndex, frozenColumnsWidth, frozenRowCount, frozenRowsHeight, scrollTop, trHeight]);
|
|
472
497
|
const markScrollActive = useCallback(() => {
|
|
473
498
|
containerRef.current?.setAttribute('data-bgrid-scrolling', 'true');
|
|
474
499
|
if (scrollIdleTimerRef.current !== null)
|
|
@@ -478,6 +503,27 @@ function Table(props) {
|
|
|
478
503
|
containerRef.current?.removeAttribute('data-bgrid-scrolling');
|
|
479
504
|
}, SCROLL_IDLE_DELAY);
|
|
480
505
|
}, []);
|
|
506
|
+
const commitScroll = useCallback((top, left) => {
|
|
507
|
+
const scrollContainer = scrollContainerRef.current;
|
|
508
|
+
if (!scrollContainer)
|
|
509
|
+
return;
|
|
510
|
+
const position = getVirtualScrollWindowPosition(top, virtualScrollWindowMetrics);
|
|
511
|
+
if (virtualScrollBaseRef.current !== position.base) {
|
|
512
|
+
virtualScrollBaseRef.current = position.base;
|
|
513
|
+
setVirtualScrollBase(position.base);
|
|
514
|
+
}
|
|
515
|
+
if (scrollContainer.scrollTop !== position.physicalScrollTop) {
|
|
516
|
+
scrollContainer.scrollTop = position.physicalScrollTop;
|
|
517
|
+
}
|
|
518
|
+
if (scrollContainer.scrollLeft !== left)
|
|
519
|
+
scrollContainer.scrollLeft = left;
|
|
520
|
+
latestScrollRef.current = { top: position.logicalScrollTop, left };
|
|
521
|
+
latestCommittedScrollRef.current = { top: position.logicalScrollTop, left };
|
|
522
|
+
setScroll(position.logicalScrollTop, left);
|
|
523
|
+
}, [setScroll, virtualScrollWindowMetrics]);
|
|
524
|
+
const handleScrollTopChange = useCallback((offset) => {
|
|
525
|
+
commitScroll(offset, scrollContainerRef.current?.scrollLeft ?? scrollLeft);
|
|
526
|
+
}, [commitScroll, scrollLeft]);
|
|
481
527
|
const scheduleScrollFrame = useCallback(() => {
|
|
482
528
|
if (scrollRafRef.current !== null)
|
|
483
529
|
return;
|
|
@@ -486,90 +532,42 @@ function Table(props) {
|
|
|
486
532
|
const scrollContainer = scrollContainerRef.current;
|
|
487
533
|
if (!scrollContainer)
|
|
488
534
|
return;
|
|
489
|
-
const { scrollTop, scrollLeft } = scrollContainer;
|
|
490
|
-
|
|
535
|
+
const { scrollTop: physicalScrollTop, scrollLeft } = scrollContainer;
|
|
536
|
+
const position = rebaseVirtualScrollWindow(virtualScrollBaseRef.current, physicalScrollTop, virtualScrollWindowMetrics);
|
|
537
|
+
if (virtualScrollBaseRef.current !== position.base) {
|
|
538
|
+
virtualScrollBaseRef.current = position.base;
|
|
539
|
+
setVirtualScrollBase(position.base);
|
|
540
|
+
}
|
|
541
|
+
if (physicalScrollTop !== position.physicalScrollTop) {
|
|
542
|
+
scrollContainer.scrollTop = position.physicalScrollTop;
|
|
543
|
+
}
|
|
544
|
+
const logicalScrollTop = position.logicalScrollTop;
|
|
545
|
+
latestScrollRef.current = { top: logicalScrollTop, left: scrollLeft };
|
|
491
546
|
const { top: committedTop, left: committedLeft } = latestCommittedScrollRef.current;
|
|
492
|
-
if (committedTop !==
|
|
493
|
-
latestCommittedScrollRef.current = { top:
|
|
494
|
-
setScroll(
|
|
547
|
+
if (committedTop !== logicalScrollTop || committedLeft !== scrollLeft) {
|
|
548
|
+
latestCommittedScrollRef.current = { top: logicalScrollTop, left: scrollLeft };
|
|
549
|
+
setScroll(logicalScrollTop, scrollLeft);
|
|
495
550
|
}
|
|
496
551
|
if (containerRef.current?.hasAttribute('data-bgrid-scrolling')) {
|
|
497
552
|
scrollRafRef.current = requestAnimationFrame(pollNativeScrollPosition);
|
|
498
553
|
}
|
|
499
554
|
};
|
|
500
555
|
scrollRafRef.current = requestAnimationFrame(pollNativeScrollPosition);
|
|
501
|
-
}, [setScroll]);
|
|
556
|
+
}, [setScroll, virtualScrollWindowMetrics]);
|
|
502
557
|
const onScroll = useCallback(() => {
|
|
503
558
|
if (scrollContainerRef.current) {
|
|
504
|
-
const { scrollTop, scrollLeft } = scrollContainerRef.current;
|
|
505
|
-
latestScrollRef.current = { top: scrollTop, left: scrollLeft };
|
|
506
559
|
markScrollActive();
|
|
507
560
|
scheduleScrollFrame();
|
|
508
561
|
}
|
|
509
562
|
}, [markScrollActive, scheduleScrollFrame]);
|
|
510
|
-
const onWheel = useCallback(evt => {
|
|
511
|
-
const scrollContainer = scrollContainerRef.current;
|
|
512
|
-
if (!scrollContainer)
|
|
513
|
-
return;
|
|
514
|
-
const delta = { x: 0, y: 0 };
|
|
515
|
-
if (evt.detail) {
|
|
516
|
-
delta.y = evt.detail * 10;
|
|
517
|
-
}
|
|
518
|
-
else if (typeof evt.deltaY === 'undefined') {
|
|
519
|
-
delta.y = -evt.wheelDelta;
|
|
520
|
-
delta.x = 0;
|
|
521
|
-
}
|
|
522
|
-
else {
|
|
523
|
-
delta.y = evt.deltaY;
|
|
524
|
-
delta.x = evt.deltaX;
|
|
525
|
-
}
|
|
526
|
-
if (evt.deltaMode === 1) {
|
|
527
|
-
delta.y = delta.y * 16;
|
|
528
|
-
delta.x = delta.x * 16;
|
|
529
|
-
}
|
|
530
|
-
else if (evt.deltaMode === 2) {
|
|
531
|
-
delta.y = delta.y * scrollContainer.clientHeight;
|
|
532
|
-
delta.x = delta.x * scrollContainer.clientWidth;
|
|
533
|
-
}
|
|
534
|
-
const maxScrollTop = Math.max(scrollContainer.scrollHeight - scrollContainer.clientHeight, 0);
|
|
535
|
-
const maxScrollLeft = Math.max(scrollContainer.scrollWidth - scrollContainer.clientWidth, 0);
|
|
536
|
-
const nextScrollTop = Math.min(maxScrollTop, Math.max(0, scrollContainer.scrollTop + delta.y));
|
|
537
|
-
const nextScrollLeft = Math.min(maxScrollLeft, Math.max(0, scrollContainer.scrollLeft + delta.x));
|
|
538
|
-
const didScrollTop = nextScrollTop !== scrollContainer.scrollTop;
|
|
539
|
-
const didScrollLeft = nextScrollLeft !== scrollContainer.scrollLeft;
|
|
540
|
-
const isVertical = Math.abs(delta.y) > Math.abs(delta.x);
|
|
541
|
-
if (isVertical) {
|
|
542
|
-
if (!didScrollTop)
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
546
|
-
if (!didScrollLeft)
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
evt.preventDefault();
|
|
550
|
-
if (didScrollTop)
|
|
551
|
-
scrollContainer.scrollTop = nextScrollTop;
|
|
552
|
-
if (didScrollLeft)
|
|
553
|
-
scrollContainer.scrollLeft = nextScrollLeft;
|
|
554
|
-
}, []);
|
|
555
563
|
const resetScrollPosition = useCallback((type) => {
|
|
556
|
-
if (type === 'all' || type === 'left')
|
|
557
|
-
scrollContainerRef.current?.scrollTo({ left: 0 });
|
|
558
|
-
if (type === 'all' || type === 'top')
|
|
559
|
-
scrollContainerRef.current?.scrollTo({ top: 0 });
|
|
560
|
-
}, []);
|
|
561
|
-
const commitScroll = useCallback((top, left) => {
|
|
562
564
|
const scrollContainer = scrollContainerRef.current;
|
|
563
565
|
if (!scrollContainer)
|
|
564
566
|
return;
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
latestScrollRef.current = { top, left };
|
|
570
|
-
latestCommittedScrollRef.current = { top, left };
|
|
571
|
-
setScroll(top, left);
|
|
572
|
-
}, [setScroll]);
|
|
567
|
+
const nextTop = type === 'all' || type === 'top' ? 0 : latestScrollRef.current.top;
|
|
568
|
+
const nextLeft = type === 'all' || type === 'left' ? 0 : scrollContainer.scrollLeft;
|
|
569
|
+
commitScroll(nextTop, nextLeft);
|
|
570
|
+
}, [commitScroll]);
|
|
573
571
|
useEffect(() => {
|
|
574
572
|
if (!searchOpen || activeSearchMatchIndex === undefined)
|
|
575
573
|
return;
|
|
@@ -593,6 +591,7 @@ function Table(props) {
|
|
|
593
591
|
frozenRowCount,
|
|
594
592
|
columns,
|
|
595
593
|
rowHeight: trHeight,
|
|
594
|
+
verticalScrollState: logicalVerticalScrollState,
|
|
596
595
|
viewportInsets,
|
|
597
596
|
});
|
|
598
597
|
if (result.didScroll)
|
|
@@ -602,6 +601,7 @@ function Table(props) {
|
|
|
602
601
|
columns,
|
|
603
602
|
commitScroll,
|
|
604
603
|
frozenRowCount,
|
|
604
|
+
logicalVerticalScrollState,
|
|
605
605
|
props.frozenColumnIndex,
|
|
606
606
|
searchMatches,
|
|
607
607
|
searchOpen,
|
|
@@ -833,18 +833,18 @@ function Table(props) {
|
|
|
833
833
|
if (!dragState || !pointer || !scrollContainer || !bodyContainer)
|
|
834
834
|
return;
|
|
835
835
|
const delta = getSelectionAutoScrollDelta(pointer.clientX, pointer.clientY, bodyContainer, scrollContainer);
|
|
836
|
-
const maxScrollTop =
|
|
836
|
+
const maxScrollTop = virtualScrollWindowMetrics.logicalMaxScroll;
|
|
837
837
|
const maxScrollLeft = Math.max(scrollContainer.scrollWidth - scrollContainer.clientWidth, 0);
|
|
838
|
-
const nextScrollTop = clamp(
|
|
838
|
+
const nextScrollTop = clamp(latestScrollRef.current.top + delta.y, 0, maxScrollTop);
|
|
839
839
|
const nextScrollLeft = clamp(scrollContainer.scrollLeft + delta.x, 0, maxScrollLeft);
|
|
840
|
-
if (nextScrollTop !==
|
|
840
|
+
if (nextScrollTop !== latestScrollRef.current.top || nextScrollLeft !== scrollContainer.scrollLeft) {
|
|
841
841
|
commitScroll(nextScrollTop, nextScrollLeft);
|
|
842
842
|
}
|
|
843
843
|
updateSelectionByPointer(pointer.clientX, pointer.clientY);
|
|
844
844
|
if (cellSelectionDragRef.current && (delta.x !== 0 || delta.y !== 0)) {
|
|
845
845
|
selectionAutoScrollRafRef.current = requestAnimationFrame(runSelectionAutoScroll);
|
|
846
846
|
}
|
|
847
|
-
}, [commitScroll, updateSelectionByPointer]);
|
|
847
|
+
}, [commitScroll, updateSelectionByPointer, virtualScrollWindowMetrics.logicalMaxScroll]);
|
|
848
848
|
const selectAllCells = useCallback(() => {
|
|
849
849
|
if (!cellSelectionEnabled)
|
|
850
850
|
return false;
|
|
@@ -1065,7 +1065,9 @@ function Table(props) {
|
|
|
1065
1065
|
clipboardRow.forEach((clipboardValue, columnOffset) => {
|
|
1066
1066
|
const columnIndex = startColumnIndex + columnOffset;
|
|
1067
1067
|
const column = columns[columnIndex];
|
|
1068
|
-
|
|
1068
|
+
// Pasting mutates row data without opening an editor, so only columns
|
|
1069
|
+
// explicitly opted into editing may receive clipboard values.
|
|
1070
|
+
if (!column || column.editable !== true)
|
|
1069
1071
|
return;
|
|
1070
1072
|
const logicalCell = resolveLogicalCell(logicalResolutionData, props.cellMergeOptions, {
|
|
1071
1073
|
rowIndex,
|
|
@@ -1497,8 +1499,6 @@ function Table(props) {
|
|
|
1497
1499
|
if (scrollContainerRefCurrent) {
|
|
1498
1500
|
scrollContainerRefCurrent.removeEventListener('scroll', onScroll);
|
|
1499
1501
|
scrollContainerRefCurrent.addEventListener('scroll', onScroll, { passive: true, capture: true });
|
|
1500
|
-
// scrollContainerRefCurrent.removeEventListener('wheel', onWheel);
|
|
1501
|
-
// scrollContainerRefCurrent.addEventListener('wheel', onWheel, { passive: false, capture: true });
|
|
1502
1502
|
}
|
|
1503
1503
|
return () => {
|
|
1504
1504
|
if (scrollRafRef.current !== null) {
|
|
@@ -1512,18 +1512,16 @@ function Table(props) {
|
|
|
1512
1512
|
containerRefCurrent?.removeAttribute('data-bgrid-scrolling');
|
|
1513
1513
|
scrollContainerRefCurrent?.removeEventListener('scroll', onScroll);
|
|
1514
1514
|
};
|
|
1515
|
-
}, [onScroll,
|
|
1515
|
+
}, [onScroll, setInitialized]);
|
|
1516
1516
|
React.useLayoutEffect(() => {
|
|
1517
1517
|
if (!scrollContainerRef.current)
|
|
1518
1518
|
return;
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
scrollContainerRef.current.scrollTop = props.scrollTop;
|
|
1524
|
-
}
|
|
1525
|
-
}, [props.scrollLeft, props.scrollTop]);
|
|
1519
|
+
const nextTop = props.scrollTop ?? latestScrollRef.current.top;
|
|
1520
|
+
const nextLeft = props.scrollLeft ?? latestScrollRef.current.left;
|
|
1521
|
+
commitScroll(nextTop, nextLeft);
|
|
1522
|
+
}, [commitScroll, props.scrollLeft, props.scrollTop]);
|
|
1526
1523
|
useEffect(() => {
|
|
1524
|
+
latestScrollRef.current = { top: scrollTop, left: scrollLeft };
|
|
1527
1525
|
latestCommittedScrollRef.current = { top: scrollTop, left: scrollLeft };
|
|
1528
1526
|
}, [scrollTop, scrollLeft]);
|
|
1529
1527
|
useEffect(() => {
|
|
@@ -1604,6 +1602,7 @@ function Table(props) {
|
|
|
1604
1602
|
searchOpen,
|
|
1605
1603
|
searchOptions,
|
|
1606
1604
|
trHeight,
|
|
1605
|
+
verticalScrollState: logicalVerticalScrollState,
|
|
1607
1606
|
viewportInsets: keyboardViewportInsets,
|
|
1608
1607
|
});
|
|
1609
1608
|
keyboardRuntimeRef.current = {
|
|
@@ -1636,6 +1635,7 @@ function Table(props) {
|
|
|
1636
1635
|
searchOpen,
|
|
1637
1636
|
searchOptions,
|
|
1638
1637
|
trHeight,
|
|
1638
|
+
verticalScrollState: logicalVerticalScrollState,
|
|
1639
1639
|
viewportInsets: keyboardViewportInsets,
|
|
1640
1640
|
};
|
|
1641
1641
|
useEffect(() => {
|
|
@@ -1651,7 +1651,7 @@ function Table(props) {
|
|
|
1651
1651
|
}
|
|
1652
1652
|
};
|
|
1653
1653
|
const moveWithArrowKey = (key, extendSelection, toBoundary = false) => {
|
|
1654
|
-
const { activeCell, cellInteractionSession, cellNavigationOptions, cellSelectionEnabled, columns, commitScroll, dataLength, frozenColumnIndex, frozenRowCount, moveActiveCell, trHeight, viewportInsets, } = keyboardRuntimeRef.current;
|
|
1654
|
+
const { activeCell, cellInteractionSession, cellNavigationOptions, cellSelectionEnabled, columns, commitScroll, dataLength, frozenColumnIndex, frozenRowCount, moveActiveCell, trHeight, verticalScrollState, viewportInsets, } = keyboardRuntimeRef.current;
|
|
1655
1655
|
const container = containerRef.current;
|
|
1656
1656
|
const activeElement = document.activeElement;
|
|
1657
1657
|
if (!container ||
|
|
@@ -1685,6 +1685,7 @@ function Table(props) {
|
|
|
1685
1685
|
frozenRowCount,
|
|
1686
1686
|
columns,
|
|
1687
1687
|
rowHeight: trHeight,
|
|
1688
|
+
verticalScrollState,
|
|
1688
1689
|
viewportInsets,
|
|
1689
1690
|
});
|
|
1690
1691
|
if (result.didScroll) {
|
|
@@ -1716,7 +1717,7 @@ function Table(props) {
|
|
|
1716
1717
|
arrowRepeatFrame = requestAnimationFrame(runArrowRepeatFrame);
|
|
1717
1718
|
};
|
|
1718
1719
|
const handleKeyDown = (evt) => {
|
|
1719
|
-
const { activeCell, cellInteractionSession, cellNavigationOptions, cellSelectionEnabled, clearCellSelection, clearCellSelectionOnEscape, columns, commitCheckboxCell, commitScroll, copySelectedCells, data, dataLength, editable, editItemIndex, endCellSelectionDrag, frozenColumnIndex, frozenRowCount, height, handleClick, moveActiveCell, openCellContextMenu, selectAllCells, setEditItem, requestSearchOpen, searchOpen, searchOptions, trHeight, viewportInsets, } = keyboardRuntimeRef.current;
|
|
1720
|
+
const { activeCell, cellInteractionSession, cellNavigationOptions, cellSelectionEnabled, clearCellSelection, clearCellSelectionOnEscape, columns, commitCheckboxCell, commitScroll, copySelectedCells, data, dataLength, editable, editItemIndex, endCellSelectionDrag, frozenColumnIndex, frozenRowCount, height, handleClick, moveActiveCell, openCellContextMenu, selectAllCells, setEditItem, requestSearchOpen, searchOpen, searchOptions, trHeight, verticalScrollState, viewportInsets, } = keyboardRuntimeRef.current;
|
|
1720
1721
|
const container = containerRef.current;
|
|
1721
1722
|
const activeElement = document.activeElement;
|
|
1722
1723
|
if (!container || (activeElement !== container && !container.contains(activeElement)))
|
|
@@ -1844,6 +1845,7 @@ function Table(props) {
|
|
|
1844
1845
|
frozenRowCount,
|
|
1845
1846
|
columns,
|
|
1846
1847
|
rowHeight: trHeight,
|
|
1848
|
+
verticalScrollState,
|
|
1847
1849
|
viewportInsets,
|
|
1848
1850
|
});
|
|
1849
1851
|
if (result.didScroll) {
|
|
@@ -1887,6 +1889,7 @@ function Table(props) {
|
|
|
1887
1889
|
frozenRowCount,
|
|
1888
1890
|
columns,
|
|
1889
1891
|
rowHeight: trHeight,
|
|
1892
|
+
verticalScrollState,
|
|
1890
1893
|
viewportInsets,
|
|
1891
1894
|
});
|
|
1892
1895
|
if (result.didScroll) {
|
|
@@ -1914,6 +1917,7 @@ function Table(props) {
|
|
|
1914
1917
|
frozenRowCount,
|
|
1915
1918
|
columns,
|
|
1916
1919
|
rowHeight: trHeight,
|
|
1920
|
+
verticalScrollState,
|
|
1917
1921
|
viewportInsets,
|
|
1918
1922
|
});
|
|
1919
1923
|
if (result.didScroll) {
|
|
@@ -2020,7 +2024,7 @@ function Table(props) {
|
|
|
2020
2024
|
event.stopPropagation();
|
|
2021
2025
|
}
|
|
2022
2026
|
} },
|
|
2023
|
-
React.createElement(ScrollPlane, { style: { height: scrollPlaneHeight, minWidth: scrollPlaneMinWidth } },
|
|
2027
|
+
React.createElement(ScrollPlane, { style: { height: scrollPlaneHeight, minWidth: scrollPlaneMinWidth }, "data-bgrid-virtual-scroll-window": virtualScrollWindowMetrics.enabled ? 'true' : undefined, "data-bgrid-logical-height": virtualScrollWindowMetrics.logicalContentHeight, "data-bgrid-physical-height": virtualScrollWindowMetrics.physicalContentHeight, "data-bgrid-logical-scroll-top": Math.round(scrollTop), "data-bgrid-virtual-scroll-base": virtualScrollWindowMetrics.enabled ? Math.round(virtualScrollBase) : undefined },
|
|
2024
2028
|
React.createElement(HeaderContainer, { style: { height: headerHeight, top: 0 }, role: 'rfdg-header-container' },
|
|
2025
2029
|
(frozenColumnsWidth ?? 0) > 0 && (React.createElement(FrozenHeader, { style: { width: frozenColumnsWidth }, role: 'rfdg-frozen-header' },
|
|
2026
2030
|
React.createElement(TableHeadFrozen, { container: containerRef }))),
|
|
@@ -2031,7 +2035,7 @@ function Table(props) {
|
|
|
2031
2035
|
React.createElement(TableSummaryFrozen, { position: 'top' }))),
|
|
2032
2036
|
React.createElement(Summary, { style: { left: frozenColumnsWidth }, role: 'rfdg-summary' },
|
|
2033
2037
|
React.createElement(TableSummary, { position: 'top' })))),
|
|
2034
|
-
React.createElement("div", { className: 'bgrid-body-scroll-content', style: { height:
|
|
2038
|
+
React.createElement("div", { className: 'bgrid-body-scroll-content', style: { height: virtualScrollWindowMetrics.physicalContentHeight } },
|
|
2035
2039
|
frozenRowCount > 0 && (React.createElement("div", { className: 'bgrid-frozen-rows-layer', style: { height: frozenRowsHeight, top: stickyTopHeight }, "data-bgrid-row-band": 'frozen' },
|
|
2036
2040
|
(frozenColumnsWidth ?? 0) > 0 && (React.createElement("div", { className: 'bgrid-frozen-rows-left bgrid-frozen-column-boundary', style: { width: frozenColumnsWidth }, role: 'rfdg-frozen-rows-left' },
|
|
2037
2041
|
React.createElement(TableBodyFrozen, { scrollContainerRef: scrollContainerRef, rowRange: frozenRowRange, role: 'rfdg-body-top-frozen', quadrant: 'top-left', allowRowReorder: false }),
|
|
@@ -2039,17 +2043,19 @@ function Table(props) {
|
|
|
2039
2043
|
React.createElement("div", { className: 'bgrid-frozen-rows-main', style: { left: frozenColumnsWidth }, role: 'rfdg-frozen-rows-main' },
|
|
2040
2044
|
React.createElement(TableBody, { scrollContainerRef: scrollContainerRef, rowRange: frozenRowRange, role: 'rfdg-body-top', quadrant: 'top-main', allowRowReorder: false }),
|
|
2041
2045
|
renderSelectionOverlay('top-main')))),
|
|
2042
|
-
React.createElement("div", { className: 'bgrid-scrollable-rows-layer', style: { height:
|
|
2046
|
+
React.createElement("div", { className: 'bgrid-scrollable-rows-layer', style: { height: physicalScrollableRowsHeight }, "data-bgrid-row-band": 'scrollable' },
|
|
2043
2047
|
(frozenColumnsWidth ?? 0) > 0 && (React.createElement(FrozenScrollContent, { style: {
|
|
2044
2048
|
width: frozenColumnsWidth,
|
|
2045
|
-
height:
|
|
2049
|
+
height: physicalScrollableRowsHeight,
|
|
2046
2050
|
}, role: 'rfdg-frozen-scroll-container' },
|
|
2047
2051
|
React.createElement(TableBodyFrozen, { scrollContainerRef: scrollContainerRef, rowRange: scrollableRowRange, style: frozenScrollableBodyStyle, quadrant: 'body-left', onRowReorderPointerDown: rowReorderController.onPointerDown, onRowReorderKeyDown: rowReorderController.onKeyDown }),
|
|
2048
2052
|
renderSelectionOverlay('body-left'))),
|
|
2049
2053
|
React.createElement(ScrollContent, { style: {
|
|
2050
2054
|
left: frozenColumnsWidth,
|
|
2051
|
-
paddingTop:
|
|
2052
|
-
|
|
2055
|
+
paddingTop: virtualScrollWindowMetrics.enabled
|
|
2056
|
+
? visibleScrollableRows.paddingTop - virtualScrollBase
|
|
2057
|
+
: visibleScrollableRows.paddingTop,
|
|
2058
|
+
height: physicalScrollableRowsHeight,
|
|
2053
2059
|
} },
|
|
2054
2060
|
React.createElement(TableBody, { scrollContainerRef: scrollContainerRef, rowRange: scrollableRowRange, quadrant: 'body-main' }),
|
|
2055
2061
|
renderSelectionOverlay('body-main')))),
|
|
@@ -2139,7 +2145,7 @@ function getCellPositionFromPointer({ clientX, clientY, bodyContainer, scrollCon
|
|
|
2139
2145
|
const rowIndex = metrics.frozenRowCount > 0 && clientY < frozenRowsBottom
|
|
2140
2146
|
? clamp(Math.floor((clientY - bodyRect.top) / metrics.trHeight), 0, metrics.frozenRowCount - 1)
|
|
2141
2147
|
: clamp(metrics.frozenRowCount +
|
|
2142
|
-
Math.floor((
|
|
2148
|
+
Math.floor((metrics.scrollTop +
|
|
2143
2149
|
clamp(clientY - scrollRect.top, 0, Math.max(scrollContainer.clientHeight - 1, 0))) /
|
|
2144
2150
|
metrics.trHeight), 0, metrics.dataLength - 1);
|
|
2145
2151
|
const columnIndex = getColumnIndexFromPointer({
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { clipCellSelectionFragment, } from '../../utils/cellSelectionGeometry';
|
|
3
|
-
export function CellSelectionOverlayLayer({ quadrant, selectionFragments, activeFragments, activeFill, activeRing, viewport, }) {
|
|
3
|
+
export function CellSelectionOverlayLayer({ quadrant, selectionFragments, activeFragments, activeFill, activeRing, viewport, offsetTop = 0, }) {
|
|
4
4
|
const quadrantSelectionFragments = getVisibleFragments(selectionFragments, quadrant, viewport);
|
|
5
5
|
const quadrantActiveFragments = getVisibleFragments(activeFragments, quadrant, viewport);
|
|
6
6
|
if (quadrantSelectionFragments.length === 0 && quadrantActiveFragments.length === 0)
|
|
7
7
|
return null;
|
|
8
8
|
return (React.createElement("div", { className: 'bgrid-cell-selection-overlay-layer', "data-bgrid-selection-quadrant": quadrant, "aria-hidden": 'true' },
|
|
9
|
-
quadrantSelectionFragments.map(fragment => (React.createElement("div", { key: `selection-${fragment.rangeIndex}`, className: 'bgrid-cell-selection-fragment', "data-bgrid-selection-fragment": 'true', "data-bgrid-selection-range-index": fragment.rangeIndex, "data-edge-top": fragment.edges.top ? 'true' : undefined, "data-edge-right": fragment.edges.right ? 'true' : undefined, "data-edge-bottom": fragment.edges.bottom ? 'true' : undefined, "data-edge-left": fragment.edges.left ? 'true' : undefined, style: getFragmentStyle(fragment) }))),
|
|
9
|
+
quadrantSelectionFragments.map(fragment => (React.createElement("div", { key: `selection-${fragment.rangeIndex}`, className: 'bgrid-cell-selection-fragment', "data-bgrid-selection-fragment": 'true', "data-bgrid-selection-range-index": fragment.rangeIndex, "data-edge-top": fragment.edges.top ? 'true' : undefined, "data-edge-right": fragment.edges.right ? 'true' : undefined, "data-edge-bottom": fragment.edges.bottom ? 'true' : undefined, "data-edge-left": fragment.edges.left ? 'true' : undefined, style: getFragmentStyle(fragment, offsetTop) }))),
|
|
10
10
|
(activeFill || activeRing) &&
|
|
11
|
-
quadrantActiveFragments.map(fragment => (React.createElement("div", { key: `active-${fragment.rangeIndex}`, className: 'bgrid-cell-active-fragment', "data-bgrid-active-fragment": 'true', "data-active-fill": activeFill ? 'true' : undefined, "data-active-ring": activeRing ? 'true' : undefined, style: getFragmentStyle(fragment) })))));
|
|
11
|
+
quadrantActiveFragments.map(fragment => (React.createElement("div", { key: `active-${fragment.rangeIndex}`, className: 'bgrid-cell-active-fragment', "data-bgrid-active-fragment": 'true', "data-active-fill": activeFill ? 'true' : undefined, "data-active-ring": activeRing ? 'true' : undefined, style: getFragmentStyle(fragment, offsetTop) })))));
|
|
12
12
|
}
|
|
13
13
|
function getVisibleFragments(fragments, quadrant, viewport) {
|
|
14
14
|
return fragments.flatMap(fragment => {
|
|
@@ -18,10 +18,10 @@ function getVisibleFragments(fragments, quadrant, viewport) {
|
|
|
18
18
|
return visibleFragment ? [visibleFragment] : [];
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
-
function getFragmentStyle(fragment) {
|
|
21
|
+
function getFragmentStyle(fragment, offsetTop) {
|
|
22
22
|
return {
|
|
23
23
|
left: fragment.left,
|
|
24
|
-
top: fragment.top,
|
|
24
|
+
top: fragment.top - offsetTop,
|
|
25
25
|
width: fragment.width,
|
|
26
26
|
height: fragment.height,
|
|
27
27
|
};
|
package/esm/utils/coordinate.js
CHANGED
|
@@ -41,8 +41,8 @@ export function getRowBottom(rowIndex, rowHeight) {
|
|
|
41
41
|
return 0;
|
|
42
42
|
return (rowIndex + 1) * rowHeight;
|
|
43
43
|
}
|
|
44
|
-
export function ensureCellVisible({ cell, scrollContainer, frozenColumnCount = 0, frozenRowCount = 0, columns, rowHeight, viewportInsets, }) {
|
|
45
|
-
const currentScrollTop = scrollContainer?.scrollTop ?? 0;
|
|
44
|
+
export function ensureCellVisible({ cell, scrollContainer, frozenColumnCount = 0, frozenRowCount = 0, columns, rowHeight, verticalScrollState, viewportInsets, }) {
|
|
45
|
+
const currentScrollTop = verticalScrollState?.scrollTop ?? scrollContainer?.scrollTop ?? 0;
|
|
46
46
|
const currentScrollLeft = scrollContainer?.scrollLeft ?? 0;
|
|
47
47
|
let nextScrollTop = currentScrollTop;
|
|
48
48
|
let nextScrollLeft = currentScrollLeft;
|
|
@@ -52,7 +52,7 @@ export function ensureCellVisible({ cell, scrollContainer, frozenColumnCount = 0
|
|
|
52
52
|
const rowTop = getRowTop(targetRowIndex, rowHeight);
|
|
53
53
|
const rowBottom = getRowBottom(targetRowIndex, rowHeight);
|
|
54
54
|
const clientHeight = scrollContainer.clientHeight;
|
|
55
|
-
const scrollHeight = scrollContainer.scrollHeight;
|
|
55
|
+
const scrollHeight = verticalScrollState?.scrollHeight ?? scrollContainer.scrollHeight;
|
|
56
56
|
const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
|
|
57
57
|
if (clientHeight > 0) {
|
|
58
58
|
const topInset = clamp(viewportInsets?.top ?? 0, 0, clientHeight);
|
|
@@ -95,7 +95,7 @@ export function ensureCellVisible({ cell, scrollContainer, frozenColumnCount = 0
|
|
|
95
95
|
const didScrollLeft = nextScrollLeft !== currentScrollLeft;
|
|
96
96
|
const didScroll = didScrollTop || didScrollLeft;
|
|
97
97
|
if (scrollContainer) {
|
|
98
|
-
if (didScrollTop) {
|
|
98
|
+
if (didScrollTop && !verticalScrollState) {
|
|
99
99
|
scrollContainer.scrollTop = nextScrollTop;
|
|
100
100
|
}
|
|
101
101
|
if (didScrollLeft) {
|
package/esm/utils/index.js
CHANGED
|
@@ -15,6 +15,7 @@ export * from './scrollbar';
|
|
|
15
15
|
export * from './number';
|
|
16
16
|
export * from './buildHeaderMatrix';
|
|
17
17
|
export * from './getVisibleScrollableRowRange';
|
|
18
|
+
export * from './virtualScrollWindow';
|
|
18
19
|
export * from './cellEditState';
|
|
19
20
|
export * from './getCellSelectionAxisState';
|
|
20
21
|
export * from './mergedCells';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const BGRID_MAX_PHYSICAL_SCROLL_HEIGHT = 1000000;
|
|
2
|
+
export function getVirtualScrollWindowMetrics({ logicalContentHeight, viewportHeight, enabled, maxPhysicalHeight = BGRID_MAX_PHYSICAL_SCROLL_HEIGHT, }) {
|
|
3
|
+
const safeViewportHeight = Math.max(viewportHeight, 0);
|
|
4
|
+
const safeLogicalContentHeight = Math.max(logicalContentHeight, safeViewportHeight);
|
|
5
|
+
const safeMaxPhysicalHeight = Math.max(maxPhysicalHeight, safeViewportHeight);
|
|
6
|
+
const windowingEnabled = enabled && safeLogicalContentHeight > safeMaxPhysicalHeight;
|
|
7
|
+
const physicalContentHeight = windowingEnabled ? safeMaxPhysicalHeight : safeLogicalContentHeight;
|
|
8
|
+
return {
|
|
9
|
+
enabled: windowingEnabled,
|
|
10
|
+
logicalContentHeight: safeLogicalContentHeight,
|
|
11
|
+
physicalContentHeight,
|
|
12
|
+
logicalMaxScroll: Math.max(safeLogicalContentHeight - safeViewportHeight, 0),
|
|
13
|
+
physicalMaxScroll: Math.max(physicalContentHeight - safeViewportHeight, 0),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function getLogicalScrollTop(base, physicalScrollTop, metrics) {
|
|
17
|
+
return clamp(base + physicalScrollTop, 0, metrics.logicalMaxScroll);
|
|
18
|
+
}
|
|
19
|
+
export function getVirtualScrollWindowPosition(logicalScrollTop, metrics) {
|
|
20
|
+
const logicalTop = clamp(logicalScrollTop, 0, metrics.logicalMaxScroll);
|
|
21
|
+
if (!metrics.enabled) {
|
|
22
|
+
return {
|
|
23
|
+
base: 0,
|
|
24
|
+
physicalScrollTop: logicalTop,
|
|
25
|
+
logicalScrollTop: logicalTop,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const preferredPhysicalTop = metrics.physicalMaxScroll / 2;
|
|
29
|
+
const maxBase = Math.max(metrics.logicalMaxScroll - metrics.physicalMaxScroll, 0);
|
|
30
|
+
const base = clamp(logicalTop - preferredPhysicalTop, 0, maxBase);
|
|
31
|
+
return {
|
|
32
|
+
base,
|
|
33
|
+
physicalScrollTop: logicalTop - base,
|
|
34
|
+
logicalScrollTop: logicalTop,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function rebaseVirtualScrollWindow(base, physicalScrollTop, metrics) {
|
|
38
|
+
const logicalScrollTop = getLogicalScrollTop(base, physicalScrollTop, metrics);
|
|
39
|
+
if (!metrics.enabled || metrics.physicalMaxScroll <= 0) {
|
|
40
|
+
return getVirtualScrollWindowPosition(logicalScrollTop, metrics);
|
|
41
|
+
}
|
|
42
|
+
const lowerGuard = metrics.physicalMaxScroll * 0.25;
|
|
43
|
+
const upperGuard = metrics.physicalMaxScroll * 0.75;
|
|
44
|
+
const maxBase = Math.max(metrics.logicalMaxScroll - metrics.physicalMaxScroll, 0);
|
|
45
|
+
const canMoveBackward = base > 0;
|
|
46
|
+
const canMoveForward = base < maxBase;
|
|
47
|
+
if ((physicalScrollTop < lowerGuard && canMoveBackward) ||
|
|
48
|
+
(physicalScrollTop > upperGuard && canMoveForward)) {
|
|
49
|
+
return getVirtualScrollWindowPosition(logicalScrollTop, metrics);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
base,
|
|
53
|
+
physicalScrollTop: clamp(physicalScrollTop, 0, metrics.physicalMaxScroll),
|
|
54
|
+
logicalScrollTop,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function clamp(value, min, max) {
|
|
58
|
+
return Math.min(Math.max(value, min), max);
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ interface Props {
|
|
|
13
13
|
activeFill: boolean;
|
|
14
14
|
activeRing: boolean;
|
|
15
15
|
viewport: SelectionViewport;
|
|
16
|
+
offsetTop?: number;
|
|
16
17
|
}
|
|
17
|
-
export declare function CellSelectionOverlayLayer({ quadrant, selectionFragments, activeFragments, activeFill, activeRing, viewport, }: Props): React.JSX.Element | null;
|
|
18
|
+
export declare function CellSelectionOverlayLayer({ quadrant, selectionFragments, activeFragments, activeFill, activeRing, viewport, offsetTop, }: Props): React.JSX.Element | null;
|
|
18
19
|
export {};
|
|
@@ -12,6 +12,10 @@ export interface EnsureCellVisibleParams {
|
|
|
12
12
|
frozenRowCount?: number;
|
|
13
13
|
columns: AppModelColumn<any>[];
|
|
14
14
|
rowHeight: number;
|
|
15
|
+
verticalScrollState?: {
|
|
16
|
+
scrollTop: number;
|
|
17
|
+
scrollHeight: number;
|
|
18
|
+
};
|
|
15
19
|
viewportInsets?: {
|
|
16
20
|
top?: number;
|
|
17
21
|
right?: number;
|
|
@@ -26,4 +30,4 @@ export interface EnsureCellVisibleResult {
|
|
|
26
30
|
didScrollTop: boolean;
|
|
27
31
|
didScrollLeft: boolean;
|
|
28
32
|
}
|
|
29
|
-
export declare function ensureCellVisible({ cell, scrollContainer, frozenColumnCount, frozenRowCount, columns, rowHeight, viewportInsets, }: EnsureCellVisibleParams): EnsureCellVisibleResult;
|
|
33
|
+
export declare function ensureCellVisible({ cell, scrollContainer, frozenColumnCount, frozenRowCount, columns, rowHeight, verticalScrollState, viewportInsets, }: EnsureCellVisibleParams): EnsureCellVisibleResult;
|
package/types/utils/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export * from './scrollbar';
|
|
|
15
15
|
export * from './number';
|
|
16
16
|
export * from './buildHeaderMatrix';
|
|
17
17
|
export * from './getVisibleScrollableRowRange';
|
|
18
|
+
export * from './virtualScrollWindow';
|
|
18
19
|
export * from './cellEditState';
|
|
19
20
|
export * from './getCellSelectionAxisState';
|
|
20
21
|
export * from './mergedCells';
|