From 904327691141ab653be8a0d964087c4077e61cf1 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 6 Mar 2024 14:03:03 -0500 Subject: [PATCH 01/31] feat: pixel buffers instead of item buffers --- .../features/lazyLoader/useGridLazyLoader.ts | 1 - .../src/DataGrid/useDataGridProps.ts | 8 +- .../features/columns/gridColumnsUtils.ts | 30 ------ .../virtualization/useGridVirtualScroller.tsx | 98 ++++++++++--------- .../src/models/props/DataGridProps.ts | 12 +-- .../tests/columnSpanning.DataGrid.test.tsx | 4 +- 6 files changed, 66 insertions(+), 87 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts b/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts index ae61a9f02f080..2b53c6cfcd08d 100644 --- a/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts +++ b/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts @@ -94,7 +94,6 @@ export const useGridLazyLoader = ( | 'rowsLoadingMode' | 'pagination' | 'paginationMode' - | 'rowBuffer' | 'experimentalFeatures' >, ): void => { diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts index 139c6151f83f4..070e6002d7219 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -32,10 +32,10 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { autoPageSize: false, checkboxSelection: false, checkboxSelectionVisibleOnly: false, - columnBuffer: 3, - rowBuffer: 3, - columnThreshold: 3, - rowThreshold: 3, + columnBufferPx: 150, + rowBufferPx: 150, + columnThreshold: 150, + rowThreshold: 150, rowSelection: true, density: 'standard', disableColumnFilter: false, diff --git a/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts b/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts index 5c1962faa6378..58f0041a90448 100644 --- a/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts +++ b/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts @@ -428,36 +428,6 @@ export function getFirstNonSpannedColumnToRender({ return firstNonSpannedColumnToRender; } -export function getFirstColumnIndexToRender({ - firstColumnIndex, - minColumnIndex, - columnBuffer, - firstRowToRender, - lastRowToRender, - apiRef, - visibleRows, -}: { - firstColumnIndex: number; - minColumnIndex: number; - columnBuffer: number; - apiRef: React.MutableRefObject; - firstRowToRender: number; - lastRowToRender: number; - visibleRows: GridRowEntry[]; -}) { - const initialFirstColumnToRender = Math.max(firstColumnIndex - columnBuffer, minColumnIndex); - - const firstColumnToRender = getFirstNonSpannedColumnToRender({ - firstColumnToRender: initialFirstColumnToRender, - apiRef, - firstRowToRender, - lastRowToRender, - visibleRows, - }); - - return firstColumnToRender; -} - export function getTotalHeaderHeight( apiRef: React.MutableRefObject, headerHeight: number, diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 1d533ee81bd05..1cbdf74411180 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -37,6 +37,8 @@ import { } from './gridVirtualizationSelectors'; import { EMPTY_RENDER_CONTEXT } from './useGridVirtualization'; +const EMPTY_SCROLL_POSITION = { top: 0, left: 0 }; + export const EMPTY_DETAIL_PANELS = Object.freeze(new Map()); export type VirtualScroller = ReturnType; @@ -71,10 +73,11 @@ export const useGridVirtualScroller = () => { useResizeObserver(mainRef, () => apiRef.current.resize()); + const previousScroll = React.useRef(EMPTY_SCROLL_POSITION); const previousContext = React.useRef(EMPTY_RENDER_CONTEXT); const previousRowContext = React.useRef(EMPTY_RENDER_CONTEXT); const renderContext = useGridSelector(apiRef, gridRenderContextSelector); - const scrollPosition = React.useRef({ top: 0, left: 0 }).current; + const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const prevTotalWidth = React.useRef(columnsTotalWidth); const focusedCell = { @@ -119,6 +122,7 @@ export const useGridVirtualScroller = () => { apiRef.current.publishEvent('renderedRowsIntervalChange', nextRenderContext); } + previousScroll.current = scrollPosition.current previousContext.current = rawRenderContext; prevTotalWidth.current = dimensions.columnsTotalWidth; }, @@ -126,35 +130,21 @@ export const useGridVirtualScroller = () => { ); const triggerUpdateRenderContext = () => { - const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition); - // Since previous render, we have scrolled... - const topRowsScrolled = Math.abs( - rawRenderContext.firstRowIndex - previousContext.current.firstRowIndex, - ); - const bottomRowsScrolled = Math.abs( - rawRenderContext.lastRowIndex - previousContext.current.lastRowIndex, - ); - - const topColumnsScrolled = Math.abs( - rawRenderContext.firstColumnIndex - previousContext.current.firstColumnIndex, - ); - const bottomColumnsScrolled = Math.abs( - rawRenderContext.lastColumnIndex - previousContext.current.lastColumnIndex, - ); + const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top); + const columnScroll = Math.abs(scrollPosition.current.left - previousScroll.current.left); const shouldUpdate = - topRowsScrolled >= rootProps.rowThreshold || - bottomRowsScrolled >= rootProps.rowThreshold || - topColumnsScrolled >= rootProps.columnThreshold || - bottomColumnsScrolled >= rootProps.columnThreshold || - prevTotalWidth.current !== dimensions.columnsTotalWidth; + rowScroll >= rootProps.rowThreshold || + columnScroll >= rootProps.columnThreshold; if (!shouldUpdate) { return previousContext.current; } + const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); + const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current); + // Prevents batching render context changes ReactDOM.flushSync(() => { updateRenderContext(nextRenderContext, rawRenderContext); @@ -165,15 +155,14 @@ export const useGridVirtualScroller = () => { const forceUpdateRenderContext = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition); + const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current); updateRenderContext(nextRenderContext, rawRenderContext); }; const handleScroll = useEventCallback((event: React.UIEvent) => { const { scrollTop, scrollLeft } = event.currentTarget; - scrollPosition.top = scrollTop; - scrollPosition.left = scrollLeft; + scrollPosition.current = { top: scrollTop, left: scrollLeft }; // On iOS and macOS, negative offsets are possible when swiping past the start if (scrollTop < 0) { @@ -441,12 +430,12 @@ export const useGridVirtualScroller = () => { useRunOnce(outerSize.width !== 0, () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [initialRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition); + const [initialRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current); updateRenderContext(initialRenderContext, rawRenderContext); apiRef.current.publishEvent('scrollPositionChange', { - top: scrollPosition.top, - left: scrollPosition.left, + top: scrollPosition.current.top, + left: scrollPosition.current.left, renderContext: initialRenderContext, }); }); @@ -491,8 +480,8 @@ type RenderContextInputs = { enabledForColumns: boolean; apiRef: React.MutableRefObject; autoHeight: boolean; - rowBuffer: number; - columnBuffer: number; + rowBufferPx: number; + columnBufferPx: number; leftPinnedWidth: number; columnsTotalWidth: number; viewportInnerWidth: number; @@ -518,8 +507,8 @@ function inputsSelector( enabledForColumns, apiRef, autoHeight: rootProps.autoHeight, - rowBuffer: rootProps.rowBuffer, - columnBuffer: rootProps.columnBuffer, + rowBufferPx: rootProps.rowBufferPx, + columnBufferPx: rootProps.columnBufferPx, leftPinnedWidth: dimensions.leftPinnedWidth, columnsTotalWidth: dimensions.columnsTotalWidth, viewportInnerWidth: dimensions.viewportInnerSize.width, @@ -569,7 +558,8 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol lastIndex: lastRowIndex, minFirstIndex: 0, maxLastIndex: inputs.rows.length, - buffer: inputs.rowBuffer, + bufferPx: inputs.rowBufferPx, + positions: inputs.rowsMeta.positions, }); for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) { @@ -599,9 +589,11 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol const actualRenderContext = deriveRenderContext( inputs.apiRef, - inputs.rowBuffer, - inputs.columnBuffer, + inputs.rowBufferPx, + inputs.columnBufferPx, inputs.rows, + inputs.rowsMeta.positions, + inputs.columnPositions, inputs.pinnedColumns, inputs.visibleColumns, renderContext, @@ -651,9 +643,11 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) { */ function deriveRenderContext( apiRef: React.MutableRefObject, - rowBuffer: number, - columnBuffer: number, + rowBufferPx: number, + columnBufferPx: number, rows: ReturnType['rows'], + rowPositions: number[], + columnPositions: number[], pinnedColumns: ReturnType, visibleColumns: ReturnType, nextRenderContext: GridRenderContext, @@ -663,7 +657,8 @@ function deriveRenderContext( lastIndex: nextRenderContext.lastRowIndex, minFirstIndex: 0, maxLastIndex: rows.length, - buffer: rowBuffer, + bufferPx: rowBufferPx, + positions: rowPositions, }); const [initialFirstColumnToRender, lastColumnToRender] = getIndexesToRender({ @@ -671,7 +666,8 @@ function deriveRenderContext( lastIndex: nextRenderContext.lastColumnIndex, minFirstIndex: pinnedColumns.left.length, maxLastIndex: visibleColumns.length - pinnedColumns.right.length, - buffer: columnBuffer, + bufferPx: columnBufferPx, + positions: columnPositions, }); const firstColumnToRender = getFirstNonSpannedColumnToRender({ @@ -682,12 +678,14 @@ function deriveRenderContext( visibleRows: rows, }); - return { + let r = { firstRowIndex: firstRowToRender, lastRowIndex: lastRowToRender, firstColumnIndex: firstColumnToRender, lastColumnIndex: lastColumnToRender, }; + console.log(r) + return r } type SearchOptions = { @@ -753,19 +751,31 @@ function exponentialSearch(offset: number, positions: number[], index: number): function getIndexesToRender({ firstIndex, lastIndex, - buffer, + bufferPx, minFirstIndex, maxLastIndex, + positions, }: { firstIndex: number; lastIndex: number; - buffer: number; + bufferPx: number; minFirstIndex: number; maxLastIndex: number; + positions: number[]; }) { + const firstPosition = positions[firstIndex] - bufferPx; + const lastPosition = positions[lastIndex] + bufferPx; + + const firstIndexPadded = binarySearch(firstPosition, positions, { + atStart: true, + lastPosition: positions[positions.length - 1] * 2, // Value doesn't matter much here, only need to be vastly superior + }); + + const lastIndexPadded = binarySearch(lastPosition, positions); + return [ - clamp(firstIndex - buffer, minFirstIndex, maxLastIndex), - clamp(lastIndex + buffer, minFirstIndex, maxLastIndex), + clamp(firstIndexPadded, minFirstIndex, maxLastIndex), + clamp(lastIndexPadded, minFirstIndex, maxLastIndex), ]; } diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index cab7a732b01e4..6683370c0da72 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -128,15 +128,15 @@ export interface DataGridPropsWithDefaultValues { */ checkboxSelectionVisibleOnly: boolean; /** - * Number of extra columns to be rendered before/after the visible slice. - * @default 3 + * Column region to render before/after the viewport + * @default 100 */ - columnBuffer: number; + columnBufferPx: number; /** - * Number of extra rows to be rendered before/after the visible slice. - * @default 3 + * Row region to render before/after the viewport + * @default 100 */ - rowBuffer: number; + rowBufferPx: number; /** * If `false`, the row selection mode is disabled. * @default true diff --git a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx index 57f591f6f573b..64f340d1b00f7 100644 --- a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx @@ -348,7 +348,7 @@ describe(' - Column spanning', () => { { field: 'col3', width: 100 }, ]} rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3' }]} - columnBuffer={1} + columnBufferPx={1} columnThreshold={1} /> , @@ -456,7 +456,7 @@ describe(' - Column spanning', () => { { field: 'col4', width: 100 }, ]} rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3', col4: '0-4' }]} - columnBuffer={1} + columnBufferPx={1} columnThreshold={1} /> , From 4dadf5c94f74d369fda4a3da4dca9f4cce8df608 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 6 Mar 2024 14:49:03 -0500 Subject: [PATCH 02/31] feat: scroll position prediction --- .../virtualization/useGridVirtualScroller.tsx | 104 +++++++++++++++--- 1 file changed, 87 insertions(+), 17 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 1cbdf74411180..597a4c47ca124 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -43,6 +43,51 @@ export const EMPTY_DETAIL_PANELS = Object.freeze(new Map; +enum ScrollDirection { + NONE, + UP, + DOWN, + LEFT, + RIGHT, +} + +function directionForDelta(dx: number, dy: number) { + if (dx === 0 && dy === 0) { + return ScrollDirection.NONE + } + if (Math.abs(dy) >= Math.abs(dx)) { + if (dy > 0) { + return ScrollDirection.DOWN + } else { + return ScrollDirection.UP + } + } else { + if (dx > 0) { + return ScrollDirection.RIGHT + } else { + return ScrollDirection.LEFT + } + } +} + +function bufferForScrollCache(scrollCache: ScrollCache) { + const direction = scrollCache.direction + return { + rowBefore: direction === ScrollDirection.LEFT ? scrollCache.expectedScroll.left : 0, + rowAfter: direction === ScrollDirection.RIGHT ? scrollCache.expectedScroll.left : 0, + columnBefore: direction === ScrollDirection.UP ? scrollCache.expectedScroll.top : 0, + columnAfter: direction === ScrollDirection.DOWN ? scrollCache.expectedScroll.top : 0, + } +} + +const EMPTY_SCROLL_CACHE = { + direction: ScrollDirection.NONE, + lastTimestamp: -1, + lastPosition: { top: 0, left: 0 }, + expectedScroll: { top: 0, left: 0 }, +} +type ScrollCache = typeof EMPTY_SCROLL_CACHE + export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext(); const rootProps = useGridRootProps(); @@ -80,6 +125,8 @@ export const useGridVirtualScroller = () => { const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const prevTotalWidth = React.useRef(columnsTotalWidth); + const scrollCache = React.useRef({ ...EMPTY_SCROLL_CACHE }).current; + const focusedCell = { rowIndex: React.useMemo( () => (cellFocus ? currentPage.rows.findIndex((row) => row.id === cellFocus.id) : -1), @@ -130,12 +177,28 @@ export const useGridVirtualScroller = () => { ); const triggerUpdateRenderContext = () => { + + // TODO: use better math to predict future position + const now = performance.now() + const isScrolling = scrollCache.lastTimestamp !== -1 && now - scrollCache.lastTimestamp < 500 + // const dt = isScrolling ? now - scrollCache.lastTimestamp : Infinity; + const dy = isScrolling ? scrollPosition.current.top - scrollCache.lastPosition.top : 0; + const dx = isScrolling ? scrollPosition.current.left - scrollCache.lastPosition.left : 0; + + // XXX: remove + // console.log('scroll', scrollPosition.current.top, { dt, dy, dx }) + + scrollCache.lastTimestamp = now + scrollCache.lastPosition = scrollPosition.current + scrollCache.expectedScroll = { top: dy, left: dx } + scrollCache.direction = directionForDelta(dx, dy) + // Since previous render, we have scrolled... - const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top); - const columnScroll = Math.abs(scrollPosition.current.left - previousScroll.current.left); + const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.expectedScroll.top; + const columnScroll = Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.expectedScroll.left; const shouldUpdate = - rowScroll >= rootProps.rowThreshold || + rowScroll >= rootProps.rowThreshold || columnScroll >= rootProps.columnThreshold; if (!shouldUpdate) { @@ -143,7 +206,7 @@ export const useGridVirtualScroller = () => { } const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current); + const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current, scrollCache); // Prevents batching render context changes ReactDOM.flushSync(() => { @@ -155,7 +218,7 @@ export const useGridVirtualScroller = () => { const forceUpdateRenderContext = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current); + const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current, scrollCache); updateRenderContext(nextRenderContext, rawRenderContext); }; @@ -430,7 +493,7 @@ export const useGridVirtualScroller = () => { useRunOnce(outerSize.width !== 0, () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [initialRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current); + const [initialRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current, scrollCache); updateRenderContext(initialRenderContext, rawRenderContext); apiRef.current.publishEvent('scrollPositionChange', { @@ -522,7 +585,7 @@ function inputsSelector( }; } -function computeRenderContext(inputs: RenderContextInputs, scrollPosition: ScrollPosition) { +function computeRenderContext(inputs: RenderContextInputs, scrollPosition: ScrollPosition, scrollCache: ScrollCache) { let renderContext: GridRenderContext; if (!inputs.enabled) { @@ -558,7 +621,8 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol lastIndex: lastRowIndex, minFirstIndex: 0, maxLastIndex: inputs.rows.length, - bufferPx: inputs.rowBufferPx, + bufferBefore: inputs.rowBufferPx, + bufferAfter: inputs.rowBufferPx, positions: inputs.rowsMeta.positions, }); @@ -597,6 +661,7 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol inputs.pinnedColumns, inputs.visibleColumns, renderContext, + scrollCache, ); return [actualRenderContext, renderContext]; @@ -651,13 +716,17 @@ function deriveRenderContext( pinnedColumns: ReturnType, visibleColumns: ReturnType, nextRenderContext: GridRenderContext, + scrollCache: ScrollCache, ) { + const buffer = bufferForScrollCache(scrollCache) + const [firstRowToRender, lastRowToRender] = getIndexesToRender({ firstIndex: nextRenderContext.firstRowIndex, lastIndex: nextRenderContext.lastRowIndex, minFirstIndex: 0, maxLastIndex: rows.length, - bufferPx: rowBufferPx, + bufferBefore: rowBufferPx + buffer.rowBefore, + bufferAfter: rowBufferPx + buffer.rowAfter, positions: rowPositions, }); @@ -666,7 +735,8 @@ function deriveRenderContext( lastIndex: nextRenderContext.lastColumnIndex, minFirstIndex: pinnedColumns.left.length, maxLastIndex: visibleColumns.length - pinnedColumns.right.length, - bufferPx: columnBufferPx, + bufferBefore: columnBufferPx + buffer.columnBefore, + bufferAfter: columnBufferPx + buffer.columnAfter, positions: columnPositions, }); @@ -678,14 +748,12 @@ function deriveRenderContext( visibleRows: rows, }); - let r = { + return { firstRowIndex: firstRowToRender, lastRowIndex: lastRowToRender, firstColumnIndex: firstColumnToRender, lastColumnIndex: lastColumnToRender, }; - console.log(r) - return r } type SearchOptions = { @@ -751,20 +819,22 @@ function exponentialSearch(offset: number, positions: number[], index: number): function getIndexesToRender({ firstIndex, lastIndex, - bufferPx, + bufferBefore, + bufferAfter, minFirstIndex, maxLastIndex, positions, }: { firstIndex: number; lastIndex: number; - bufferPx: number; + bufferBefore: number; + bufferAfter: number; minFirstIndex: number; maxLastIndex: number; positions: number[]; }) { - const firstPosition = positions[firstIndex] - bufferPx; - const lastPosition = positions[lastIndex] + bufferPx; + const firstPosition = positions[firstIndex] - bufferBefore; + const lastPosition = positions[lastIndex] + bufferAfter; const firstIndexPadded = binarySearch(firstPosition, positions, { atStart: true, From 8742d375e8afde2b29b1c00e2aaec314b7454240 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 6 Mar 2024 19:48:09 -0500 Subject: [PATCH 03/31] feat: predict with linear regression --- packages/x-data-grid/package.json | 1 + .../virtualization/useGridVirtualScroller.tsx | 39 +++++++++++++++---- yarn.lock | 26 +++++++++++++ 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index eee28b6cac29d..a2cbdea97206a 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -50,6 +50,7 @@ "@mui/system": "^5.15.9", "@mui/utils": "^5.15.9", "clsx": "^2.1.0", + "ml-regression-simple-linear": "^3.0.0", "prop-types": "^15.8.1", "reselect": "^4.1.8" }, diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 597a4c47ca124..4d76c9d9623d6 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -5,6 +5,7 @@ import { unstable_useEventCallback as useEventCallback, } from '@mui/utils'; import { useTheme, Theme } from '@mui/material/styles'; +import { SimpleLinearRegression } from 'ml-regression-simple-linear'; import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; import { useGridRootProps } from '../../utils/useGridRootProps'; @@ -85,6 +86,7 @@ const EMPTY_SCROLL_CACHE = { lastTimestamp: -1, lastPosition: { top: 0, left: 0 }, expectedScroll: { top: 0, left: 0 }, + events: [] as ({ top: number, left: number, timestamp: number } & Record)[] } type ScrollCache = typeof EMPTY_SCROLL_CACHE @@ -179,19 +181,40 @@ export const useGridVirtualScroller = () => { const triggerUpdateRenderContext = () => { // TODO: use better math to predict future position - const now = performance.now() - const isScrolling = scrollCache.lastTimestamp !== -1 && now - scrollCache.lastTimestamp < 500 - // const dt = isScrolling ? now - scrollCache.lastTimestamp : Infinity; - const dy = isScrolling ? scrollPosition.current.top - scrollCache.lastPosition.top : 0; - const dx = isScrolling ? scrollPosition.current.left - scrollCache.lastPosition.left : 0; + const timestamp = performance.now() + const isScrolling = scrollCache.lastTimestamp !== -1 && timestamp - scrollCache.lastTimestamp < 500 + const dt = timestamp - scrollCache.lastTimestamp // XXX: remove // console.log('scroll', scrollPosition.current.top, { dt, dy, dx }) - scrollCache.lastTimestamp = now + scrollCache.lastTimestamp = timestamp scrollCache.lastPosition = scrollPosition.current - scrollCache.expectedScroll = { top: dy, left: dx } - scrollCache.direction = directionForDelta(dx, dy) + if (isScrolling) { + scrollCache.events.push({ ...scrollPosition.current, timestamp }) + } else { + scrollCache.events = [{ ...scrollPosition.current, timestamp }] + } + + if (isScrolling) { + const y = scrollPosition.current.top; + const x = scrollPosition.current.left; + const dy = Math.round(new SimpleLinearRegression( + scrollCache.events.slice(-4).map(e => e.timestamp), + scrollCache.events.slice(-4).map(e => e.top), + ).predict(timestamp + dt)) - y + const dx = Math.round(new SimpleLinearRegression( + scrollCache.events.slice(-4).map(e => e.timestamp), + scrollCache.events.slice(-4).map(e => e.left), + ).predict(timestamp + dt)) - x + scrollCache.expectedScroll = { top: dy, left: dx } + scrollCache.direction = directionForDelta(dx, dy) + } else { + scrollCache.expectedScroll = { top: 0, left: 0 } + scrollCache.direction = ScrollDirection.NONE + } + // console.log(scrollCache.expectedScroll) + // Since previous render, we have scrolled... const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.expectedScroll.top; diff --git a/yarn.lock b/yarn.lock index eb98506862d27..955d882e68eb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5048,6 +5048,11 @@ cheerio@^1.0.0-rc.3: parse5 "^7.0.0" parse5-htmlparser2-tree-adapter "^7.0.0" +cheminfo-types@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/cheminfo-types/-/cheminfo-types-1.7.2.tgz#15e77fa571abf80b47c9f002ad926d400369d16b" + integrity sha512-Zz7HPnh6wB2beEK7nfsXlNSK1Tpl4O0DpYUod8L6gI/5+INpn/d5UgJLI+3ck6CYY5Qsq34ylyKhERmZ5Wks2A== + chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.5.1: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -8552,6 +8557,11 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" +is-any-array@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-any-array/-/is-any-array-2.0.1.tgz#9233242a9c098220290aa2ec28f82ca7fa79899e" + integrity sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ== + is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -10635,6 +10645,22 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +ml-regression-base@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ml-regression-base/-/ml-regression-base-3.0.0.tgz#96e48c0fb474e01c3bb019970e7efc8b9f317650" + integrity sha512-qkQWvNk8VU1LIytjid/+YHOSx8GnEU9dCUPsAQ8AzCh4saijrsni/XA6x7r+N1UrHMDHeSEUBtRZTsl2syyu/A== + dependencies: + cheminfo-types "^1.7.2" + is-any-array "^2.0.1" + +ml-regression-simple-linear@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ml-regression-simple-linear/-/ml-regression-simple-linear-3.0.0.tgz#cf5cf6c0c07938d2d02e64cd3eccca45fd7657dd" + integrity sha512-WHtHq8CE6PIPWS3a6JA/Ql39ppHTOAAZ0l/UoxQ7p7cMh2taOebsicnBxlqRjibUl+RGUr+6tZlBp1ppiTwMdQ== + dependencies: + cheminfo-types "^1.7.2" + ml-regression-base "^3.0.0" + mocha@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.3.0.tgz#0e185c49e6dccf582035c05fa91084a4ff6e3fe9" From 82e24c29565591291a7ed6bbb8cd5b73b4ca340e Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 6 Mar 2024 20:08:45 -0500 Subject: [PATCH 04/31] feat: more simple buffer --- packages/x-data-grid/package.json | 1 - .../virtualization/useGridVirtualScroller.tsx | 99 ++++++++----------- yarn.lock | 26 ----- 3 files changed, 41 insertions(+), 85 deletions(-) diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index a2cbdea97206a..eee28b6cac29d 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -50,7 +50,6 @@ "@mui/system": "^5.15.9", "@mui/utils": "^5.15.9", "clsx": "^2.1.0", - "ml-regression-simple-linear": "^3.0.0", "prop-types": "^15.8.1", "reselect": "^4.1.8" }, diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 4d76c9d9623d6..4a5a4fc2a48d0 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -5,7 +5,6 @@ import { unstable_useEventCallback as useEventCallback, } from '@mui/utils'; import { useTheme, Theme } from '@mui/material/styles'; -import { SimpleLinearRegression } from 'ml-regression-simple-linear'; import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; import { useGridRootProps } from '../../utils/useGridRootProps'; @@ -52,40 +51,11 @@ enum ScrollDirection { RIGHT, } -function directionForDelta(dx: number, dy: number) { - if (dx === 0 && dy === 0) { - return ScrollDirection.NONE - } - if (Math.abs(dy) >= Math.abs(dx)) { - if (dy > 0) { - return ScrollDirection.DOWN - } else { - return ScrollDirection.UP - } - } else { - if (dx > 0) { - return ScrollDirection.RIGHT - } else { - return ScrollDirection.LEFT - } - } -} - -function bufferForScrollCache(scrollCache: ScrollCache) { - const direction = scrollCache.direction - return { - rowBefore: direction === ScrollDirection.LEFT ? scrollCache.expectedScroll.left : 0, - rowAfter: direction === ScrollDirection.RIGHT ? scrollCache.expectedScroll.left : 0, - columnBefore: direction === ScrollDirection.UP ? scrollCache.expectedScroll.top : 0, - columnAfter: direction === ScrollDirection.DOWN ? scrollCache.expectedScroll.top : 0, - } -} - const EMPTY_SCROLL_CACHE = { direction: ScrollDirection.NONE, lastTimestamp: -1, lastPosition: { top: 0, left: 0 }, - expectedScroll: { top: 0, left: 0 }, + buffer: { top: 0, left: 0 }, events: [] as ({ top: number, left: number, timestamp: number } & Record)[] } type ScrollCache = typeof EMPTY_SCROLL_CACHE @@ -179,46 +149,29 @@ export const useGridVirtualScroller = () => { ); const triggerUpdateRenderContext = () => { - - // TODO: use better math to predict future position const timestamp = performance.now() - const isScrolling = scrollCache.lastTimestamp !== -1 && timestamp - scrollCache.lastTimestamp < 500 const dt = timestamp - scrollCache.lastTimestamp - - // XXX: remove - // console.log('scroll', scrollPosition.current.top, { dt, dy, dx }) + const isScrolling = scrollCache.lastTimestamp !== -1 && dt < 500 scrollCache.lastTimestamp = timestamp scrollCache.lastPosition = scrollPosition.current - if (isScrolling) { - scrollCache.events.push({ ...scrollPosition.current, timestamp }) - } else { - scrollCache.events = [{ ...scrollPosition.current, timestamp }] - } if (isScrolling) { - const y = scrollPosition.current.top; - const x = scrollPosition.current.left; - const dy = Math.round(new SimpleLinearRegression( - scrollCache.events.slice(-4).map(e => e.timestamp), - scrollCache.events.slice(-4).map(e => e.top), - ).predict(timestamp + dt)) - y - const dx = Math.round(new SimpleLinearRegression( - scrollCache.events.slice(-4).map(e => e.timestamp), - scrollCache.events.slice(-4).map(e => e.left), - ).predict(timestamp + dt)) - x - scrollCache.expectedScroll = { top: dy, left: dx } + const dy = scrollPosition.current.top - previousScroll.current.top; + const dx = scrollPosition.current.left - previousScroll.current.left; + scrollCache.buffer = { + top: dimensions.rowHeight * 10, + left: 50 * 3, + } scrollCache.direction = directionForDelta(dx, dy) } else { - scrollCache.expectedScroll = { top: 0, left: 0 } + scrollCache.buffer = { top: 0, left: 0 } scrollCache.direction = ScrollDirection.NONE } - // console.log(scrollCache.expectedScroll) - // Since previous render, we have scrolled... - const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.expectedScroll.top; - const columnScroll = Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.expectedScroll.left; + const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.buffer.top; + const columnScroll = Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.buffer.left; const shouldUpdate = rowScroll >= rootProps.rowThreshold || @@ -897,3 +850,33 @@ export function computeOffsetLeft( return left; } + +function directionForDelta(dx: number, dy: number) { + if (dx === 0 && dy === 0) { + return ScrollDirection.NONE + } + if (Math.abs(dy) >= Math.abs(dx)) { + if (dy > 0) { + return ScrollDirection.DOWN + } else { + return ScrollDirection.UP + } + } else { + if (dx > 0) { + return ScrollDirection.RIGHT + } else { + return ScrollDirection.LEFT + } + } +} + +function bufferForScrollCache(scrollCache: ScrollCache) { + const direction = scrollCache.direction + return { + columnBefore: direction === ScrollDirection.LEFT ? scrollCache.buffer.left : 0, + columnAfter: direction === ScrollDirection.RIGHT ? scrollCache.buffer.left : 0, + rowBefore: direction === ScrollDirection.UP ? scrollCache.buffer.top : 0, + rowAfter: direction === ScrollDirection.DOWN ? scrollCache.buffer.top : 0, + } +} + diff --git a/yarn.lock b/yarn.lock index 955d882e68eb1..eb98506862d27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5048,11 +5048,6 @@ cheerio@^1.0.0-rc.3: parse5 "^7.0.0" parse5-htmlparser2-tree-adapter "^7.0.0" -cheminfo-types@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/cheminfo-types/-/cheminfo-types-1.7.2.tgz#15e77fa571abf80b47c9f002ad926d400369d16b" - integrity sha512-Zz7HPnh6wB2beEK7nfsXlNSK1Tpl4O0DpYUod8L6gI/5+INpn/d5UgJLI+3ck6CYY5Qsq34ylyKhERmZ5Wks2A== - chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.5.1: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -8557,11 +8552,6 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" -is-any-array@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-any-array/-/is-any-array-2.0.1.tgz#9233242a9c098220290aa2ec28f82ca7fa79899e" - integrity sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ== - is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -10645,22 +10635,6 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ml-regression-base@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ml-regression-base/-/ml-regression-base-3.0.0.tgz#96e48c0fb474e01c3bb019970e7efc8b9f317650" - integrity sha512-qkQWvNk8VU1LIytjid/+YHOSx8GnEU9dCUPsAQ8AzCh4saijrsni/XA6x7r+N1UrHMDHeSEUBtRZTsl2syyu/A== - dependencies: - cheminfo-types "^1.7.2" - is-any-array "^2.0.1" - -ml-regression-simple-linear@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ml-regression-simple-linear/-/ml-regression-simple-linear-3.0.0.tgz#cf5cf6c0c07938d2d02e64cd3eccca45fd7657dd" - integrity sha512-WHtHq8CE6PIPWS3a6JA/Ql39ppHTOAAZ0l/UoxQ7p7cMh2taOebsicnBxlqRjibUl+RGUr+6tZlBp1ppiTwMdQ== - dependencies: - cheminfo-types "^1.7.2" - ml-regression-base "^3.0.0" - mocha@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.3.0.tgz#0e185c49e6dccf582035c05fa91084a4ff6e3fe9" From 036fc26a54d95933ab5754d7837541182fddffa0 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 6 Mar 2024 20:39:15 -0500 Subject: [PATCH 05/31] lint --- .../features/lazyLoader/useGridLazyLoader.ts | 6 +- .../virtualization/useGridVirtualScroller.tsx | 80 ++++++++++++------- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts b/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts index 2b53c6cfcd08d..41f46f58ae836 100644 --- a/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts +++ b/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts @@ -90,11 +90,7 @@ export const useGridLazyLoader = ( privateApiRef: React.MutableRefObject, props: Pick< DataGridProProcessedProps, - | 'onFetchRows' - | 'rowsLoadingMode' - | 'pagination' - | 'paginationMode' - | 'experimentalFeatures' + 'onFetchRows' | 'rowsLoadingMode' | 'pagination' | 'paginationMode' | 'experimentalFeatures' >, ): void => { const sortModel = useGridSelector(privateApiRef, gridSortModelSelector); diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 4a5a4fc2a48d0..be5b40ca17ea8 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -56,9 +56,9 @@ const EMPTY_SCROLL_CACHE = { lastTimestamp: -1, lastPosition: { top: 0, left: 0 }, buffer: { top: 0, left: 0 }, - events: [] as ({ top: number, left: number, timestamp: number } & Record)[] -} -type ScrollCache = typeof EMPTY_SCROLL_CACHE + events: [] as ({ top: number; left: number; timestamp: number } & Record)[], +}; +type ScrollCache = typeof EMPTY_SCROLL_CACHE; export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext(); @@ -141,7 +141,7 @@ export const useGridVirtualScroller = () => { apiRef.current.publishEvent('renderedRowsIntervalChange', nextRenderContext); } - previousScroll.current = scrollPosition.current + previousScroll.current = scrollPosition.current; previousContext.current = rawRenderContext; prevTotalWidth.current = dimensions.columnsTotalWidth; }, @@ -149,12 +149,12 @@ export const useGridVirtualScroller = () => { ); const triggerUpdateRenderContext = () => { - const timestamp = performance.now() - const dt = timestamp - scrollCache.lastTimestamp - const isScrolling = scrollCache.lastTimestamp !== -1 && dt < 500 + const timestamp = performance.now(); + const dt = timestamp - scrollCache.lastTimestamp; + const isScrolling = scrollCache.lastTimestamp !== -1 && dt < 500; - scrollCache.lastTimestamp = timestamp - scrollCache.lastPosition = scrollPosition.current + scrollCache.lastTimestamp = timestamp; + scrollCache.lastPosition = scrollPosition.current; if (isScrolling) { const dy = scrollPosition.current.top - previousScroll.current.top; @@ -162,27 +162,32 @@ export const useGridVirtualScroller = () => { scrollCache.buffer = { top: dimensions.rowHeight * 10, left: 50 * 3, - } - scrollCache.direction = directionForDelta(dx, dy) + }; + scrollCache.direction = directionForDelta(dx, dy); } else { - scrollCache.buffer = { top: 0, left: 0 } - scrollCache.direction = ScrollDirection.NONE + scrollCache.buffer = { top: 0, left: 0 }; + scrollCache.direction = ScrollDirection.NONE; } // Since previous render, we have scrolled... - const rowScroll = Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.buffer.top; - const columnScroll = Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.buffer.left; + const rowScroll = + Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.buffer.top; + const columnScroll = + Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.buffer.left; const shouldUpdate = - rowScroll >= rootProps.rowThreshold || - columnScroll >= rootProps.columnThreshold; + rowScroll >= rootProps.rowThreshold || columnScroll >= rootProps.columnThreshold; if (!shouldUpdate) { return previousContext.current; } const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current, scrollCache); + const [nextRenderContext, rawRenderContext] = computeRenderContext( + inputs, + scrollPosition.current, + scrollCache, + ); // Prevents batching render context changes ReactDOM.flushSync(() => { @@ -194,7 +199,11 @@ export const useGridVirtualScroller = () => { const forceUpdateRenderContext = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current, scrollCache); + const [nextRenderContext, rawRenderContext] = computeRenderContext( + inputs, + scrollPosition.current, + scrollCache, + ); updateRenderContext(nextRenderContext, rawRenderContext); }; @@ -469,7 +478,11 @@ export const useGridVirtualScroller = () => { useRunOnce(outerSize.width !== 0, () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [initialRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition.current, scrollCache); + const [initialRenderContext, rawRenderContext] = computeRenderContext( + inputs, + scrollPosition.current, + scrollCache, + ); updateRenderContext(initialRenderContext, rawRenderContext); apiRef.current.publishEvent('scrollPositionChange', { @@ -561,7 +574,11 @@ function inputsSelector( }; } -function computeRenderContext(inputs: RenderContextInputs, scrollPosition: ScrollPosition, scrollCache: ScrollCache) { +function computeRenderContext( + inputs: RenderContextInputs, + scrollPosition: ScrollPosition, + scrollCache: ScrollCache, +) { let renderContext: GridRenderContext; if (!inputs.enabled) { @@ -694,7 +711,7 @@ function deriveRenderContext( nextRenderContext: GridRenderContext, scrollCache: ScrollCache, ) { - const buffer = bufferForScrollCache(scrollCache) + const buffer = bufferForScrollCache(scrollCache); const [firstRowToRender, lastRowToRender] = getIndexesToRender({ firstIndex: nextRenderContext.firstRowIndex, @@ -810,7 +827,7 @@ function getIndexesToRender({ positions: number[]; }) { const firstPosition = positions[firstIndex] - bufferBefore; - const lastPosition = positions[lastIndex] + bufferAfter; + const lastPosition = positions[lastIndex] + bufferAfter; const firstIndexPadded = binarySearch(firstPosition, positions, { atStart: true, @@ -853,30 +870,31 @@ export function computeOffsetLeft( function directionForDelta(dx: number, dy: number) { if (dx === 0 && dy === 0) { - return ScrollDirection.NONE + return ScrollDirection.NONE; } + /* eslint-disable */ if (Math.abs(dy) >= Math.abs(dx)) { if (dy > 0) { - return ScrollDirection.DOWN + return ScrollDirection.DOWN; } else { - return ScrollDirection.UP + return ScrollDirection.UP; } } else { if (dx > 0) { - return ScrollDirection.RIGHT + return ScrollDirection.RIGHT; } else { - return ScrollDirection.LEFT + return ScrollDirection.LEFT; } } + /* eslint-enable */ } function bufferForScrollCache(scrollCache: ScrollCache) { - const direction = scrollCache.direction + const direction = scrollCache.direction; return { columnBefore: direction === ScrollDirection.LEFT ? scrollCache.buffer.left : 0, columnAfter: direction === ScrollDirection.RIGHT ? scrollCache.buffer.left : 0, rowBefore: direction === ScrollDirection.UP ? scrollCache.buffer.top : 0, rowAfter: direction === ScrollDirection.DOWN ? scrollCache.buffer.top : 0, - } + }; } - From 54564fb84bc84bb28be9e6ce0c28fb09ed357197 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 07:42:38 -0500 Subject: [PATCH 06/31] ci: run From 3d73f8fa79b65c36cccb556baebd47e6cc171bd8 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 20:20:52 -0500 Subject: [PATCH 07/31] feat: finish buffer changes --- docs/data/data-grid/demo/FullFeaturedDemo.js | 2 +- docs/data/data-grid/demo/FullFeaturedDemo.tsx | 2 +- .../master-detail/BasicDetailPanels.js | 2 +- .../master-detail/BasicDetailPanels.tsx | 2 +- .../BasicDetailPanels.tsx.preview | 2 +- .../master-detail/ControlMasterDetail.js | 2 +- .../master-detail/ControlMasterDetail.tsx | 2 +- .../CustomizeDetailPanelToggle.js | 2 +- .../CustomizeDetailPanelToggle.tsx | 2 +- .../CustomizeDetailPanelToggle.tsx.preview | 2 +- .../master-detail/DetailPanelAutoHeight.js | 2 +- .../master-detail/DetailPanelAutoHeight.tsx | 2 +- .../DetailPanelAutoHeight.tsx.preview | 2 +- .../master-detail/FormDetailPanel.js | 2 +- .../master-detail/FormDetailPanel.tsx | 2 +- .../master-detail/FormDetailPanel.tsx.preview | 2 +- .../master-detail/FullWidthDetailPanel.js | 2 +- .../master-detail/FullWidthDetailPanel.tsx | 2 +- .../FullWidthDetailPanel.tsx.preview | 2 +- .../data-grid/master-detail/master-detail.md | 4 +- .../ColumnVirtualizationGrid.js | 2 +- .../ColumnVirtualizationGrid.tsx | 2 +- .../ColumnVirtualizationGrid.tsx.preview | 2 +- .../src/DataGridPremium/DataGridPremium.tsx | 2 +- .../tests/columns.DataGridPremium.test.tsx | 2 +- .../src/DataGridPro/DataGridPro.tsx | 2 +- .../tests/detailPanel.DataGridPro.test.tsx | 4 +- .../src/tests/rows.DataGridPro.test.tsx | 48 +++++++------- .../src/DataGrid/useDataGridProps.ts | 4 +- .../virtualization/useGridVirtualScroller.tsx | 62 +++++++++---------- .../src/models/props/DataGridProps.ts | 8 +-- .../tests/columnSpanning.DataGrid.test.tsx | 32 +++++----- .../src/tests/keyboard.DataGrid.test.tsx | 4 +- .../src/tests/layout.DataGrid.test.tsx | 2 - .../src/tests/rows.DataGrid.test.tsx | 32 +++++----- .../DataGridPro/KeyboardNavigationFocus.tsx | 2 +- 36 files changed, 125 insertions(+), 127 deletions(-) diff --git a/docs/data/data-grid/demo/FullFeaturedDemo.js b/docs/data/data-grid/demo/FullFeaturedDemo.js index ef0717f61f405..345b15379170a 100644 --- a/docs/data/data-grid/demo/FullFeaturedDemo.js +++ b/docs/data/data-grid/demo/FullFeaturedDemo.js @@ -301,7 +301,7 @@ export default function FullFeaturedDemo() { loading={loading} checkboxSelection disableRowSelectionOnClick - rowThreshold={0} + rowThresholdPx={0} initialState={{ ...data.initialState, pinnedColumns: { left: [GRID_CHECKBOX_SELECTION_FIELD, 'desk'] }, diff --git a/docs/data/data-grid/demo/FullFeaturedDemo.tsx b/docs/data/data-grid/demo/FullFeaturedDemo.tsx index bb11d75390382..f751ee75a51f7 100644 --- a/docs/data/data-grid/demo/FullFeaturedDemo.tsx +++ b/docs/data/data-grid/demo/FullFeaturedDemo.tsx @@ -341,7 +341,7 @@ export default function FullFeaturedDemo() { loading={loading} checkboxSelection disableRowSelectionOnClick - rowThreshold={0} + rowThresholdPx={0} initialState={{ ...data.initialState, pinnedColumns: { left: [GRID_CHECKBOX_SELECTION_FIELD, 'desk'] }, diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.js b/docs/data/data-grid/master-detail/BasicDetailPanels.js index 20da411552c06..8800a3dfcaafa 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.js +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.js @@ -175,7 +175,7 @@ export default function BasicDetailPanels() { diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx index b9c17508bd5b5..124e8c3baaa7d 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx @@ -177,7 +177,7 @@ export default function BasicDetailPanels() { diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview index ea6bfcbf5f283..b7fa987a8071a 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/ControlMasterDetail.js b/docs/data/data-grid/master-detail/ControlMasterDetail.js index ac0e5159d101e..94cf33fbcdab4 100644 --- a/docs/data/data-grid/master-detail/ControlMasterDetail.js +++ b/docs/data/data-grid/master-detail/ControlMasterDetail.js @@ -29,7 +29,7 @@ export default function ControlMasterDetail() { ( {`Order #${row.id}`} )} diff --git a/docs/data/data-grid/master-detail/ControlMasterDetail.tsx b/docs/data/data-grid/master-detail/ControlMasterDetail.tsx index 77c09b13a4e4a..c6a0ab47e0dfb 100644 --- a/docs/data/data-grid/master-detail/ControlMasterDetail.tsx +++ b/docs/data/data-grid/master-detail/ControlMasterDetail.tsx @@ -37,7 +37,7 @@ export default function ControlMasterDetail() { ( {`Order #${row.id}`} )} diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js index af60da408ca75..219d08f790fb8 100644 --- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js +++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js @@ -30,7 +30,7 @@ export default function CustomizeDetailPanelToggle() { diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx index 4692667b60d5f..9f8741b90da4d 100644 --- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx +++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx @@ -34,7 +34,7 @@ export default function CustomizeDetailPanelToggle() { diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview index 953b7b32aa504..d77d462a20e9b 100644 --- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview +++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js index 6819a2be2b18b..542dc32e6f061 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js @@ -228,7 +228,7 @@ export default function DetailPanelAutoHeight() { diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx index dfe9d815e169f..68fdd16bd8ea7 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx @@ -234,7 +234,7 @@ export default function DetailPanelAutoHeight() { diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview index ea6bfcbf5f283..b7fa987a8071a 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.js b/docs/data/data-grid/master-detail/FormDetailPanel.js index ce6831835d533..17af82c4bd08f 100644 --- a/docs/data/data-grid/master-detail/FormDetailPanel.js +++ b/docs/data/data-grid/master-detail/FormDetailPanel.js @@ -131,7 +131,7 @@ export default function FormDetailPanel() { diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.tsx b/docs/data/data-grid/master-detail/FormDetailPanel.tsx index f202ae9ba07e4..4f470cb075401 100644 --- a/docs/data/data-grid/master-detail/FormDetailPanel.tsx +++ b/docs/data/data-grid/master-detail/FormDetailPanel.tsx @@ -139,7 +139,7 @@ export default function FormDetailPanel() { diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview b/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview index ea6bfcbf5f283..b7fa987a8071a 100644 --- a/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview +++ b/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js index 16bd2837aba38..e000c3f3dbed3 100644 --- a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js +++ b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js @@ -201,7 +201,7 @@ export default function FullWidthDetailPanel() { { ... }, []); Depending on the height of the detail panel, you may see a blank space when scrolling. This is caused by the data grid using a lazy approach to update the rendered rows. -Set `rowThreshold` to 0 to force new rows to be rendered more often to fill the blank space. +Set `rowThresholdPx` to a lower value to force new rows to be rendered more often to fill the blank space. Note that this may reduce the performance. ```tsx - + ``` ::: diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js index b789fd690dc4c..dac4a5294548a 100644 --- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js +++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js @@ -39,7 +39,7 @@ export default function ColumnVirtualizationGrid() { return (
- +
); } diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx index ef0aa8f4d8a9f..e800e31f0eea9 100644 --- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx +++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx @@ -49,7 +49,7 @@ export default function ColumnVirtualizationGrid() { return (
- +
); } diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview index 0fa5d537a93f7..aa775ae151718 100644 --- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview +++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 6bbdd2ae94e3e..cf353edb1b287 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -945,7 +945,7 @@ DataGridPremiumRaw.propTypes = { * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. * @default 3 */ - rowThreshold: PropTypes.number, + rowThresholdPx: PropTypes.number, /** * Override the height/width of the Data Grid inner scrollbar. */ diff --git a/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx index 14267f4ac7dca..63543419ab26c 100644 --- a/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx +++ b/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx @@ -32,7 +32,7 @@ describe(' - Columns', () => { columns={[{ field: 'brand' }]} initialState={{ aggregation: { model: { brand: 'size' } } }} showCellVerticalBorder - rowBuffer={1} + rowBufferPx={52} /> , ); diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index d28392f9721e6..56380af339c21 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -845,7 +845,7 @@ DataGridProRaw.propTypes = { * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. * @default 3 */ - rowThreshold: PropTypes.number, + rowThresholdPx: PropTypes.number, /** * Override the height/width of the Data Grid inner scrollbar. */ diff --git a/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx index 511e024d7b53f..60c1af46b6cd5 100644 --- a/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx @@ -59,8 +59,8 @@ describe(' - Detail panel', () => { getDetailPanelHeight={({ id }) => (Number(id) % 2 === 0 ? 1 : 2) * rowHeight} // 50px for even rows, otherwise 100px getDetailPanelContent={() =>
} rowHeight={rowHeight} - rowBuffer={0} - rowThreshold={0} + rowBufferPx={0} + rowThresholdPx={0} initialState={{ detailPanel: { expandedRowIds: [0, 1], diff --git a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx index ece96b663e629..2bc7445e31d6f 100644 --- a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx @@ -419,7 +419,7 @@ describe(' - Rows', () => { it('should compute rows correctly on height change', async () => { const { setProps } = render( - , + , ); expect(getRows()).to.have.length(1); setProps({ @@ -430,9 +430,10 @@ describe(' - Rows', () => { expect(getRows()).to.have.length(3); }); - it('should render last row when scrolling to the bottom', () => { + it('should render last row when scrolling to the bottom', async () => { + const n = 4; const rowHeight = 50; - const rowBuffer = 4; + const rowBufferPx = n * rowHeight; const nbRows = 996; const height = 600; render( @@ -440,7 +441,7 @@ describe(' - Rows', () => { nbRows={nbRows} columnHeaderHeight={0} rowHeight={rowHeight} - rowBuffer={rowBuffer} + rowBufferPx={rowBufferPx} hideFooter height={height} />, @@ -453,9 +454,7 @@ describe(' - Rows', () => { const lastCell = $$('[role="row"]:last-child [role="gridcell"]')[0]; expect(lastCell).to.have.text('995'); - expect(renderingZone.children.length).to.equal( - Math.floor((height - 1) / rowHeight) + rowBuffer, - ); // Subtracting 1 is needed because of the column header borders + expect(renderingZone.children.length).to.equal(Math.floor((height - 1) / rowHeight) + n); // Subtracting 1 is needed because of the column header borders const scrollbarSize = apiRef.current.state.dimensions.scrollbarSize; const distanceToFirstRow = (nbRows - renderingZone.children.length) * rowHeight; expect(gridOffsetTop()).to.equal(distanceToFirstRow); @@ -475,55 +474,62 @@ describe(' - Rows', () => { it('should render extra columns when the columnBuffer prop is present', () => { const border = 1; const width = 300; - const columnBuffer = 2; + const n = 2; const columnWidth = 100; + const columnBufferPx = n * columnWidth; render( , ); const firstRow = getRow(0); - expect($$(firstRow, '[role="gridcell"]')).to.have.length( - Math.floor(width / columnWidth) + columnBuffer, - ); + expect($$(firstRow, '[role="gridcell"]')).to.have.length(Math.floor(width / columnWidth) + n); const virtualScroller = document.querySelector('.MuiDataGrid-virtualScroller')!; virtualScroller.scrollLeft = 301; act(() => virtualScroller.dispatchEvent(new Event('scroll'))); expect($$(firstRow, '[role="gridcell"]')).to.have.length( - columnBuffer + 1 + Math.floor(width / columnWidth) + columnBuffer, + n + 1 + Math.floor(width / columnWidth) + n, ); }); - it('should render new rows when scrolling past the rowThreshold value', () => { - const rowThreshold = 3; + it('should render new rows when scrolling past the rowThresholdPx value', () => { const rowHeight = 50; + const rowThresholdPx = 3 * rowHeight; render( - , + , ); const virtualScroller = document.querySelector('.MuiDataGrid-virtualScroller')!; const renderingZone = document.querySelector('.MuiDataGrid-virtualScrollerRenderZone')!; let firstRow = renderingZone.firstChild; expect(firstRow).to.have.attr('data-rowindex', '0'); - virtualScroller.scrollTop = rowThreshold * rowHeight; + virtualScroller.scrollTop = rowThresholdPx; act(() => virtualScroller.dispatchEvent(new Event('scroll'))); firstRow = renderingZone.firstChild; expect(firstRow).to.have.attr('data-rowindex', '3'); }); - it('should render new columns when scrolling past the columnThreshold value', () => { - const columnThreshold = 3; + it('should render new columns when scrolling past the columnThresholdPx value', () => { const columnWidth = 100; + const columnThresholdPx = 3 * columnWidth; render( - , + , ); const virtualScroller = grid('virtualScroller')!; const renderingZone = grid('virtualScrollerRenderZone')!; const firstRow = $(renderingZone, '[role="row"]:first-child')!; let firstColumn = $$(firstRow, '[role="gridcell"]')[0]; expect(firstColumn).to.have.attr('data-colindex', '0'); - virtualScroller.scrollLeft = columnThreshold * columnWidth; + virtualScroller.scrollLeft = columnThresholdPx; act(() => virtualScroller.dispatchEvent(new Event('scroll'))); firstColumn = $(renderingZone, '[role="row"] > [role="gridcell"]')!; expect(firstColumn).to.have.attr('data-colindex', '3'); diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts index 070e6002d7219..c3c70e11bd750 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -34,8 +34,8 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { checkboxSelectionVisibleOnly: false, columnBufferPx: 150, rowBufferPx: 150, - columnThreshold: 150, - rowThreshold: 150, + columnThresholdPx: 150, + rowThresholdPx: 150, rowSelection: true, density: 'standard', disableColumnFilter: false, diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index be5b40ca17ea8..f50c401aff36a 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -176,7 +176,7 @@ export const useGridVirtualScroller = () => { Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.buffer.left; const shouldUpdate = - rowScroll >= rootProps.rowThreshold || columnScroll >= rootProps.columnThreshold; + rowScroll >= rootProps.rowThresholdPx || columnScroll >= rootProps.columnThresholdPx; if (!shouldUpdate) { return previousContext.current; @@ -538,6 +538,8 @@ type RenderContextInputs = { columnsTotalWidth: number; viewportInnerWidth: number; viewportInnerHeight: number; + lastRowHeight: number; + lastColumnWidth: number; rowsMeta: ReturnType; columnPositions: ReturnType; rows: ReturnType['rows']; @@ -554,6 +556,9 @@ function inputsSelector( ): RenderContextInputs { const dimensions = gridDimensionsSelector(apiRef.current.state); const currentPage = getVisibleRows(apiRef, rootProps); + const visibleColumns = gridVisibleColumnDefinitionsSelector(apiRef); + const lastRowId = apiRef.current.state.rows.dataRowIds.at(-1); + const lastColumn = visibleColumns.at(-1); return { enabled, enabledForColumns, @@ -565,12 +570,14 @@ function inputsSelector( columnsTotalWidth: dimensions.columnsTotalWidth, viewportInnerWidth: dimensions.viewportInnerSize.width, viewportInnerHeight: dimensions.viewportInnerSize.height, + lastRowHeight: lastRowId ? apiRef.current.unstable_getRowHeight(lastRowId) : 0, + lastColumnWidth: lastColumn?.computedWidth ?? 0, rowsMeta: gridRowsMetaSelector(apiRef.current.state), columnPositions: gridColumnPositionsSelector(apiRef), rows: currentPage.rows, range: currentPage.range, pinnedColumns: gridVisiblePinnedColumnDefinitionsSelector(apiRef), - visibleColumns: gridVisibleColumnDefinitionsSelector(apiRef), + visibleColumns, }; } @@ -617,6 +624,7 @@ function computeRenderContext( bufferBefore: inputs.rowBufferPx, bufferAfter: inputs.rowBufferPx, positions: inputs.rowsMeta.positions, + lastSize: inputs.lastRowHeight, }); for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) { @@ -644,18 +652,7 @@ function computeRenderContext( }; } - const actualRenderContext = deriveRenderContext( - inputs.apiRef, - inputs.rowBufferPx, - inputs.columnBufferPx, - inputs.rows, - inputs.rowsMeta.positions, - inputs.columnPositions, - inputs.pinnedColumns, - inputs.visibleColumns, - renderContext, - scrollCache, - ); + const actualRenderContext = deriveRenderContext(inputs, renderContext, scrollCache); return [actualRenderContext, renderContext]; } @@ -700,14 +697,7 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) { * spanning. */ function deriveRenderContext( - apiRef: React.MutableRefObject, - rowBufferPx: number, - columnBufferPx: number, - rows: ReturnType['rows'], - rowPositions: number[], - columnPositions: number[], - pinnedColumns: ReturnType, - visibleColumns: ReturnType, + inputs: RenderContextInputs, nextRenderContext: GridRenderContext, scrollCache: ScrollCache, ) { @@ -717,28 +707,30 @@ function deriveRenderContext( firstIndex: nextRenderContext.firstRowIndex, lastIndex: nextRenderContext.lastRowIndex, minFirstIndex: 0, - maxLastIndex: rows.length, - bufferBefore: rowBufferPx + buffer.rowBefore, - bufferAfter: rowBufferPx + buffer.rowAfter, - positions: rowPositions, + maxLastIndex: inputs.rows.length, + bufferBefore: inputs.rowBufferPx + buffer.rowBefore, + bufferAfter: inputs.rowBufferPx + buffer.rowAfter, + positions: inputs.rowsMeta.positions, + lastSize: inputs.lastRowHeight, }); const [initialFirstColumnToRender, lastColumnToRender] = getIndexesToRender({ firstIndex: nextRenderContext.firstColumnIndex, lastIndex: nextRenderContext.lastColumnIndex, - minFirstIndex: pinnedColumns.left.length, - maxLastIndex: visibleColumns.length - pinnedColumns.right.length, - bufferBefore: columnBufferPx + buffer.columnBefore, - bufferAfter: columnBufferPx + buffer.columnAfter, - positions: columnPositions, + minFirstIndex: inputs.pinnedColumns.left.length, + maxLastIndex: inputs.visibleColumns.length - inputs.pinnedColumns.right.length, + bufferBefore: inputs.columnBufferPx + buffer.columnBefore, + bufferAfter: inputs.columnBufferPx + buffer.columnAfter, + positions: inputs.columnPositions, + lastSize: inputs.lastColumnWidth, }); const firstColumnToRender = getFirstNonSpannedColumnToRender({ firstColumnToRender: initialFirstColumnToRender, - apiRef, + apiRef: inputs.apiRef, firstRowToRender, lastRowToRender, - visibleRows: rows, + visibleRows: inputs.rows, }); return { @@ -817,6 +809,7 @@ function getIndexesToRender({ minFirstIndex, maxLastIndex, positions, + lastSize, }: { firstIndex: number; lastIndex: number; @@ -825,13 +818,14 @@ function getIndexesToRender({ minFirstIndex: number; maxLastIndex: number; positions: number[]; + lastSize: number; }) { const firstPosition = positions[firstIndex] - bufferBefore; const lastPosition = positions[lastIndex] + bufferAfter; const firstIndexPadded = binarySearch(firstPosition, positions, { atStart: true, - lastPosition: positions[positions.length - 1] * 2, // Value doesn't matter much here, only need to be vastly superior + lastPosition: positions[positions.length - 1] + lastSize, }); const lastIndexPadded = binarySearch(lastPosition, positions); diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index 6683370c0da72..096bb7202c0d7 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -144,14 +144,14 @@ export interface DataGridPropsWithDefaultValues { rowSelection: boolean; /** * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ - rowThreshold: number; + rowThresholdPx: number; /** * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ - columnThreshold: number; + columnThresholdPx: number; /** * Set the density of the Data Grid. * @default "standard" diff --git a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx index 64f340d1b00f7..3ef82ad64369a 100644 --- a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx @@ -312,8 +312,8 @@ describe(' - Column spanning', () => { { field: 'price' }, ]} rows={rows} - rowBuffer={1} - rowThreshold={1} + rowBufferPx={rowHeight} + rowThresholdPx={rowHeight} rowHeight={rowHeight} />
, @@ -348,8 +348,8 @@ describe(' - Column spanning', () => { { field: 'col3', width: 100 }, ]} rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3' }]} - columnBufferPx={1} - columnThreshold={1} + columnBufferPx={100} + columnThresholdPx={100} /> , ); @@ -456,8 +456,8 @@ describe(' - Column spanning', () => { { field: 'col4', width: 100 }, ]} rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3', col4: '0-4' }]} - columnBufferPx={1} - columnThreshold={1} + columnBufferPx={100} + columnThresholdPx={100} /> , ); @@ -743,8 +743,8 @@ describe(' - Column spanning', () => { { id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3', col4: '0-4', col5: '0-5' }, { id: 1, col0: '1-0', col1: '1-1', col2: '1-2', col3: '1-3', col4: '1-4', col5: '1-5' }, ]} - columnBuffer={1} - columnThreshold={1} + columnBufferPx={100} + columnThresholdPx={100} /> , ); @@ -803,10 +803,10 @@ describe(' - Column spanning', () => { { id: 5, col0: '5-0', col1: '5-1', col2: '5-2', col3: '5-3', col4: '5-4', col5: '5-5' }, { id: 6, col0: '6-0', col1: '6-1', col2: '6-2', col3: '6-3', col4: '6-4', col5: '6-5' }, ]} - columnBuffer={1} - columnThreshold={1} - rowBuffer={1} - rowThreshold={1} + columnBufferPx={100} + columnThresholdPx={100} + rowBufferPx={50} + rowThresholdPx={50} rowHeight={rowHeight} /> , @@ -918,10 +918,10 @@ describe(' - Column spanning', () => { col5: '5-5', }, ]} - columnBuffer={1} - columnThreshold={1} - rowBuffer={1} - rowThreshold={1} + columnBufferPx={100} + columnThresholdPx={100} + rowBufferPx={50} + rowThresholdPx={50} rowHeight={rowHeight} /> diff --git a/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx b/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx index 2f27606d0c3ea..3e3ebce72f00a 100644 --- a/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx @@ -50,7 +50,7 @@ describe(' - Keyboard', () => { columns={transformColSizes(data.columns)} initialState={{ pagination: { paginationModel: { pageSize: PAGE_SIZE } } }} pageSizeOptions={[PAGE_SIZE]} - rowBuffer={PAGE_SIZE} + rowBufferPx={PAGE_SIZE * ROW_HEIGHT} rowHeight={ROW_HEIGHT} columnHeaderHeight={HEADER_HEIGHT} hideFooter @@ -478,7 +478,7 @@ describe(' - Keyboard', () => { columns={transformColSizes(data.columns)} paginationModel={{ pageSize: PAGE_SIZE, page: 0 }} pageSizeOptions={[PAGE_SIZE]} - rowBuffer={PAGE_SIZE} + rowBufferPx={PAGE_SIZE * ROW_HEIGHT} rowHeight={ROW_HEIGHT} columnHeaderHeight={HEADER_HEIGHT} hideFooter diff --git a/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx b/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx index 52b7342ccb617..468d5709d28a4 100644 --- a/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx @@ -1202,8 +1202,6 @@ describe(' - Layout & warnings', () => { }).toErrorDev([ 'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.', 'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.', - 'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.', - 'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.', ]); }); diff --git a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx index 0056600086a73..cb9965653e9be 100644 --- a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx @@ -663,7 +663,7 @@ describe(' - Rows', () => { height={columnHeaderHeight + 20 + border * 2} // Force to only measure the first row getBioContentHeight={() => measuredRowHeight} getRowHeight={() => 'auto'} - rowBuffer={0} + rowBufferPx={0} />, ); const virtualScrollerContent = document.querySelector( @@ -693,7 +693,7 @@ describe(' - Rows', () => { getBioContentHeight={() => measuredRowHeight} getEstimatedRowHeight={() => estimatedRowHeight} getRowHeight={() => 'auto'} - rowBuffer={0} + rowBufferPx={0} />, ); const virtualScrollerContent = document.querySelector( @@ -716,7 +716,7 @@ describe(' - Rows', () => { getBioContentHeight={(row) => (row.expanded ? 200 : 100)} rows={[{ clientId: 'c1', expanded: false }]} getRowHeight={() => 'auto'} - rowBuffer={0} + rowBufferPx={0} />, ); const virtualScrollerContent = document.querySelector( @@ -742,7 +742,7 @@ describe(' - Rows', () => { 50} getRowHeight={({ id }) => (id === 'c3' ? 100 : 'auto')} - rowBuffer={0} + rowBufferPx={0} />, ); expect(getRow(0)).toHaveInlineStyle({ minHeight: 'auto' }); @@ -756,8 +756,8 @@ describe(' - Rows', () => { rows={baselineProps.rows.slice(0, 1)} getBioContentHeight={() => 100} getRowHeight={() => 'auto'} - columnBuffer={0} - columnThreshold={0} + columnBufferPx={0} + columnThresholdPx={0} width={100} />, ); @@ -771,8 +771,8 @@ describe(' - Rows', () => { 100} getRowHeight={() => 'auto'} - rowBuffer={0} - rowThreshold={0} + rowBufferPx={0} + rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} height={columnHeaderHeight + 52 + border * 2} />, @@ -807,8 +807,8 @@ describe(' - Rows', () => { getRowHeight={({ id }) => (id === 'c1' ? 'auto' : null)} density="comfortable" rows={baselineProps.rows.slice(0, 2)} - rowBuffer={0} - rowThreshold={0} + rowBufferPx={0} + rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} />, ); @@ -835,8 +835,8 @@ describe(' - Rows', () => { measuredRowHeight} getRowHeight={() => 'auto'} - rowBuffer={0} - rowThreshold={0} + rowBufferPx={0} + rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} getRowId={(row) => row.id} hideFooter={false} @@ -863,8 +863,8 @@ describe(' - Rows', () => { measuredRowHeight} getRowHeight={() => 'auto'} - rowBuffer={0} - rowThreshold={0} + rowBufferPx={0} + rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} getRowId={(row) => row.id} hideFooter={false} @@ -892,8 +892,8 @@ describe(' - Rows', () => { measuredRowHeight} getRowHeight={() => 'auto'} - rowBuffer={0} - rowThreshold={0} + rowBufferPx={0} + rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} getRowId={(row) => row.id} hideFooter={false} diff --git a/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx b/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx index fa9f918881536..6732fb9c457b7 100644 --- a/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx +++ b/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx @@ -13,7 +13,7 @@ export default function KeyboardNavigationFocus() { initial focus
- +
); From 272ae192b4d366449a9d108e75499e32235ac937 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 20:27:04 -0500 Subject: [PATCH 08/31] doc: update guide --- .../migration-data-grid-v6/migration-data-grid-v6.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md index 3ce5734605a16..f11256f65e2d4 100644 --- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md +++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md @@ -106,9 +106,10 @@ As a result, the following changes have been made: - Pinned row and column sections are now contained in the virtual scroller. - The cell inner wrapper `.MuiDataGrid-cellContent` has been removed. - +- The props `rowBuffer`, `columnBuffer`, `rowThreshold` and `columnThreshold` were renamed to `rowBufferPx`, `columnBufferPx`, `rowThresholdPx` and `columnThresholdPx`. + Their value is now a pixel value rather than a number of items. Their default value is now `150`. ### Removed props From f49842e6ea11846c0195265eb678e2a973749c6c Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 20:39:17 -0500 Subject: [PATCH 09/31] lint --- .../src/hooks/features/virtualization/useGridVirtualScroller.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index f50c401aff36a..92bf6590ad970 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -56,7 +56,6 @@ const EMPTY_SCROLL_CACHE = { lastTimestamp: -1, lastPosition: { top: 0, left: 0 }, buffer: { top: 0, left: 0 }, - events: [] as ({ top: number; left: number; timestamp: number } & Record)[], }; type ScrollCache = typeof EMPTY_SCROLL_CACHE; From 7a5cb7baa760362bf2072cf002d86bc1b515f841 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 20:44:49 -0500 Subject: [PATCH 10/31] lint --- .../hooks/features/virtualization/useGridVirtualScroller.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 92bf6590ad970..5c0a0f953e17b 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -4,6 +4,7 @@ import { unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, } from '@mui/utils'; +import useLazyRef from '@mui/utils/useLazyRef'; import { useTheme, Theme } from '@mui/material/styles'; import { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; @@ -59,6 +60,8 @@ const EMPTY_SCROLL_CACHE = { }; type ScrollCache = typeof EMPTY_SCROLL_CACHE; +const createScrollCache = () => ({ ...EMPTY_SCROLL_CACHE }) + export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext(); const rootProps = useGridRootProps(); @@ -96,7 +99,7 @@ export const useGridVirtualScroller = () => { const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const prevTotalWidth = React.useRef(columnsTotalWidth); - const scrollCache = React.useRef({ ...EMPTY_SCROLL_CACHE }).current; + const scrollCache = useLazyRef(createScrollCache).current; const focusedCell = { rowIndex: React.useMemo( From 3d69375be8cd5396dbae9b1bd31982659e9ed74b Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 20:51:03 -0500 Subject: [PATCH 11/31] lint --- .../hooks/features/virtualization/useGridVirtualScroller.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 5c0a0f953e17b..5e8c3ee6c8ba7 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -60,7 +60,7 @@ const EMPTY_SCROLL_CACHE = { }; type ScrollCache = typeof EMPTY_SCROLL_CACHE; -const createScrollCache = () => ({ ...EMPTY_SCROLL_CACHE }) +const createScrollCache = () => ({ ...EMPTY_SCROLL_CACHE }); export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext(); From 1a8f08ddd9d07fb71e513e7637bc54e478346425 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 8 Mar 2024 20:57:20 -0500 Subject: [PATCH 12/31] lint --- .../x/api/data-grid/data-grid-premium.json | 8 ++++---- docs/pages/x/api/data-grid/data-grid-pro.json | 8 ++++---- docs/pages/x/api/data-grid/data-grid.json | 8 ++++---- .../data-grid-premium/data-grid-premium.json | 12 ++++------- .../data-grid-pro/data-grid-pro.json | 12 ++++------- .../data-grid/data-grid/data-grid.json | 12 ++++------- .../src/DataGridPremium/DataGridPremium.tsx | 18 ++++++++--------- .../src/DataGridPro/DataGridPro.tsx | 18 ++++++++--------- .../x-data-grid/src/DataGrid/DataGrid.tsx | 20 +++++++++---------- 9 files changed, 52 insertions(+), 64 deletions(-) diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index f6aab9649ea01..02a590742f9df 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -36,9 +36,9 @@ "checkboxSelectionVisibleOnly": { "type": { "name": "bool" }, "default": "false" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, - "columnBuffer": { "type": { "name": "number" }, "default": "3" }, + "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, - "columnThreshold": { "type": { "name": "number" }, "default": "3" }, + "columnThresholdPx": { "type": { "name": "number" }, "default": "150" }, "columnVisibilityModel": { "type": { "name": "object" } }, "defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" }, "density": { @@ -541,7 +541,7 @@ "returned": "Promise | R" } }, - "rowBuffer": { "type": { "name": "number" }, "default": "3" }, + "rowBufferPx": { "type": { "name": "number" }, "default": "100" }, "rowCount": { "type": { "name": "number" } }, "rowGroupingColumnMode": { "type": { "name": "enum", "description": "'multiple'
| 'single'" }, @@ -566,7 +566,7 @@ "type": { "name": "enum", "description": "'border'
| 'margin'" }, "default": "\"margin\"" }, - "rowThreshold": { "type": { "name": "number" }, "default": "3" }, + "rowThresholdPx": { "type": { "name": "number" }, "default": "150" }, "scrollbarSize": { "type": { "name": "number" } }, "scrollEndThreshold": { "type": { "name": "number" }, "default": "80" }, "showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 0ae775c41b774..9116bc9350fe7 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -25,9 +25,9 @@ "checkboxSelectionVisibleOnly": { "type": { "name": "bool" }, "default": "false" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, - "columnBuffer": { "type": { "name": "number" }, "default": "3" }, + "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, - "columnThreshold": { "type": { "name": "number" }, "default": "3" }, + "columnThresholdPx": { "type": { "name": "number" }, "default": "150" }, "columnVisibilityModel": { "type": { "name": "object" } }, "defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" }, "density": { @@ -488,7 +488,7 @@ "returned": "Promise | R" } }, - "rowBuffer": { "type": { "name": "number" }, "default": "3" }, + "rowBufferPx": { "type": { "name": "number" }, "default": "100" }, "rowCount": { "type": { "name": "number" } }, "rowHeight": { "type": { "name": "number" }, "default": "52" }, "rowModesModel": { "type": { "name": "object" } }, @@ -508,7 +508,7 @@ "type": { "name": "enum", "description": "'border'
| 'margin'" }, "default": "\"margin\"" }, - "rowThreshold": { "type": { "name": "number" }, "default": "3" }, + "rowThresholdPx": { "type": { "name": "number" }, "default": "150" }, "scrollbarSize": { "type": { "name": "number" } }, "scrollEndThreshold": { "type": { "name": "number" }, "default": "80" }, "showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 6daecb51bd8aa..2d5b0c5438a37 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -17,9 +17,9 @@ "checkboxSelection": { "type": { "name": "bool" }, "default": "false" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, - "columnBuffer": { "type": { "name": "number" }, "default": "3" }, + "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, - "columnThreshold": { "type": { "name": "number" }, "default": "3" }, + "columnThresholdPx": { "type": { "name": "number" }, "default": "150" }, "columnVisibilityModel": { "type": { "name": "object" } }, "density": { "type": { @@ -379,7 +379,7 @@ "returned": "Promise | R" } }, - "rowBuffer": { "type": { "name": "number" }, "default": "3" }, + "rowBufferPx": { "type": { "name": "number" }, "default": "100" }, "rowCount": { "type": { "name": "number" } }, "rowHeight": { "type": { "name": "number" }, "default": "52" }, "rowModesModel": { "type": { "name": "object" } }, @@ -395,7 +395,7 @@ "type": { "name": "enum", "description": "'border'
| 'margin'" }, "default": "\"margin\"" }, - "rowThreshold": { "type": { "name": "number" }, "default": "3" }, + "rowThresholdPx": { "type": { "name": "number" }, "default": "150" }, "scrollbarSize": { "type": { "name": "number" } }, "showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, "showColumnVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index c7931fb45627c..1a36c27ad641e 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -36,16 +36,14 @@ "clipboardCopyCellDelimiter": { "description": "The character used to separate cell values when copying to the clipboard." }, - "columnBuffer": { - "description": "Number of extra columns to be rendered before/after the visible slice." - }, + "columnBufferPx": { "description": "Column region to render before/after the viewport" }, "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, "columns": { "description": "Set of columns of type GridColDef[]." }, - "columnThreshold": { + "columnThresholdPx": { "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { @@ -566,9 +564,7 @@ "Promise | R": "The final values to update the row." } }, - "rowBuffer": { - "description": "Number of extra rows to be rendered before/after the visible slice." - }, + "rowBufferPx": { "description": "Row region to render before/after the viewport" }, "rowCount": { "description": "Set the total number of rows, if it is different from the length of the value rows prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows." }, @@ -591,7 +587,7 @@ "rowSpacingType": { "description": "Sets the type of space between rows added by getRowSpacing." }, - "rowThreshold": { + "rowThresholdPx": { "description": "Number of rows from the rowBuffer that can be visible before a new slice is rendered." }, "scrollbarSize": { diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index 7e08ead8fa2d5..02dd0ff054695 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -29,16 +29,14 @@ "clipboardCopyCellDelimiter": { "description": "The character used to separate cell values when copying to the clipboard." }, - "columnBuffer": { - "description": "Number of extra columns to be rendered before/after the visible slice." - }, + "columnBufferPx": { "description": "Column region to render before/after the viewport" }, "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, "columns": { "description": "Set of columns of type GridColDef[]." }, - "columnThreshold": { + "columnThresholdPx": { "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { @@ -516,9 +514,7 @@ "Promise | R": "The final values to update the row." } }, - "rowBuffer": { - "description": "Number of extra rows to be rendered before/after the visible slice." - }, + "rowBufferPx": { "description": "Row region to render before/after the viewport" }, "rowCount": { "description": "Set the total number of rows, if it is different from the length of the value rows prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows." }, @@ -537,7 +533,7 @@ "rowSpacingType": { "description": "Sets the type of space between rows added by getRowSpacing." }, - "rowThreshold": { + "rowThresholdPx": { "description": "Number of rows from the rowBuffer that can be visible before a new slice is rendered." }, "scrollbarSize": { diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index a805b4dea7ea2..6cb6c8f22b67a 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -22,16 +22,14 @@ "clipboardCopyCellDelimiter": { "description": "The character used to separate cell values when copying to the clipboard." }, - "columnBuffer": { - "description": "Number of extra columns to be rendered before/after the visible slice." - }, + "columnBufferPx": { "description": "Column region to render before/after the viewport" }, "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, "columns": { "description": "Set of columns of type GridColDef[]." }, - "columnThreshold": { + "columnThresholdPx": { "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { @@ -395,9 +393,7 @@ "Promise | R": "The final values to update the row." } }, - "rowBuffer": { - "description": "Number of extra rows to be rendered before/after the visible slice." - }, + "rowBufferPx": { "description": "Row region to render before/after the viewport" }, "rowCount": { "description": "Set the total number of rows, if it is different from the length of the value rows prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows." }, @@ -412,7 +408,7 @@ "rowSpacingType": { "description": "Sets the type of space between rows added by getRowSpacing." }, - "rowThreshold": { + "rowThresholdPx": { "description": "Number of rows from the rowBuffer that can be visible before a new slice is rendered." }, "scrollbarSize": { diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index cf353edb1b287..3077c738c711e 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -171,10 +171,10 @@ DataGridPremiumRaw.propTypes = { */ clipboardCopyCellDelimiter: PropTypes.string, /** - * Number of extra columns to be rendered before/after the visible slice. - * @default 3 + * Column region to render before/after the viewport + * @default 100 */ - columnBuffer: PropTypes.number, + columnBufferPx: PropTypes.number, columnGroupingModel: PropTypes.arrayOf(PropTypes.object), /** * Sets the height in pixel of the column headers in the Data Grid. @@ -187,9 +187,9 @@ DataGridPremiumRaw.propTypes = { columns: PropTypes.arrayOf(PropTypes.object).isRequired, /** * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ - columnThreshold: PropTypes.number, + columnThresholdPx: PropTypes.number, /** * Set the column visibility model of the Data Grid. * If defined, the Data Grid will ignore the `hide` property in [[GridColDef]]. @@ -872,10 +872,10 @@ DataGridPremiumRaw.propTypes = { */ processRowUpdate: PropTypes.func, /** - * Number of extra rows to be rendered before/after the visible slice. - * @default 3 + * Row region to render before/after the viewport + * @default 100 */ - rowBuffer: PropTypes.number, + rowBufferPx: PropTypes.number, /** * Set the total number of rows, if it is different from the length of the value `rows` prop. * If some rows have children (for instance in the tree data), this number represents the amount of top level rows. @@ -943,7 +943,7 @@ DataGridPremiumRaw.propTypes = { rowSpacingType: PropTypes.oneOf(['border', 'margin']), /** * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ rowThresholdPx: PropTypes.number, /** diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 56380af339c21..26e50622f2b79 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -134,10 +134,10 @@ DataGridProRaw.propTypes = { */ clipboardCopyCellDelimiter: PropTypes.string, /** - * Number of extra columns to be rendered before/after the visible slice. - * @default 3 + * Column region to render before/after the viewport + * @default 100 */ - columnBuffer: PropTypes.number, + columnBufferPx: PropTypes.number, columnGroupingModel: PropTypes.arrayOf(PropTypes.object), /** * Sets the height in pixel of the column headers in the Data Grid. @@ -150,9 +150,9 @@ DataGridProRaw.propTypes = { columns: PropTypes.arrayOf(PropTypes.object).isRequired, /** * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ - columnThreshold: PropTypes.number, + columnThresholdPx: PropTypes.number, /** * Set the column visibility model of the Data Grid. * If defined, the Data Grid will ignore the `hide` property in [[GridColDef]]. @@ -782,10 +782,10 @@ DataGridProRaw.propTypes = { */ processRowUpdate: PropTypes.func, /** - * Number of extra rows to be rendered before/after the visible slice. - * @default 3 + * Row region to render before/after the viewport + * @default 100 */ - rowBuffer: PropTypes.number, + rowBufferPx: PropTypes.number, /** * Set the total number of rows, if it is different from the length of the value `rows` prop. * If some rows have children (for instance in the tree data), this number represents the amount of top level rows. @@ -843,7 +843,7 @@ DataGridProRaw.propTypes = { rowSpacingType: PropTypes.oneOf(['border', 'margin']), /** * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ rowThresholdPx: PropTypes.number, /** diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 1d57912613e9e..478e6b9ce3193 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -120,10 +120,10 @@ DataGridRaw.propTypes = { */ clipboardCopyCellDelimiter: PropTypes.string, /** - * Number of extra columns to be rendered before/after the visible slice. - * @default 3 + * Column region to render before/after the viewport + * @default 100 */ - columnBuffer: PropTypes.number, + columnBufferPx: PropTypes.number, columnGroupingModel: PropTypes.arrayOf(PropTypes.object), /** * Sets the height in pixel of the column headers in the Data Grid. @@ -136,9 +136,9 @@ DataGridRaw.propTypes = { columns: PropTypes.arrayOf(PropTypes.object).isRequired, /** * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ - columnThreshold: PropTypes.number, + columnThresholdPx: PropTypes.number, /** * Set the column visibility model of the Data Grid. * If defined, the Data Grid will ignore the `hide` property in [[GridColDef]]. @@ -609,10 +609,10 @@ DataGridRaw.propTypes = { */ processRowUpdate: PropTypes.func, /** - * Number of extra rows to be rendered before/after the visible slice. - * @default 3 + * Row region to render before/after the viewport + * @default 100 */ - rowBuffer: PropTypes.number, + rowBufferPx: PropTypes.number, /** * Set the total number of rows, if it is different from the length of the value `rows` prop. * If some rows have children (for instance in the tree data), this number represents the amount of top level rows. @@ -658,9 +658,9 @@ DataGridRaw.propTypes = { rowSpacingType: PropTypes.oneOf(['border', 'margin']), /** * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 3 + * @default 150 */ - rowThreshold: PropTypes.number, + rowThresholdPx: PropTypes.number, /** * Override the height/width of the Data Grid inner scrollbar. */ From 239c5121f613ea4d3bfc4c1e8d8b7b2be47b574f Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Sun, 10 Mar 2024 20:35:58 -0400 Subject: [PATCH 13/31] feat: render context rework --- .../data-grid-premium/data-grid-premium.json | 10 +- .../data-grid-pro/data-grid-pro.json | 10 +- .../data-grid/data-grid/data-grid.json | 10 +- .../src/DataGridPremium/DataGridPremium.tsx | 8 +- .../src/DataGridPro/DataGridPro.tsx | 8 +- .../x-data-grid/src/DataGrid/DataGrid.tsx | 8 +- .../virtualization/useGridVirtualScroller.tsx | 180 ++++++++++++------ .../src/models/props/DataGridProps.ts | 8 +- 8 files changed, 161 insertions(+), 81 deletions(-) diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index 03527395087ca..8d3249c0bcafc 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -36,7 +36,9 @@ "clipboardCopyCellDelimiter": { "description": "The character used to separate cell values when copying to the clipboard." }, - "columnBufferPx": { "description": "Column region to render before/after the viewport" }, + "columnBufferPx": { + "description": "Column region in pixels to render before/after the viewport" + }, "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, @@ -44,7 +46,7 @@ "description": "Set of columns of type GridColDef[]." }, "columnThresholdPx": { - "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." + "description": "Number of pixels from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." @@ -568,7 +570,7 @@ "Promise | R": "The final values to update the row." } }, - "rowBufferPx": { "description": "Row region to render before/after the viewport" }, + "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" }, "rowCount": { "description": "Set the total number of rows, if it is different from the length of the value rows prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows." }, @@ -592,7 +594,7 @@ "description": "Sets the type of space between rows added by getRowSpacing." }, "rowThresholdPx": { - "description": "Number of rows from the rowBuffer that can be visible before a new slice is rendered." + "description": "Number of pixels from the rowBuffer that can be visible before a new slice is rendered." }, "scrollbarSize": { "description": "Override the height/width of the Data Grid inner scrollbar." diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index c5f765488e311..94875544d533b 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -29,7 +29,9 @@ "clipboardCopyCellDelimiter": { "description": "The character used to separate cell values when copying to the clipboard." }, - "columnBufferPx": { "description": "Column region to render before/after the viewport" }, + "columnBufferPx": { + "description": "Column region in pixels to render before/after the viewport" + }, "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, @@ -37,7 +39,7 @@ "description": "Set of columns of type GridColDef[]." }, "columnThresholdPx": { - "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." + "description": "Number of pixels from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." @@ -518,7 +520,7 @@ "Promise | R": "The final values to update the row." } }, - "rowBufferPx": { "description": "Row region to render before/after the viewport" }, + "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" }, "rowCount": { "description": "Set the total number of rows, if it is different from the length of the value rows prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows." }, @@ -538,7 +540,7 @@ "description": "Sets the type of space between rows added by getRowSpacing." }, "rowThresholdPx": { - "description": "Number of rows from the rowBuffer that can be visible before a new slice is rendered." + "description": "Number of pixels from the rowBuffer that can be visible before a new slice is rendered." }, "scrollbarSize": { "description": "Override the height/width of the Data Grid inner scrollbar." diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index b98a12fc53fee..10583256dea30 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -22,7 +22,9 @@ "clipboardCopyCellDelimiter": { "description": "The character used to separate cell values when copying to the clipboard." }, - "columnBufferPx": { "description": "Column region to render before/after the viewport" }, + "columnBufferPx": { + "description": "Column region in pixels to render before/after the viewport" + }, "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, @@ -30,7 +32,7 @@ "description": "Set of columns of type GridColDef[]." }, "columnThresholdPx": { - "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." + "description": "Number of pixels from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." @@ -397,7 +399,7 @@ "Promise | R": "The final values to update the row." } }, - "rowBufferPx": { "description": "Row region to render before/after the viewport" }, + "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" }, "rowCount": { "description": "Set the total number of rows, if it is different from the length of the value rows prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows." }, @@ -413,7 +415,7 @@ "description": "Sets the type of space between rows added by getRowSpacing." }, "rowThresholdPx": { - "description": "Number of rows from the rowBuffer that can be visible before a new slice is rendered." + "description": "Number of pixels from the rowBuffer that can be visible before a new slice is rendered." }, "scrollbarSize": { "description": "Override the height/width of the Data Grid inner scrollbar." diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 15cd7f9f8ff23..18543e4762acc 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -171,7 +171,7 @@ DataGridPremiumRaw.propTypes = { */ clipboardCopyCellDelimiter: PropTypes.string, /** - * Column region to render before/after the viewport + * Column region in pixels to render before/after the viewport * @default 100 */ columnBufferPx: PropTypes.number, @@ -186,7 +186,7 @@ DataGridPremiumRaw.propTypes = { */ columns: PropTypes.arrayOf(PropTypes.object).isRequired, /** - * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. * @default 150 */ columnThresholdPx: PropTypes.number, @@ -877,7 +877,7 @@ DataGridPremiumRaw.propTypes = { */ processRowUpdate: PropTypes.func, /** - * Row region to render before/after the viewport + * Row region in pixels to render before/after the viewport * @default 100 */ rowBufferPx: PropTypes.number, @@ -947,7 +947,7 @@ DataGridPremiumRaw.propTypes = { */ rowSpacingType: PropTypes.oneOf(['border', 'margin']), /** - * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. * @default 150 */ rowThresholdPx: PropTypes.number, diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 81ce4add89b50..2addc9871cc4d 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -134,7 +134,7 @@ DataGridProRaw.propTypes = { */ clipboardCopyCellDelimiter: PropTypes.string, /** - * Column region to render before/after the viewport + * Column region in pixels to render before/after the viewport * @default 100 */ columnBufferPx: PropTypes.number, @@ -149,7 +149,7 @@ DataGridProRaw.propTypes = { */ columns: PropTypes.arrayOf(PropTypes.object).isRequired, /** - * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. * @default 150 */ columnThresholdPx: PropTypes.number, @@ -787,7 +787,7 @@ DataGridProRaw.propTypes = { */ processRowUpdate: PropTypes.func, /** - * Row region to render before/after the viewport + * Row region in pixels to render before/after the viewport * @default 100 */ rowBufferPx: PropTypes.number, @@ -847,7 +847,7 @@ DataGridProRaw.propTypes = { */ rowSpacingType: PropTypes.oneOf(['border', 'margin']), /** - * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. * @default 150 */ rowThresholdPx: PropTypes.number, diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 393dd0626739f..2075dd504556d 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -120,7 +120,7 @@ DataGridRaw.propTypes = { */ clipboardCopyCellDelimiter: PropTypes.string, /** - * Column region to render before/after the viewport + * Column region in pixels to render before/after the viewport * @default 100 */ columnBufferPx: PropTypes.number, @@ -135,7 +135,7 @@ DataGridRaw.propTypes = { */ columns: PropTypes.arrayOf(PropTypes.object).isRequired, /** - * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. * @default 150 */ columnThresholdPx: PropTypes.number, @@ -614,7 +614,7 @@ DataGridRaw.propTypes = { */ processRowUpdate: PropTypes.func, /** - * Row region to render before/after the viewport + * Row region in pixels to render before/after the viewport * @default 100 */ rowBufferPx: PropTypes.number, @@ -662,7 +662,7 @@ DataGridRaw.propTypes = { */ rowSpacingType: PropTypes.oneOf(['border', 'margin']), /** - * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. * @default 150 */ rowThresholdPx: PropTypes.number, diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 05051a065ed55..699bbad4647c4 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -4,7 +4,7 @@ import { unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, } from '@mui/utils'; -import useLazyRef from '@mui/utils/useLazyRef'; +import useTimeout from '@mui/utils/useTimeout'; import { useTheme, Theme } from '@mui/material/styles'; import type { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; @@ -45,6 +45,7 @@ interface PrivateApiWithInfiniteLoader export type VirtualScroller = ReturnType; +type ScrollPosition = { top: number; left: number }; enum ScrollDirection { NONE, UP, @@ -59,14 +60,10 @@ export const EMPTY_DETAIL_PANELS = Object.freeze(new Map ({ ...EMPTY_SCROLL_CACHE }); - export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext() as React.MutableRefObject; const rootProps = useGridRootProps(); @@ -97,14 +94,29 @@ export const useGridVirtualScroller = () => { useResizeObserver(mainRef, () => apiRef.current.resize()); - const previousScroll = React.useRef(EMPTY_SCROLL_POSITION); + /* + * Scroll context logic + * ==================== + * We only render the cells contained in the `renderContext`. However, when the user starts scrolling the grid + * in a direction, we want to render as many cells as possible in that direction, as to avoid presenting white + * areas if the user scrolls too fast/far and the viewport ends up in a region we haven't rendered yet. To render + * more cells, we store some offsets to add to the viewport in `scrollCache.buffer`. Those offsets make the render + * context wider in the direction the user is going, but also makes the buffer around the viewport `0` for the + * dimension (horizontal or vertical) in which the user is not scrolling. So if the normal viewport is 8 columns + * wide, with a 1 column buffer (10 columns total), then we want it to be exactly 8 columns wide during vertical + * scroll. + * However, we don't want the rows in the old context to re-render from e.g. 10 columns to 8 columns, because that's + * work that's not necessary. Thus we store the context at the start of the scroll in `frozenContext`, and the rows + * that are part of this old context will keep their same render context as to avoid re-rendering. + */ + const currentScroll = React.useRef(EMPTY_SCROLL_POSITION); const previousContext = React.useRef(EMPTY_RENDER_CONTEXT); + const previousContextScrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const previousRowContext = React.useRef(EMPTY_RENDER_CONTEXT); const renderContext = useGridSelector(apiRef, gridRenderContextSelector); - const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION); - const prevTotalWidth = React.useRef(columnsTotalWidth); - - const scrollCache = useLazyRef(createScrollCache).current; + const scrollTimeout = useTimeout(); + const frozenContext = React.useRef(undefined); + const scrollCache = React.useRef(EMPTY_SCROLL_CACHE); const focusedCell = { rowIndex: React.useMemo( @@ -148,52 +160,94 @@ export const useGridVirtualScroller = () => { apiRef.current.publishEvent('renderedRowsIntervalChange', nextRenderContext); } - previousScroll.current = scrollPosition.current; + previousContextScrollPosition.current = currentScroll.current; previousContext.current = rawRenderContext; - prevTotalWidth.current = dimensions.columnsTotalWidth; }, - [apiRef, dimensions.isReady, dimensions.columnsTotalWidth], + [apiRef, dimensions.isReady], ); const triggerUpdateRenderContext = () => { - const timestamp = performance.now(); - const dt = timestamp - scrollCache.lastTimestamp; - const isScrolling = scrollCache.lastTimestamp !== -1 && dt < 500; + const newScroll = { + top: scrollerRef.current!.scrollTop, + left: scrollerRef.current!.scrollLeft, + }; - scrollCache.lastTimestamp = timestamp; - scrollCache.lastPosition = scrollPosition.current; + const dx = newScroll.left - currentScroll.current.left; + const dy = newScroll.top - currentScroll.current.top; + const isScrolling = dx !== 0 || dy !== 0; + + currentScroll.current = newScroll; + + let direction: ScrollCache['direction']; if (isScrolling) { - const dy = scrollPosition.current.top - previousScroll.current.top; - const dx = scrollPosition.current.left - previousScroll.current.left; - scrollCache.buffer = { - top: dimensions.rowHeight * 10, - left: 50 * 3, - }; - scrollCache.direction = directionForDelta(dx, dy); + direction = directionForDelta(dx, dy); } else { - scrollCache.buffer = { top: 0, left: 0 }; - scrollCache.direction = ScrollDirection.NONE; + direction = ScrollDirection.NONE; } // Since previous render, we have scrolled... - const rowScroll = - Math.abs(scrollPosition.current.top - previousScroll.current.top) + scrollCache.buffer.top; - const columnScroll = - Math.abs(scrollPosition.current.left - previousScroll.current.left) + scrollCache.buffer.left; + const rowScroll = Math.abs( + currentScroll.current.top - previousContextScrollPosition.current.top, + ); + const columnScroll = Math.abs( + currentScroll.current.left - previousContextScrollPosition.current.left, + ); - const shouldUpdate = + const didCrossThreshold = rowScroll >= rootProps.rowThresholdPx || columnScroll >= rootProps.columnThresholdPx; + const didChangeDirection = scrollCache.current.direction !== direction; + const shouldUpdate = didCrossThreshold || didChangeDirection; if (!shouldUpdate) { return previousContext.current; } + // Render a new context + + if (didChangeDirection) { + switch (direction) { + case ScrollDirection.NONE: + case ScrollDirection.LEFT: + case ScrollDirection.RIGHT: + frozenContext.current = undefined; + break; + default: + frozenContext.current = renderContext; + break; + } + } + + let buffer: ScrollCache['buffer']; + /* eslint-disable */ + switch (direction) { + case ScrollDirection.NONE: + buffer = { vertical: 0, horizontal: 0 }; + break; + case ScrollDirection.LEFT: + case ScrollDirection.RIGHT: + buffer = { + vertical: -rootProps.rowBufferPx, + horizontal: 50 * 3, + }; + break; + case ScrollDirection.UP: + case ScrollDirection.DOWN: + buffer = { + vertical: dimensions.rowHeight * 15, + horizontal: -rootProps.columnBufferPx, + }; + break; + } + /* eslint-enable */ + + scrollCache.current = { buffer, direction }; + const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); const [nextRenderContext, rawRenderContext] = computeRenderContext( inputs, - scrollPosition.current, - scrollCache, + currentScroll.current, + scrollCache.current, ); // Prevents batching render context changes @@ -201,6 +255,8 @@ export const useGridVirtualScroller = () => { updateRenderContext(nextRenderContext, rawRenderContext); }); + scrollTimeout.start(1000, triggerUpdateRenderContext); + return nextRenderContext; }; @@ -208,8 +264,8 @@ export const useGridVirtualScroller = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); const [nextRenderContext, rawRenderContext] = computeRenderContext( inputs, - scrollPosition.current, - scrollCache, + currentScroll.current, + scrollCache.current, ); updateRenderContext(nextRenderContext, rawRenderContext); }; @@ -217,8 +273,6 @@ export const useGridVirtualScroller = () => { const handleScroll = useEventCallback((event: React.UIEvent) => { const { scrollTop, scrollLeft } = event.currentTarget; - scrollPosition.current = { top: scrollTop, left: scrollLeft }; - // On iOS and macOS, negative offsets are possible when swiping past the start if (scrollTop < 0) { return; @@ -262,8 +316,7 @@ export const useGridVirtualScroller = () => { return []; } - const columnPositions = gridColumnPositionsSelector(apiRef); - const currentRenderContext = params.renderContext ?? renderContext; + const baseRenderContext = params.renderContext ?? renderContext; const isLastSection = (!hasBottomPinnedRows && params.position === undefined) || @@ -287,8 +340,8 @@ export const useGridVirtualScroller = () => { const rowModels = params.rows ?? currentPage.rows; - const firstRowToRender = currentRenderContext.firstRowIndex; - const lastRowToRender = Math.min(currentRenderContext.lastRowIndex, rowModels.length); + const firstRowToRender = baseRenderContext.firstRowIndex; + const lastRowToRender = Math.min(baseRenderContext.lastRowIndex, rowModels.length); const rowIndexes = params.rows ? range(0, params.rows.length) @@ -308,6 +361,7 @@ export const useGridVirtualScroller = () => { const rows: React.ReactNode[] = []; const rowProps = rootProps.slotProps?.row; + const columnPositions = gridColumnPositionsSelector(apiRef); rowIndexes.forEach((rowIndexInPage) => { const { id, model } = rowModels[rowIndexInPage]; @@ -384,6 +438,16 @@ export const useGridVirtualScroller = () => { tabbableCell = cellParams.cellMode === 'view' ? cellTabIndex.field : null; } + let currentRenderContext = baseRenderContext; + if ( + !isPinnedSection && + frozenContext.current && + rowIndexInPage >= frozenContext.current.firstRowIndex && + rowIndexInPage < frozenContext.current.lastRowIndex + ) { + currentRenderContext = frozenContext.current; + } + const offsetLeft = computeOffsetLeft( columnPositions, currentRenderContext, @@ -489,14 +553,14 @@ export const useGridVirtualScroller = () => { const [initialRenderContext, rawRenderContext] = computeRenderContext( inputs, - scrollPosition.current, - scrollCache, + currentScroll.current, + scrollCache.current, ); updateRenderContext(initialRenderContext, rawRenderContext); apiRef.current.publishEvent('scrollPositionChange', { - top: scrollPosition.current.top, - left: scrollPosition.current.left, + top: currentScroll.current.top, + left: currentScroll.current.left, renderContext: initialRenderContext, }); }); @@ -535,7 +599,6 @@ export const useGridVirtualScroller = () => { }; }; -type ScrollPosition = { top: number; left: number }; type RenderContextInputs = { enabled: boolean; enabledForColumns: boolean; @@ -894,10 +957,21 @@ function directionForDelta(dx: number, dy: number) { function bufferForScrollCache(scrollCache: ScrollCache) { const direction = scrollCache.direction; - return { - columnBefore: direction === ScrollDirection.LEFT ? scrollCache.buffer.left : 0, - columnAfter: direction === ScrollDirection.RIGHT ? scrollCache.buffer.left : 0, - rowBefore: direction === ScrollDirection.UP ? scrollCache.buffer.top : 0, - rowAfter: direction === ScrollDirection.DOWN ? scrollCache.buffer.top : 0, + const isVertical = direction === ScrollDirection.UP || direction === ScrollDirection.DOWN; + const isHorizontal = direction === ScrollDirection.LEFT || direction === ScrollDirection.RIGHT; + const buffer = { + columnBefore: direction === ScrollDirection.LEFT ? scrollCache.buffer.horizontal : 0, + columnAfter: direction === ScrollDirection.RIGHT ? scrollCache.buffer.horizontal : 0, + rowBefore: direction === ScrollDirection.UP ? scrollCache.buffer.vertical : 0, + rowAfter: direction === ScrollDirection.DOWN ? scrollCache.buffer.vertical : 0, }; + if (isVertical) { + buffer.columnAfter = scrollCache.buffer.horizontal; + buffer.columnBefore = scrollCache.buffer.horizontal; + } + if (isHorizontal) { + buffer.rowAfter = scrollCache.buffer.vertical; + buffer.rowBefore = scrollCache.buffer.vertical; + } + return buffer; } diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index 02fac404d3654..8b6901686f934 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -128,12 +128,12 @@ export interface DataGridPropsWithDefaultValues { */ checkboxSelectionVisibleOnly: boolean; /** - * Column region to render before/after the viewport + * Column region in pixels to render before/after the viewport * @default 100 */ columnBufferPx: number; /** - * Row region to render before/after the viewport + * Row region in pixels to render before/after the viewport * @default 100 */ rowBufferPx: number; @@ -143,12 +143,12 @@ export interface DataGridPropsWithDefaultValues { */ rowSelection: boolean; /** - * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. * @default 150 */ rowThresholdPx: number; /** - * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered. + * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. * @default 150 */ columnThresholdPx: number; From 241b730f35f5f9b410c56c09ac35b89a184193f4 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Sun, 10 Mar 2024 20:56:04 -0400 Subject: [PATCH 14/31] lint --- .../virtualization/useGridVirtualScroller.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 699bbad4647c4..180ddb5e487d6 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -109,7 +109,7 @@ export const useGridVirtualScroller = () => { * work that's not necessary. Thus we store the context at the start of the scroll in `frozenContext`, and the rows * that are part of this old context will keep their same render context as to avoid re-rendering. */ - const currentScroll = React.useRef(EMPTY_SCROLL_POSITION); + const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const previousContext = React.useRef(EMPTY_RENDER_CONTEXT); const previousContextScrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const previousRowContext = React.useRef(EMPTY_RENDER_CONTEXT); @@ -160,7 +160,7 @@ export const useGridVirtualScroller = () => { apiRef.current.publishEvent('renderedRowsIntervalChange', nextRenderContext); } - previousContextScrollPosition.current = currentScroll.current; + previousContextScrollPosition.current = scrollPosition.current; previousContext.current = rawRenderContext; }, [apiRef, dimensions.isReady], @@ -172,12 +172,12 @@ export const useGridVirtualScroller = () => { left: scrollerRef.current!.scrollLeft, }; - const dx = newScroll.left - currentScroll.current.left; - const dy = newScroll.top - currentScroll.current.top; + const dx = newScroll.left - scrollPosition.current.left; + const dy = newScroll.top - scrollPosition.current.top; const isScrolling = dx !== 0 || dy !== 0; - currentScroll.current = newScroll; + scrollPosition.current = newScroll; let direction: ScrollCache['direction']; if (isScrolling) { @@ -188,10 +188,10 @@ export const useGridVirtualScroller = () => { // Since previous render, we have scrolled... const rowScroll = Math.abs( - currentScroll.current.top - previousContextScrollPosition.current.top, + scrollPosition.current.top - previousContextScrollPosition.current.top, ); const columnScroll = Math.abs( - currentScroll.current.left - previousContextScrollPosition.current.left, + scrollPosition.current.left - previousContextScrollPosition.current.left, ); const didCrossThreshold = @@ -246,7 +246,7 @@ export const useGridVirtualScroller = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); const [nextRenderContext, rawRenderContext] = computeRenderContext( inputs, - currentScroll.current, + scrollPosition.current, scrollCache.current, ); @@ -264,7 +264,7 @@ export const useGridVirtualScroller = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); const [nextRenderContext, rawRenderContext] = computeRenderContext( inputs, - currentScroll.current, + scrollPosition.current, scrollCache.current, ); updateRenderContext(nextRenderContext, rawRenderContext); @@ -553,14 +553,14 @@ export const useGridVirtualScroller = () => { const [initialRenderContext, rawRenderContext] = computeRenderContext( inputs, - currentScroll.current, + scrollPosition.current, scrollCache.current, ); updateRenderContext(initialRenderContext, rawRenderContext); apiRef.current.publishEvent('scrollPositionChange', { - top: currentScroll.current.top, - left: currentScroll.current.left, + top: scrollPosition.current.top, + left: scrollPosition.current.left, renderContext: initialRenderContext, }); }); From 8ab7b5b65dedb90f186dda09df9e4edc93f6921c Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Mon, 11 Mar 2024 22:06:28 -0400 Subject: [PATCH 15/31] feat: remove props --- docs/data/data-grid/demo/FullFeaturedDemo.js | 1 - docs/data/data-grid/demo/FullFeaturedDemo.tsx | 1 - .../master-detail/BasicDetailPanels.js | 1 - .../master-detail/BasicDetailPanels.tsx | 1 - .../BasicDetailPanels.tsx.preview | 1 - .../master-detail/ControlMasterDetail.js | 1 - .../master-detail/ControlMasterDetail.tsx | 1 - .../CustomizeDetailPanelToggle.js | 1 - .../CustomizeDetailPanelToggle.tsx | 1 - .../CustomizeDetailPanelToggle.tsx.preview | 1 - .../master-detail/DetailPanelAutoHeight.js | 1 - .../master-detail/DetailPanelAutoHeight.tsx | 1 - .../DetailPanelAutoHeight.tsx.preview | 1 - .../master-detail/FormDetailPanel.js | 1 - .../master-detail/FormDetailPanel.tsx | 1 - .../master-detail/FormDetailPanel.tsx.preview | 1 - .../master-detail/FullWidthDetailPanel.js | 1 - .../master-detail/FullWidthDetailPanel.tsx | 1 - .../FullWidthDetailPanel.tsx.preview | 1 - .../data-grid/master-detail/master-detail.md | 9 - .../ColumnVirtualizationGrid.js | 2 +- .../ColumnVirtualizationGrid.tsx | 2 +- .../ColumnVirtualizationGrid.tsx.preview | 2 +- .../migration-data-grid-v6.md | 4 +- .../tests/detailPanel.DataGridPro.test.tsx | 1 - .../tests/infiniteLoader.DataGridPro.test.tsx | 20 +- .../src/tests/rows.DataGridPro.test.tsx | 35 ++-- .../src/DataGrid/useDataGridProps.ts | 2 - .../virtualization/useGridVirtualScroller.tsx | 193 ++++++++++-------- .../src/models/props/DataGridProps.ts | 10 - .../tests/columnSpanning.DataGrid.test.tsx | 9 +- .../src/tests/rows.DataGrid.test.tsx | 6 - .../DataGridPro/KeyboardNavigationFocus.tsx | 2 +- 33 files changed, 146 insertions(+), 170 deletions(-) diff --git a/docs/data/data-grid/demo/FullFeaturedDemo.js b/docs/data/data-grid/demo/FullFeaturedDemo.js index 345b15379170a..3fc0fb9d27edc 100644 --- a/docs/data/data-grid/demo/FullFeaturedDemo.js +++ b/docs/data/data-grid/demo/FullFeaturedDemo.js @@ -301,7 +301,6 @@ export default function FullFeaturedDemo() { loading={loading} checkboxSelection disableRowSelectionOnClick - rowThresholdPx={0} initialState={{ ...data.initialState, pinnedColumns: { left: [GRID_CHECKBOX_SELECTION_FIELD, 'desk'] }, diff --git a/docs/data/data-grid/demo/FullFeaturedDemo.tsx b/docs/data/data-grid/demo/FullFeaturedDemo.tsx index f751ee75a51f7..2928393ef60ec 100644 --- a/docs/data/data-grid/demo/FullFeaturedDemo.tsx +++ b/docs/data/data-grid/demo/FullFeaturedDemo.tsx @@ -341,7 +341,6 @@ export default function FullFeaturedDemo() { loading={loading} checkboxSelection disableRowSelectionOnClick - rowThresholdPx={0} initialState={{ ...data.initialState, pinnedColumns: { left: [GRID_CHECKBOX_SELECTION_FIELD, 'desk'] }, diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.js b/docs/data/data-grid/master-detail/BasicDetailPanels.js index 8800a3dfcaafa..172e2c73444a1 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.js +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.js @@ -175,7 +175,6 @@ export default function BasicDetailPanels() { diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx index 124e8c3baaa7d..e34bdf9861969 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx @@ -177,7 +177,6 @@ export default function BasicDetailPanels() { diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview index b7fa987a8071a..ac41382b6e510 100644 --- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview +++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview @@ -1,7 +1,6 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/ControlMasterDetail.js b/docs/data/data-grid/master-detail/ControlMasterDetail.js index 94cf33fbcdab4..bebc52b7b1778 100644 --- a/docs/data/data-grid/master-detail/ControlMasterDetail.js +++ b/docs/data/data-grid/master-detail/ControlMasterDetail.js @@ -29,7 +29,6 @@ export default function ControlMasterDetail() { ( {`Order #${row.id}`} )} diff --git a/docs/data/data-grid/master-detail/ControlMasterDetail.tsx b/docs/data/data-grid/master-detail/ControlMasterDetail.tsx index c6a0ab47e0dfb..611e8f8dd434f 100644 --- a/docs/data/data-grid/master-detail/ControlMasterDetail.tsx +++ b/docs/data/data-grid/master-detail/ControlMasterDetail.tsx @@ -37,7 +37,6 @@ export default function ControlMasterDetail() { ( {`Order #${row.id}`} )} diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js index 219d08f790fb8..0f9a8b1b1f648 100644 --- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js +++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js @@ -30,7 +30,6 @@ export default function CustomizeDetailPanelToggle() { diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx index 9f8741b90da4d..47a78a7af50a3 100644 --- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx +++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx @@ -34,7 +34,6 @@ export default function CustomizeDetailPanelToggle() { diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview index d77d462a20e9b..d89161b50e8d3 100644 --- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview +++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview @@ -1,7 +1,6 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js index 542dc32e6f061..cc6d34bac8231 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js @@ -228,7 +228,6 @@ export default function DetailPanelAutoHeight() { diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx index 68fdd16bd8ea7..ed845bdc8f50c 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx @@ -234,7 +234,6 @@ export default function DetailPanelAutoHeight() { diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview index b7fa987a8071a..ac41382b6e510 100644 --- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview +++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview @@ -1,7 +1,6 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.js b/docs/data/data-grid/master-detail/FormDetailPanel.js index 17af82c4bd08f..a09c4b6ab2e21 100644 --- a/docs/data/data-grid/master-detail/FormDetailPanel.js +++ b/docs/data/data-grid/master-detail/FormDetailPanel.js @@ -131,7 +131,6 @@ export default function FormDetailPanel() { diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.tsx b/docs/data/data-grid/master-detail/FormDetailPanel.tsx index 4f470cb075401..12d6f209fc9b7 100644 --- a/docs/data/data-grid/master-detail/FormDetailPanel.tsx +++ b/docs/data/data-grid/master-detail/FormDetailPanel.tsx @@ -139,7 +139,6 @@ export default function FormDetailPanel() { diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview b/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview index b7fa987a8071a..ac41382b6e510 100644 --- a/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview +++ b/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview @@ -1,7 +1,6 @@ \ No newline at end of file diff --git a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js index e000c3f3dbed3..c7aed919254cf 100644 --- a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js +++ b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js @@ -201,7 +201,6 @@ export default function FullWidthDetailPanel() { { ... }, []); ``` -Depending on the height of the detail panel, you may see a blank space when scrolling. -This is caused by the data grid using a lazy approach to update the rendered rows. -Set `rowThresholdPx` to a lower value to force new rows to be rendered more often to fill the blank space. -Note that this may reduce the performance. - -```tsx - -``` - ::: ## Infer height from the content diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js index dac4a5294548a..014b0e55bfec3 100644 --- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js +++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js @@ -39,7 +39,7 @@ export default function ColumnVirtualizationGrid() { return (
- +
); } diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx index e800e31f0eea9..c314fa3160c4e 100644 --- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx +++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx @@ -49,7 +49,7 @@ export default function ColumnVirtualizationGrid() { return (
- +
); } diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview index aa775ae151718..ce7543c27f818 100644 --- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview +++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md index f11256f65e2d4..fce67eba44959 100644 --- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md +++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md @@ -108,7 +108,7 @@ As a result, the following changes have been made: ## Renamed props -- The props `rowBuffer`, `columnBuffer`, `rowThreshold` and `columnThreshold` were renamed to `rowBufferPx`, `columnBufferPx`, `rowThresholdPx` and `columnThresholdPx`. +- The props `rowBuffer` and `columnBuffer` were renamed to `rowBufferPx` and `columnBufferPx`. Their value is now a pixel value rather than a number of items. Their default value is now `150`. ### Removed props @@ -136,6 +136,8 @@ As a result, the following changes have been made: }; ``` +- The props `rowThreshold` and `columnThreshold` have been removed. + ### Behavioral changes The disabled column specific features like `hiding`, `sorting`, `filtering`, `pinning`, `row grouping`, etc., can now be controlled programmatically using `initialState`, respective controlled models, or the [API object](/x/react-data-grid/api-object/). diff --git a/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx index 60c1af46b6cd5..bfe5efda3299e 100644 --- a/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx @@ -60,7 +60,6 @@ describe(' - Detail panel', () => { getDetailPanelContent={() =>
} rowHeight={rowHeight} rowBufferPx={0} - rowThresholdPx={0} initialState={{ detailPanel: { expandedRowIds: [0, 1], diff --git a/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx index 9973b2a200b45..eb99be09db6db 100644 --- a/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx @@ -124,27 +124,37 @@ describe(' - Infnite loader', () => { await waitFor(() => { expect(getRow.callCount).to.equal(1); }); - expect(getColumnValues(0)).to.deep.equal(['0', '1']); + await waitFor(() => { + expect(getColumnValues(0)).to.deep.equal(['0', '1']); + }); await waitFor(() => { expect(getRow.callCount).to.equal(2); }); - expect(getColumnValues(0)).to.deep.equal(['0', '1', '2']); + await waitFor(() => { + expect(getColumnValues(0)).to.deep.equal(['0', '1', '2']); + }); await waitFor(() => { expect(getRow.callCount).to.equal(3); }); - expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3']); + await waitFor(() => { + expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3']); + }); await waitFor(() => { expect(getRow.callCount).to.equal(4); }); - expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4']); + await waitFor(() => { + expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4']); + }); await waitFor(() => { expect(getRow.callCount).to.equal(5); }); - expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4', '5']); + await waitFor(() => { + expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4', '5']); + }); await sleep(200); // should not load more rows because the threshold is not reached diff --git a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx index 2bc7445e31d6f..e203adbc14b89 100644 --- a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx @@ -452,9 +452,11 @@ describe(' - Rows', () => { virtualScroller.scrollTop = 10e6; // scroll to the bottom act(() => virtualScroller.dispatchEvent(new Event('scroll'))); + clock.runToLast(); + const lastCell = $$('[role="row"]:last-child [role="gridcell"]')[0]; expect(lastCell).to.have.text('995'); - expect(renderingZone.children.length).to.equal(Math.floor((height - 1) / rowHeight) + n); // Subtracting 1 is needed because of the column header borders + expect(renderingZone.children.length).to.equal(Math.floor((height) / rowHeight) + n); const scrollbarSize = apiRef.current.state.dimensions.scrollbarSize; const distanceToFirstRow = (nbRows - renderingZone.children.length) * rowHeight; expect(gridOffsetTop()).to.equal(distanceToFirstRow); @@ -489,41 +491,31 @@ describe(' - Rows', () => { const virtualScroller = document.querySelector('.MuiDataGrid-virtualScroller')!; virtualScroller.scrollLeft = 301; act(() => virtualScroller.dispatchEvent(new Event('scroll'))); + clock.runToLast(); expect($$(firstRow, '[role="gridcell"]')).to.have.length( n + 1 + Math.floor(width / columnWidth) + n, ); }); - it('should render new rows when scrolling past the rowThresholdPx value', () => { + it('should render new rows when scrolling past the threshold value', () => { const rowHeight = 50; - const rowThresholdPx = 3 * rowHeight; - render( - , - ); + const rowThresholdPx = 1 * rowHeight; + render(); const virtualScroller = document.querySelector('.MuiDataGrid-virtualScroller')!; const renderingZone = document.querySelector('.MuiDataGrid-virtualScrollerRenderZone')!; let firstRow = renderingZone.firstChild; expect(firstRow).to.have.attr('data-rowindex', '0'); virtualScroller.scrollTop = rowThresholdPx; act(() => virtualScroller.dispatchEvent(new Event('scroll'))); + clock.runToLast(); firstRow = renderingZone.firstChild; - expect(firstRow).to.have.attr('data-rowindex', '3'); + expect(firstRow).to.have.attr('data-rowindex', '1'); }); - it('should render new columns when scrolling past the columnThresholdPx value', () => { + it('should render new columns when scrolling past the threshold value', () => { const columnWidth = 100; - const columnThresholdPx = 3 * columnWidth; - render( - , - ); + const columnThresholdPx = 1 * columnWidth; + render(); const virtualScroller = grid('virtualScroller')!; const renderingZone = grid('virtualScrollerRenderZone')!; const firstRow = $(renderingZone, '[role="row"]:first-child')!; @@ -531,8 +523,9 @@ describe(' - Rows', () => { expect(firstColumn).to.have.attr('data-colindex', '0'); virtualScroller.scrollLeft = columnThresholdPx; act(() => virtualScroller.dispatchEvent(new Event('scroll'))); + clock.runToLast(); firstColumn = $(renderingZone, '[role="row"] > [role="gridcell"]')!; - expect(firstColumn).to.have.attr('data-colindex', '3'); + expect(firstColumn).to.have.attr('data-colindex', '1'); }); describe('Pagination', () => { diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts index c3c70e11bd750..44d8202cd1542 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -34,8 +34,6 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { checkboxSelectionVisibleOnly: false, columnBufferPx: 150, rowBufferPx: 150, - columnThresholdPx: 150, - rowThresholdPx: 150, rowSelection: true, density: 'standard', disableColumnFilter: false, diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 180ddb5e487d6..994809ce1c4a9 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -4,6 +4,7 @@ import { unstable_useEnhancedEffect as useEnhancedEffect, unstable_useEventCallback as useEventCallback, } from '@mui/utils'; +import useLazyRef from '@mui/utils/useLazyRef'; import useTimeout from '@mui/utils/useTimeout'; import { useTheme, Theme } from '@mui/material/styles'; import type { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; @@ -58,11 +59,22 @@ const EMPTY_SCROLL_POSITION = { top: 0, left: 0 }; export const EMPTY_DETAIL_PANELS = Object.freeze(new Map()); -const EMPTY_SCROLL_CACHE = { +const createScrollCache = ( + rowBufferPx: number, + columnBufferPx: number, + verticalBuffer: number, + horizontalBuffer: number, +) => ({ direction: ScrollDirection.NONE, - buffer: { vertical: 0, horizontal: 0 }, -}; -type ScrollCache = typeof EMPTY_SCROLL_CACHE; + buffer: bufferForDirection( + ScrollDirection.NONE, + rowBufferPx, + columnBufferPx, + verticalBuffer, + horizontalBuffer, + ), +}); +type ScrollCache = ReturnType; export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext() as React.MutableRefObject; @@ -110,13 +122,19 @@ export const useGridVirtualScroller = () => { * that are part of this old context will keep their same render context as to avoid re-rendering. */ const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION); - const previousContext = React.useRef(EMPTY_RENDER_CONTEXT); const previousContextScrollPosition = React.useRef(EMPTY_SCROLL_POSITION); const previousRowContext = React.useRef(EMPTY_RENDER_CONTEXT); const renderContext = useGridSelector(apiRef, gridRenderContextSelector); const scrollTimeout = useTimeout(); const frozenContext = React.useRef(undefined); - const scrollCache = React.useRef(EMPTY_SCROLL_CACHE); + const scrollCache = useLazyRef(() => + createScrollCache( + rootProps.rowBufferPx, + rootProps.columnBufferPx, + dimensions.rowHeight * 15, + 50 * 3, + ), + ).current; const focusedCell = { rowIndex: React.useMemo( @@ -131,7 +149,7 @@ export const useGridVirtualScroller = () => { }; const updateRenderContext = React.useCallback( - (nextRenderContext: GridRenderContext, rawRenderContext: GridRenderContext) => { + (nextRenderContext: GridRenderContext) => { if ( areRenderContextsEqual(nextRenderContext, apiRef.current.state.virtualization.renderContext) ) { @@ -161,7 +179,6 @@ export const useGridVirtualScroller = () => { } previousContextScrollPosition.current = scrollPosition.current; - previousContext.current = rawRenderContext; }, [apiRef, dimensions.isReady], ); @@ -179,12 +196,7 @@ export const useGridVirtualScroller = () => { scrollPosition.current = newScroll; - let direction: ScrollCache['direction']; - if (isScrolling) { - direction = directionForDelta(dx, dy); - } else { - direction = ScrollDirection.NONE; - } + const direction = isScrolling ? directionForDelta(dx, dy) : ScrollDirection.NONE; // Since previous render, we have scrolled... const rowScroll = Math.abs( @@ -194,13 +206,12 @@ export const useGridVirtualScroller = () => { scrollPosition.current.left - previousContextScrollPosition.current.left, ); - const didCrossThreshold = - rowScroll >= rootProps.rowThresholdPx || columnScroll >= rootProps.columnThresholdPx; - const didChangeDirection = scrollCache.current.direction !== direction; + const didCrossThreshold = rowScroll >= dimensions.rowHeight || columnScroll >= 50; + const didChangeDirection = scrollCache.direction !== direction; const shouldUpdate = didCrossThreshold || didChangeDirection; if (!shouldUpdate) { - return previousContext.current; + return renderContext; } // Render a new context @@ -218,41 +229,25 @@ export const useGridVirtualScroller = () => { } } - let buffer: ScrollCache['buffer']; - /* eslint-disable */ - switch (direction) { - case ScrollDirection.NONE: - buffer = { vertical: 0, horizontal: 0 }; - break; - case ScrollDirection.LEFT: - case ScrollDirection.RIGHT: - buffer = { - vertical: -rootProps.rowBufferPx, - horizontal: 50 * 3, - }; - break; - case ScrollDirection.UP: - case ScrollDirection.DOWN: - buffer = { - vertical: dimensions.rowHeight * 15, - horizontal: -rootProps.columnBufferPx, - }; - break; - } - /* eslint-enable */ - - scrollCache.current = { buffer, direction }; + scrollCache.direction = direction; + scrollCache.buffer = bufferForDirection( + direction, + rootProps.rowBufferPx, + rootProps.columnBufferPx, + dimensions.rowHeight * 15, + 50 * 3, + ); const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext( + const nextRenderContext = computeRenderContext( inputs, scrollPosition.current, - scrollCache.current, + scrollCache, ); // Prevents batching render context changes ReactDOM.flushSync(() => { - updateRenderContext(nextRenderContext, rawRenderContext); + updateRenderContext(nextRenderContext); }); scrollTimeout.start(1000, triggerUpdateRenderContext); @@ -262,12 +257,12 @@ export const useGridVirtualScroller = () => { const forceUpdateRenderContext = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [nextRenderContext, rawRenderContext] = computeRenderContext( + const nextRenderContext = computeRenderContext( inputs, scrollPosition.current, - scrollCache.current, + scrollCache, ); - updateRenderContext(nextRenderContext, rawRenderContext); + updateRenderContext(nextRenderContext); }; const handleScroll = useEventCallback((event: React.UIEvent) => { @@ -551,12 +546,12 @@ export const useGridVirtualScroller = () => { useRunOnce(outerSize.width !== 0, () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const [initialRenderContext, rawRenderContext] = computeRenderContext( + const initialRenderContext = computeRenderContext( inputs, scrollPosition.current, - scrollCache.current, + scrollCache, ); - updateRenderContext(initialRenderContext, rawRenderContext); + updateRenderContext(initialRenderContext); apiRef.current.publishEvent('scrollPositionChange', { top: scrollPosition.current.top, @@ -642,7 +637,7 @@ function inputsSelector( columnsTotalWidth: dimensions.columnsTotalWidth, viewportInnerWidth: dimensions.viewportInnerSize.width, viewportInnerHeight: dimensions.viewportInnerSize.height, - lastRowHeight: lastRowId ? apiRef.current.unstable_getRowHeight(lastRowId) : 0, + lastRowHeight: lastRowId !== undefined ? apiRef.current.unstable_getRowHeight(lastRowId) : 0, lastColumnWidth: lastColumn?.computedWidth ?? 0, rowsMeta: gridRowsMetaSelector(apiRef.current.state), columnPositions: gridColumnPositionsSelector(apiRef), @@ -674,7 +669,10 @@ function computeRenderContext( // Clamp the value because the search may return an index out of bounds. // In the last index, this is not needed because Array.slice doesn't include it. const firstRowIndex = Math.min( - getNearestIndexToRender(inputs, top), + getNearestIndexToRender(inputs, top, { + atStart: true, + lastPosition: inputs.rowsMeta.positions[inputs.rowsMeta.positions.length - 1] + inputs.lastRowHeight, + }), inputs.rowsMeta.positions.length - 1, ); @@ -693,8 +691,8 @@ function computeRenderContext( lastIndex: lastRowIndex, minFirstIndex: 0, maxLastIndex: inputs.rows.length, - bufferBefore: inputs.rowBufferPx, - bufferAfter: inputs.rowBufferPx, + bufferBefore: scrollCache.buffer.rowBefore, + bufferAfter: scrollCache.buffer.rowAfter, positions: inputs.rowsMeta.positions, lastSize: inputs.lastRowHeight, }); @@ -726,10 +724,10 @@ function computeRenderContext( const actualRenderContext = deriveRenderContext(inputs, renderContext, scrollCache); - return [actualRenderContext, renderContext]; + return actualRenderContext; } -function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) { +function getNearestIndexToRender(inputs: RenderContextInputs, offset: number, options?: SearchOptions) { const lastMeasuredIndexRelativeToAllRows = inputs.apiRef.current.getLastMeasuredRowIndex(); let allRowsMeasured = lastMeasuredIndexRelativeToAllRows === Infinity; if (inputs.range?.lastRowIndex && !allRowsMeasured) { @@ -749,7 +747,7 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) { ) { // If all rows were measured (when no row has "auto" as height) or all rows before the offset // were measured, then use a binary search because it's faster. - return binarySearch(offset, inputs.rowsMeta.positions); + return binarySearch(offset, inputs.rowsMeta.positions, options); } // Otherwise, use an exponential search. @@ -760,6 +758,7 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) { offset, inputs.rowsMeta.positions, lastMeasuredIndexRelativeToCurrentPage, + options, ); } @@ -773,15 +772,13 @@ function deriveRenderContext( nextRenderContext: GridRenderContext, scrollCache: ScrollCache, ) { - const buffer = bufferForScrollCache(scrollCache); - const [firstRowToRender, lastRowToRender] = getIndexesToRender({ firstIndex: nextRenderContext.firstRowIndex, lastIndex: nextRenderContext.lastRowIndex, minFirstIndex: 0, maxLastIndex: inputs.rows.length, - bufferBefore: inputs.rowBufferPx + buffer.rowBefore, - bufferAfter: inputs.rowBufferPx + buffer.rowAfter, + bufferBefore: scrollCache.buffer.rowBefore, + bufferAfter: scrollCache.buffer.rowAfter, positions: inputs.rowsMeta.positions, lastSize: inputs.lastRowHeight, }); @@ -791,8 +788,8 @@ function deriveRenderContext( lastIndex: nextRenderContext.lastColumnIndex, minFirstIndex: inputs.pinnedColumns.left.length, maxLastIndex: inputs.visibleColumns.length - inputs.pinnedColumns.right.length, - bufferBefore: inputs.columnBufferPx + buffer.columnBefore, - bufferAfter: inputs.columnBufferPx + buffer.columnAfter, + bufferBefore: scrollCache.buffer.columnBefore, + bufferAfter: scrollCache.buffer.columnAfter, positions: inputs.columnPositions, lastSize: inputs.lastColumnWidth, }); @@ -856,7 +853,7 @@ function binarySearch( : binarySearch(offset, positions, options, pivot + 1, sliceEnd); } -function exponentialSearch(offset: number, positions: number[], index: number): number { +function exponentialSearch(offset: number, positions: number[], index: number, options: SearchOptions | undefined = undefined): number { let interval = 1; while (index < positions.length && Math.abs(positions[index]) < offset) { @@ -867,7 +864,7 @@ function exponentialSearch(offset: number, positions: number[], index: number): return binarySearch( offset, positions, - undefined, + options, Math.floor(index / 2), Math.min(index, positions.length), ); @@ -955,23 +952,51 @@ function directionForDelta(dx: number, dy: number) { /* eslint-enable */ } -function bufferForScrollCache(scrollCache: ScrollCache) { - const direction = scrollCache.direction; - const isVertical = direction === ScrollDirection.UP || direction === ScrollDirection.DOWN; - const isHorizontal = direction === ScrollDirection.LEFT || direction === ScrollDirection.RIGHT; - const buffer = { - columnBefore: direction === ScrollDirection.LEFT ? scrollCache.buffer.horizontal : 0, - columnAfter: direction === ScrollDirection.RIGHT ? scrollCache.buffer.horizontal : 0, - rowBefore: direction === ScrollDirection.UP ? scrollCache.buffer.vertical : 0, - rowAfter: direction === ScrollDirection.DOWN ? scrollCache.buffer.vertical : 0, - }; - if (isVertical) { - buffer.columnAfter = scrollCache.buffer.horizontal; - buffer.columnBefore = scrollCache.buffer.horizontal; - } - if (isHorizontal) { - buffer.rowAfter = scrollCache.buffer.vertical; - buffer.rowBefore = scrollCache.buffer.vertical; +function bufferForDirection( + direction: ScrollDirection, + rowBufferPx: number, + columnBufferPx: number, + verticalBuffer: number, + horizontalBuffer: number, +) { + switch (direction) { + case ScrollDirection.NONE: + return { + rowAfter: rowBufferPx, + rowBefore: rowBufferPx, + columnAfter: columnBufferPx, + columnBefore: columnBufferPx, + }; + case ScrollDirection.LEFT: + return { + rowAfter: 0, + rowBefore: 0, + columnAfter: 0, + columnBefore: horizontalBuffer, + }; + case ScrollDirection.RIGHT: + return { + rowAfter: 0, + rowBefore: 0, + columnAfter: horizontalBuffer, + columnBefore: 0, + }; + case ScrollDirection.UP: + return { + rowAfter: 0, + rowBefore: verticalBuffer, + columnAfter: 0, + columnBefore: 0, + }; + case ScrollDirection.DOWN: + return { + rowAfter: verticalBuffer, + rowBefore: 0, + columnAfter: 0, + columnBefore: 0, + }; + default: + // eslint unable to figure out enum exhaustiveness + throw new Error('unreachable'); } - return buffer; } diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index 8b6901686f934..84bcc803d0efe 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -142,16 +142,6 @@ export interface DataGridPropsWithDefaultValues { * @default true */ rowSelection: boolean; - /** - * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - rowThresholdPx: number; - /** - * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - columnThresholdPx: number; /** * Set the density of the Data Grid. * @default "standard" diff --git a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx index 3ef82ad64369a..25071ffe04e88 100644 --- a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx @@ -313,7 +313,6 @@ describe(' - Column spanning', () => { ]} rows={rows} rowBufferPx={rowHeight} - rowThresholdPx={rowHeight} rowHeight={rowHeight} />
, @@ -349,7 +348,6 @@ describe(' - Column spanning', () => { ]} rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3' }]} columnBufferPx={100} - columnThresholdPx={100} /> , ); @@ -457,7 +455,6 @@ describe(' - Column spanning', () => { ]} rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3', col4: '0-4' }]} columnBufferPx={100} - columnThresholdPx={100} /> , ); @@ -744,7 +741,6 @@ describe(' - Column spanning', () => { { id: 1, col0: '1-0', col1: '1-1', col2: '1-2', col3: '1-3', col4: '1-4', col5: '1-5' }, ]} columnBufferPx={100} - columnThresholdPx={100} /> , ); @@ -804,9 +800,7 @@ describe(' - Column spanning', () => { { id: 6, col0: '6-0', col1: '6-1', col2: '6-2', col3: '6-3', col4: '6-4', col5: '6-5' }, ]} columnBufferPx={100} - columnThresholdPx={100} rowBufferPx={50} - rowThresholdPx={50} rowHeight={rowHeight} /> , @@ -828,6 +822,7 @@ describe(' - Column spanning', () => { // hide first row to trigger row virtualization virtualScroller.scrollTop = rowHeight + 10; virtualScroller.dispatchEvent(new Event('scroll')); + clock.runToLast(); expect(getCell(2, 5).offsetLeft).to.equal( getCell(1, 5).offsetLeft, @@ -919,9 +914,7 @@ describe(' - Column spanning', () => { }, ]} columnBufferPx={100} - columnThresholdPx={100} rowBufferPx={50} - rowThresholdPx={50} rowHeight={rowHeight} /> diff --git a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx index cb9965653e9be..97e80fc1f70ee 100644 --- a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx @@ -757,7 +757,6 @@ describe(' - Rows', () => { getBioContentHeight={() => 100} getRowHeight={() => 'auto'} columnBufferPx={0} - columnThresholdPx={0} width={100} />, ); @@ -772,7 +771,6 @@ describe(' - Rows', () => { getBioContentHeight={() => 100} getRowHeight={() => 'auto'} rowBufferPx={0} - rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} height={columnHeaderHeight + 52 + border * 2} />, @@ -808,7 +806,6 @@ describe(' - Rows', () => { density="comfortable" rows={baselineProps.rows.slice(0, 2)} rowBufferPx={0} - rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} />, ); @@ -836,7 +833,6 @@ describe(' - Rows', () => { getBioContentHeight={() => measuredRowHeight} getRowHeight={() => 'auto'} rowBufferPx={0} - rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} getRowId={(row) => row.id} hideFooter={false} @@ -864,7 +860,6 @@ describe(' - Rows', () => { getBioContentHeight={() => measuredRowHeight} getRowHeight={() => 'auto'} rowBufferPx={0} - rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} getRowId={(row) => row.id} hideFooter={false} @@ -893,7 +888,6 @@ describe(' - Rows', () => { getBioContentHeight={() => measuredRowHeight} getRowHeight={() => 'auto'} rowBufferPx={0} - rowThresholdPx={0} columnHeaderHeight={columnHeaderHeight} getRowId={(row) => row.id} hideFooter={false} diff --git a/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx b/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx index 6732fb9c457b7..57f00d3c8af01 100644 --- a/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx +++ b/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx @@ -13,7 +13,7 @@ export default function KeyboardNavigationFocus() { initial focus
- +
); From 5fedc098f860d668be81e9df6f64268dbe353218 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Mon, 11 Mar 2024 22:14:32 -0400 Subject: [PATCH 16/31] lint --- .../src/tests/rows.DataGridPro.test.tsx | 2 +- .../virtualization/useGridVirtualScroller.tsx | 34 +++++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx index e203adbc14b89..0433592c536bc 100644 --- a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx @@ -456,7 +456,7 @@ describe(' - Rows', () => { const lastCell = $$('[role="row"]:last-child [role="gridcell"]')[0]; expect(lastCell).to.have.text('995'); - expect(renderingZone.children.length).to.equal(Math.floor((height) / rowHeight) + n); + expect(renderingZone.children.length).to.equal(Math.floor(height / rowHeight) + n); const scrollbarSize = apiRef.current.state.dimensions.scrollbarSize; const distanceToFirstRow = (nbRows - renderingZone.children.length) * rowHeight; expect(gridOffsetTop()).to.equal(distanceToFirstRow); diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 994809ce1c4a9..de81859388682 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -239,11 +239,7 @@ export const useGridVirtualScroller = () => { ); const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const nextRenderContext = computeRenderContext( - inputs, - scrollPosition.current, - scrollCache, - ); + const nextRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache); // Prevents batching render context changes ReactDOM.flushSync(() => { @@ -257,11 +253,7 @@ export const useGridVirtualScroller = () => { const forceUpdateRenderContext = () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const nextRenderContext = computeRenderContext( - inputs, - scrollPosition.current, - scrollCache, - ); + const nextRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache); updateRenderContext(nextRenderContext); }; @@ -546,11 +538,7 @@ export const useGridVirtualScroller = () => { useRunOnce(outerSize.width !== 0, () => { const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); - const initialRenderContext = computeRenderContext( - inputs, - scrollPosition.current, - scrollCache, - ); + const initialRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache); updateRenderContext(initialRenderContext); apiRef.current.publishEvent('scrollPositionChange', { @@ -671,7 +659,8 @@ function computeRenderContext( const firstRowIndex = Math.min( getNearestIndexToRender(inputs, top, { atStart: true, - lastPosition: inputs.rowsMeta.positions[inputs.rowsMeta.positions.length - 1] + inputs.lastRowHeight, + lastPosition: + inputs.rowsMeta.positions[inputs.rowsMeta.positions.length - 1] + inputs.lastRowHeight, }), inputs.rowsMeta.positions.length - 1, ); @@ -727,7 +716,11 @@ function computeRenderContext( return actualRenderContext; } -function getNearestIndexToRender(inputs: RenderContextInputs, offset: number, options?: SearchOptions) { +function getNearestIndexToRender( + inputs: RenderContextInputs, + offset: number, + options?: SearchOptions, +) { const lastMeasuredIndexRelativeToAllRows = inputs.apiRef.current.getLastMeasuredRowIndex(); let allRowsMeasured = lastMeasuredIndexRelativeToAllRows === Infinity; if (inputs.range?.lastRowIndex && !allRowsMeasured) { @@ -853,7 +846,12 @@ function binarySearch( : binarySearch(offset, positions, options, pivot + 1, sliceEnd); } -function exponentialSearch(offset: number, positions: number[], index: number, options: SearchOptions | undefined = undefined): number { +function exponentialSearch( + offset: number, + positions: number[], + index: number, + options: SearchOptions | undefined = undefined, +): number { let interval = 1; while (index < positions.length && Math.abs(positions[index]) < offset) { From 33ad4edbfbdbceffbff1c74f311d4a70e520052b Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Mon, 11 Mar 2024 22:24:38 -0400 Subject: [PATCH 17/31] lint --- docs/data/data-grid/virtualization/virtualization.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/data/data-grid/virtualization/virtualization.md b/docs/data/data-grid/virtualization/virtualization.md index 7ee018b63d752..fa6bd2a458709 100644 --- a/docs/data/data-grid/virtualization/virtualization.md +++ b/docs/data/data-grid/virtualization/virtualization.md @@ -11,7 +11,7 @@ _\*unlimited: Browsers set a limit on the number of pixels a scroll container ca Row virtualization is the insertion and removal of rows as the data grid scrolls vertically. -The grid renders twice as many rows as are visible. It isn't configurable yet. +The grid renders some additional rows above and below the visible rows. You can use `rowBufferPx` prop to hint to the Data Grid the area to render, but this value may not be respected in certain situations, for example during high-speed scrolling. Row virtualization is limited to 100 rows in the `DataGrid` component. ## Column virtualization @@ -23,11 +23,11 @@ Column virtualization is the insertion and removal of columns as the data grid s - Overscanning more allows the built-in search feature of the browser to find more matching cells. - Overscanning too much can negatively impact performance. -By default, 2 columns are rendered outside of the viewport. You can change this option with the `columnBuffer` prop. The following demo renders 1,000 columns in total: +By default, columns coming under 150 pixels region are rendered outside of the viewport. You can change this option with the `columnBufferPx` prop. As for `rowBufferPx`, the value may be ignored in some situations. The following demo renders 1,000 columns in total: {{"demo": "ColumnVirtualizationGrid.js", "bg": "inline"}} -You can disable column virtualization by setting the column buffer to a higher number than the number of rendered columns, e.g. with `columnBuffer={columns.length}` or `columnBuffer={Number.MAX_SAFE_INTEGER}`. +You can disable column virtualization by calling `apiRef.current.setColumnVirtualization(false)`, or by setting the column buffer to `Number.MAX_SAFE_INTEGER`. ## Disable virtualization From 026a6f6155d89d01ff4811e31ff17613cfec5be8 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Mon, 11 Mar 2024 22:25:52 -0400 Subject: [PATCH 18/31] lint --- .../src/DataGridPremium/DataGridPremium.tsx | 10 ---------- .../x-data-grid-pro/src/DataGridPro/DataGridPro.tsx | 10 ---------- packages/x-data-grid/src/DataGrid/DataGrid.tsx | 10 ---------- 3 files changed, 30 deletions(-) diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 18543e4762acc..50122f49d431c 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -185,11 +185,6 @@ DataGridPremiumRaw.propTypes = { * Set of columns of type [[GridColDef]][]. */ columns: PropTypes.arrayOf(PropTypes.object).isRequired, - /** - * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - columnThresholdPx: PropTypes.number, /** * Set the column visibility model of the Data Grid. * If defined, the Data Grid will ignore the `hide` property in [[GridColDef]]. @@ -946,11 +941,6 @@ DataGridPremiumRaw.propTypes = { * @default "margin" */ rowSpacingType: PropTypes.oneOf(['border', 'margin']), - /** - * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - rowThresholdPx: PropTypes.number, /** * Override the height/width of the Data Grid inner scrollbar. */ diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 2addc9871cc4d..245b38efdef25 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -148,11 +148,6 @@ DataGridProRaw.propTypes = { * Set of columns of type [[GridColDef]][]. */ columns: PropTypes.arrayOf(PropTypes.object).isRequired, - /** - * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - columnThresholdPx: PropTypes.number, /** * Set the column visibility model of the Data Grid. * If defined, the Data Grid will ignore the `hide` property in [[GridColDef]]. @@ -846,11 +841,6 @@ DataGridProRaw.propTypes = { * @default "margin" */ rowSpacingType: PropTypes.oneOf(['border', 'margin']), - /** - * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - rowThresholdPx: PropTypes.number, /** * Override the height/width of the Data Grid inner scrollbar. */ diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 2075dd504556d..3445637103b27 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -134,11 +134,6 @@ DataGridRaw.propTypes = { * Set of columns of type [[GridColDef]][]. */ columns: PropTypes.arrayOf(PropTypes.object).isRequired, - /** - * Number of pixels from the `columnBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - columnThresholdPx: PropTypes.number, /** * Set the column visibility model of the Data Grid. * If defined, the Data Grid will ignore the `hide` property in [[GridColDef]]. @@ -661,11 +656,6 @@ DataGridRaw.propTypes = { * @default "margin" */ rowSpacingType: PropTypes.oneOf(['border', 'margin']), - /** - * Number of pixels from the `rowBuffer` that can be visible before a new slice is rendered. - * @default 150 - */ - rowThresholdPx: PropTypes.number, /** * Override the height/width of the Data Grid inner scrollbar. */ From a996bb430b255b78e7db08100b1757caeda5a8f1 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Mon, 11 Mar 2024 22:46:35 -0400 Subject: [PATCH 19/31] lint --- docs/pages/x/api/data-grid/data-grid-premium.json | 2 -- docs/pages/x/api/data-grid/data-grid-pro.json | 2 -- docs/pages/x/api/data-grid/data-grid.json | 2 -- .../data-grid/data-grid-premium/data-grid-premium.json | 6 ------ .../api-docs/data-grid/data-grid-pro/data-grid-pro.json | 6 ------ .../api-docs/data-grid/data-grid/data-grid.json | 6 ------ 6 files changed, 24 deletions(-) diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index 92fc9c1e2a227..61682f8d2bcfd 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -38,7 +38,6 @@ "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, - "columnThresholdPx": { "type": { "name": "number" }, "default": "150" }, "columnVisibilityModel": { "type": { "name": "object" } }, "defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" }, "density": { @@ -570,7 +569,6 @@ "type": { "name": "enum", "description": "'border'
| 'margin'" }, "default": "\"margin\"" }, - "rowThresholdPx": { "type": { "name": "number" }, "default": "150" }, "scrollbarSize": { "type": { "name": "number" } }, "scrollEndThreshold": { "type": { "name": "number" }, "default": "80" }, "showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 3db3501bc4477..71d7d7191ddc6 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -27,7 +27,6 @@ "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, - "columnThresholdPx": { "type": { "name": "number" }, "default": "150" }, "columnVisibilityModel": { "type": { "name": "object" } }, "defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" }, "density": { @@ -512,7 +511,6 @@ "type": { "name": "enum", "description": "'border'
| 'margin'" }, "default": "\"margin\"" }, - "rowThresholdPx": { "type": { "name": "number" }, "default": "150" }, "scrollbarSize": { "type": { "name": "number" } }, "scrollEndThreshold": { "type": { "name": "number" }, "default": "80" }, "showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 9d9ff7ebb83c4..af039ec19b937 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -19,7 +19,6 @@ "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, - "columnThresholdPx": { "type": { "name": "number" }, "default": "150" }, "columnVisibilityModel": { "type": { "name": "object" } }, "density": { "type": { @@ -399,7 +398,6 @@ "type": { "name": "enum", "description": "'border'
| 'margin'" }, "default": "\"margin\"" }, - "rowThresholdPx": { "type": { "name": "number" }, "default": "150" }, "scrollbarSize": { "type": { "name": "number" } }, "showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, "showColumnVerticalBorder": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index 8d3249c0bcafc..f366e49d043c0 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -45,9 +45,6 @@ "columns": { "description": "Set of columns of type GridColDef[]." }, - "columnThresholdPx": { - "description": "Number of pixels from the columnBuffer that can be visible before a new slice is rendered." - }, "columnVisibilityModel": { "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." }, @@ -593,9 +590,6 @@ "rowSpacingType": { "description": "Sets the type of space between rows added by getRowSpacing." }, - "rowThresholdPx": { - "description": "Number of pixels from the rowBuffer that can be visible before a new slice is rendered." - }, "scrollbarSize": { "description": "Override the height/width of the Data Grid inner scrollbar." }, diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index 94875544d533b..772451634f5d5 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -38,9 +38,6 @@ "columns": { "description": "Set of columns of type GridColDef[]." }, - "columnThresholdPx": { - "description": "Number of pixels from the columnBuffer that can be visible before a new slice is rendered." - }, "columnVisibilityModel": { "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." }, @@ -539,9 +536,6 @@ "rowSpacingType": { "description": "Sets the type of space between rows added by getRowSpacing." }, - "rowThresholdPx": { - "description": "Number of pixels from the rowBuffer that can be visible before a new slice is rendered." - }, "scrollbarSize": { "description": "Override the height/width of the Data Grid inner scrollbar." }, diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index 10583256dea30..c455c98df703b 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -31,9 +31,6 @@ "columns": { "description": "Set of columns of type GridColDef[]." }, - "columnThresholdPx": { - "description": "Number of pixels from the columnBuffer that can be visible before a new slice is rendered." - }, "columnVisibilityModel": { "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." }, @@ -414,9 +411,6 @@ "rowSpacingType": { "description": "Sets the type of space between rows added by getRowSpacing." }, - "rowThresholdPx": { - "description": "Number of pixels from the rowBuffer that can be visible before a new slice is rendered." - }, "scrollbarSize": { "description": "Override the height/width of the Data Grid inner scrollbar." }, From 1c04d643e1c4ebfb732d77d7bf5f1a466e53b630 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Mon, 11 Mar 2024 22:50:59 -0400 Subject: [PATCH 20/31] lint --- .../src/DataGridPremium/DataGridPremium.tsx | 4 ++-- packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx | 4 ++-- packages/x-data-grid/src/DataGrid/DataGrid.tsx | 4 ++-- packages/x-data-grid/src/models/props/DataGridProps.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 50122f49d431c..14acfbb1e6c2c 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -172,7 +172,7 @@ DataGridPremiumRaw.propTypes = { clipboardCopyCellDelimiter: PropTypes.string, /** * Column region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ columnBufferPx: PropTypes.number, columnGroupingModel: PropTypes.arrayOf(PropTypes.object), @@ -873,7 +873,7 @@ DataGridPremiumRaw.propTypes = { processRowUpdate: PropTypes.func, /** * Row region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ rowBufferPx: PropTypes.number, /** diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 245b38efdef25..8e5d2dd6163f1 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -135,7 +135,7 @@ DataGridProRaw.propTypes = { clipboardCopyCellDelimiter: PropTypes.string, /** * Column region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ columnBufferPx: PropTypes.number, columnGroupingModel: PropTypes.arrayOf(PropTypes.object), @@ -783,7 +783,7 @@ DataGridProRaw.propTypes = { processRowUpdate: PropTypes.func, /** * Row region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ rowBufferPx: PropTypes.number, /** diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 3445637103b27..61798a31074bc 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -121,7 +121,7 @@ DataGridRaw.propTypes = { clipboardCopyCellDelimiter: PropTypes.string, /** * Column region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ columnBufferPx: PropTypes.number, columnGroupingModel: PropTypes.arrayOf(PropTypes.object), @@ -610,7 +610,7 @@ DataGridRaw.propTypes = { processRowUpdate: PropTypes.func, /** * Row region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ rowBufferPx: PropTypes.number, /** diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index 84bcc803d0efe..a5d493628b733 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -129,12 +129,12 @@ export interface DataGridPropsWithDefaultValues { checkboxSelectionVisibleOnly: boolean; /** * Column region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ columnBufferPx: number; /** * Row region in pixels to render before/after the viewport - * @default 100 + * @default 150 */ rowBufferPx: number; /** From df5f06b6af7df845b3d8714939f914281e70c8f2 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 13 Mar 2024 11:36:08 -0400 Subject: [PATCH 21/31] Update docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md Co-authored-by: Andrew Cherniavskii Signed-off-by: Rom Grk --- .../migration/migration-data-grid-v6/migration-data-grid-v6.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md index fce67eba44959..49bf03fd99ebf 100644 --- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md +++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md @@ -137,6 +137,7 @@ As a result, the following changes have been made: ``` - The props `rowThreshold` and `columnThreshold` have been removed. + If you had the `rowThreshold` prop set to `0` to force new rows to be rendered more often – this is no longer necessary. ### Behavioral changes From ca76f302e3942b053ed3fbac480773b87aa7ac41 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 14 Mar 2024 03:06:50 -0400 Subject: [PATCH 22/31] lint --- .../migration/migration-data-grid-v6/migration-data-grid-v6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md index 88cad994a790a..99776a38b6218 100644 --- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md +++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md @@ -146,11 +146,11 @@ As a result, the following changes have been made: ``` - The props `rowThreshold` and `columnThreshold` have been removed. + If you had the `rowThreshold` prop set to `0` to force new rows to be rendered more often – this is no longer necessary. - Some feature flags were removed from the `experimentalFeatures` prop. These features are now stable and enabled by default: - [`columnGrouping`](/x/react-data-grid/column-groups/) - [`clipboardPaste`](/x/react-data-grid/clipboard/#clipboard-paste) - [`lazyLoading`](/x/react-data-grid/row-updates/#lazy-loading) - If you had the `rowThreshold` prop set to `0` to force new rows to be rendered more often – this is no longer necessary. ### Behavioral changes From ab1052c1ea7808950e5a7f0ac6c7f4f7761acccc Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 14 Mar 2024 03:10:23 -0400 Subject: [PATCH 23/31] refactor: column width as constant --- .../features/virtualization/useGridVirtualScroller.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 691120e1ac9a2..6123399ef0894 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -45,6 +45,8 @@ import { } from './gridVirtualizationSelectors'; import { EMPTY_RENDER_CONTEXT } from './useGridVirtualization'; +const MINIMUM_COLUMN_WIDTH = 50; + interface PrivateApiWithInfiniteLoader extends GridPrivateApiCommunity, GridInfiniteLoaderPrivateApi {} @@ -137,7 +139,7 @@ export const useGridVirtualScroller = () => { rootProps.rowBufferPx, rootProps.columnBufferPx, dimensions.rowHeight * 15, - 50 * 3, + MINIMUM_COLUMN_WIDTH * 6, ), ).current; @@ -211,7 +213,8 @@ export const useGridVirtualScroller = () => { scrollPosition.current.left - previousContextScrollPosition.current.left, ); - const didCrossThreshold = rowScroll >= dimensions.rowHeight || columnScroll >= 50; + // PERF: use the computed minimum column width instead of a static one + const didCrossThreshold = rowScroll >= dimensions.rowHeight || columnScroll >= MINIMUM_COLUMN_WIDTH; const didChangeDirection = scrollCache.direction !== direction; const shouldUpdate = didCrossThreshold || didChangeDirection; @@ -240,7 +243,7 @@ export const useGridVirtualScroller = () => { rootProps.rowBufferPx, rootProps.columnBufferPx, dimensions.rowHeight * 15, - 50 * 3, + MINIMUM_COLUMN_WIDTH * 6, ); const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns); From f489228c6c88bb86346c33d41efd20a0e26d4863 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 14 Mar 2024 03:17:48 -0400 Subject: [PATCH 24/31] lint --- docs/data/data-grid/virtualization/virtualization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data/data-grid/virtualization/virtualization.md b/docs/data/data-grid/virtualization/virtualization.md index fa6bd2a458709..82481e4548e92 100644 --- a/docs/data/data-grid/virtualization/virtualization.md +++ b/docs/data/data-grid/virtualization/virtualization.md @@ -27,7 +27,7 @@ By default, columns coming under 150 pixels region are rendered outside of the v {{"demo": "ColumnVirtualizationGrid.js", "bg": "inline"}} -You can disable column virtualization by calling `apiRef.current.setColumnVirtualization(false)`, or by setting the column buffer to `Number.MAX_SAFE_INTEGER`. +You can disable column virtualization by calling `apiRef.current.unstable_setColumnVirtualization(false)`, or by setting the column buffer to `Number.MAX_SAFE_INTEGER`. ## Disable virtualization From 1b5ef9338a045c47a77ef1347898e0d905849de9 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 14 Mar 2024 03:22:04 -0400 Subject: [PATCH 25/31] lint --- .../hooks/features/virtualization/useGridVirtualScroller.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 6123399ef0894..54c7c3f8c4383 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -214,7 +214,8 @@ export const useGridVirtualScroller = () => { ); // PERF: use the computed minimum column width instead of a static one - const didCrossThreshold = rowScroll >= dimensions.rowHeight || columnScroll >= MINIMUM_COLUMN_WIDTH; + const didCrossThreshold = + rowScroll >= dimensions.rowHeight || columnScroll >= MINIMUM_COLUMN_WIDTH; const didChangeDirection = scrollCache.direction !== direction; const shouldUpdate = didCrossThreshold || didChangeDirection; From b492aacb1e9ac426a5e3db0195f44a152d463883 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 14 Mar 2024 03:32:14 -0400 Subject: [PATCH 26/31] lint --- docs/pages/x/api/data-grid/data-grid-premium.json | 4 ++-- docs/pages/x/api/data-grid/data-grid-pro.json | 4 ++-- docs/pages/x/api/data-grid/data-grid.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index 362e34cb8fb69..da5cae9183dbc 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -36,7 +36,7 @@ "checkboxSelectionVisibleOnly": { "type": { "name": "bool" }, "default": "false" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, - "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, + "columnBufferPx": { "type": { "name": "number" }, "default": "150" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, "columnVisibilityModel": { "type": { "name": "object" } }, "defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" }, @@ -541,7 +541,7 @@ "returned": "Promise | R" } }, - "rowBufferPx": { "type": { "name": "number" }, "default": "100" }, + "rowBufferPx": { "type": { "name": "number" }, "default": "150" }, "rowCount": { "type": { "name": "number" } }, "rowGroupingColumnMode": { "type": { "name": "enum", "description": "'multiple'
| 'single'" }, diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 1e083b462338f..91b93b4382cee 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -25,7 +25,7 @@ "checkboxSelectionVisibleOnly": { "type": { "name": "bool" }, "default": "false" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, - "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, + "columnBufferPx": { "type": { "name": "number" }, "default": "150" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, "columnVisibilityModel": { "type": { "name": "object" } }, "defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" }, @@ -488,7 +488,7 @@ "returned": "Promise | R" } }, - "rowBufferPx": { "type": { "name": "number" }, "default": "100" }, + "rowBufferPx": { "type": { "name": "number" }, "default": "150" }, "rowCount": { "type": { "name": "number" } }, "rowHeight": { "type": { "name": "number" }, "default": "52" }, "rowModesModel": { "type": { "name": "object" } }, diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 842a242933a2e..7828f6fca9ee5 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -24,7 +24,7 @@ "checkboxSelection": { "type": { "name": "bool" }, "default": "false" }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" }, - "columnBufferPx": { "type": { "name": "number" }, "default": "100" }, + "columnBufferPx": { "type": { "name": "number" }, "default": "150" }, "columnHeaderHeight": { "type": { "name": "number" }, "default": "56" }, "columnVisibilityModel": { "type": { "name": "object" } }, "density": { @@ -405,7 +405,7 @@ "returned": "Promise | R" } }, - "rowBufferPx": { "type": { "name": "number" }, "default": "100" }, + "rowBufferPx": { "type": { "name": "number" }, "default": "150" }, "rowCount": { "type": { "name": "number" } }, "rowHeight": { "type": { "name": "number" }, "default": "52" }, "rowModesModel": { "type": { "name": "object" } }, From 9ac297bfd3e9eef29a1ce6c2f1a39fb1b626943c Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 14 Mar 2024 23:56:51 -0400 Subject: [PATCH 27/31] test: disable virtualization in jsdom --- .../features/virtualization/useGridVirtualScroller.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 54c7c3f8c4383..9583879e5a85a 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -83,12 +83,14 @@ const createScrollCache = ( }); type ScrollCache = ReturnType; +const isJSDOM = typeof window !== 'undefined' ? /jsdom/.test(window.navigator.userAgent) : false; + export const useGridVirtualScroller = () => { const apiRef = useGridPrivateApiContext() as React.MutableRefObject; const rootProps = useGridRootProps(); const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); - const enabled = useGridSelector(apiRef, gridVirtualizationEnabledSelector); - const enabledForColumns = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector); + const enabled = useGridSelector(apiRef, gridVirtualizationEnabledSelector) && !isJSDOM; + const enabledForColumns = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector) && !isJSDOM; const dimensions = useGridSelector(apiRef, gridDimensionsSelector); const outerSize = dimensions.viewportOuterSize; const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector); From d43b2a83ba70f74ae84b3d7781ae6a8ec3d6297c Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Fri, 15 Mar 2024 00:36:25 -0400 Subject: [PATCH 28/31] lint --- .../hooks/features/virtualization/useGridVirtualScroller.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx index 9583879e5a85a..8ed66d64e1ae8 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx @@ -90,7 +90,8 @@ export const useGridVirtualScroller = () => { const rootProps = useGridRootProps(); const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); const enabled = useGridSelector(apiRef, gridVirtualizationEnabledSelector) && !isJSDOM; - const enabledForColumns = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector) && !isJSDOM; + const enabledForColumns = + useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector) && !isJSDOM; const dimensions = useGridSelector(apiRef, gridDimensionsSelector); const outerSize = dimensions.viewportOuterSize; const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector); From 97defb74bcf8c19eb45324c1c125e01f93ad8f6d Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Tue, 19 Mar 2024 07:05:11 -0400 Subject: [PATCH 29/31] fix: async autosizing demo --- .../data-grid/column-dimensions/ColumnAutosizingAsync.js | 5 ++++- .../data-grid/column-dimensions/ColumnAutosizingAsync.tsx | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js index 58cdeef72eb40..ae1319171524c 100644 --- a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js +++ b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js @@ -60,10 +60,13 @@ export default function ColumnAutosizingAsync() { setIsLoading(true); getFakeData(100) .then((data) => { - return ReactDOM.flushSync(() => { + ReactDOM.flushSync(() => { setIsLoading(false); apiRef.current.updateRows(data.rows); }); + // `setTimeout` is required because `.updateRows` is an async + // function throttled to avoid choking on frequent changes. + return new Promise((resolve) => setTimeout(resolve, 0)); }) .then(() => apiRef.current.autosizeColumns({ diff --git a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx index 3c00a2b4bb01f..d8c62dcbfd74d 100644 --- a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx +++ b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx @@ -60,10 +60,13 @@ export default function ColumnAutosizingAsync() { setIsLoading(true); getFakeData(100) .then((data) => { - return ReactDOM.flushSync(() => { + ReactDOM.flushSync(() => { setIsLoading(false); apiRef.current.updateRows(data.rows); }); + // `setTimeout` is required because `.updateRows` is an async + // function throttled to avoid choking on frequent changes. + return new Promise((resolve) => setTimeout(resolve, 0)) }) .then(() => apiRef.current.autosizeColumns({ From 4d45e2230b45acee4d1cdabd20d41265c2f1cb77 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Tue, 19 Mar 2024 07:33:37 -0400 Subject: [PATCH 30/31] lint --- .../column-dimensions/ColumnAutosizingAsync.js | 12 +++++++++--- .../column-dimensions/ColumnAutosizingAsync.tsx | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js index ae1319171524c..06da1d5d56555 100644 --- a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js +++ b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js @@ -64,10 +64,10 @@ export default function ColumnAutosizingAsync() { setIsLoading(false); apiRef.current.updateRows(data.rows); }); - // `setTimeout` is required because `.updateRows` is an async - // function throttled to avoid choking on frequent changes. - return new Promise((resolve) => setTimeout(resolve, 0)); }) + // `sleep`/`setTimeout` is required because `.updateRows` is an + // async function throttled to avoid choking on frequent changes. + .then(() => sleep(0)) .then(() => apiRef.current.autosizeColumns({ includeHeaders: true, @@ -106,3 +106,9 @@ export default function ColumnAutosizingAsync() { ); } + +function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} diff --git a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx index d8c62dcbfd74d..650f0e1bced9e 100644 --- a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx +++ b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx @@ -64,10 +64,10 @@ export default function ColumnAutosizingAsync() { setIsLoading(false); apiRef.current.updateRows(data.rows); }); - // `setTimeout` is required because `.updateRows` is an async - // function throttled to avoid choking on frequent changes. - return new Promise((resolve) => setTimeout(resolve, 0)) }) + // `sleep`/`setTimeout` is required because `.updateRows` is an + // async function throttled to avoid choking on frequent changes. + .then(() => sleep(0)) .then(() => apiRef.current.autosizeColumns({ includeHeaders: true, @@ -106,3 +106,9 @@ export default function ColumnAutosizingAsync() { ); } + +function sleep(ms: number) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} From a5db4a48a9eed84f30e519640e2a3f4342239024 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Wed, 20 Mar 2024 01:44:22 -0400 Subject: [PATCH 31/31] lint --- packages/x-data-grid/src/models/props/DataGridProps.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index adc3cb26c21f9..eca76ffebad09 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -142,11 +142,6 @@ export interface DataGridPropsWithDefaultValues { * @default true */ rowSelection: boolean; - /** - * Set the density of the Data Grid. - * @default "standard" - */ - density: GridDensity; /** * If `true`, column filters are disabled. * @default false