Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as React from 'react';
import { createRenderer, fireEvent, screen, act, waitFor } from '@mui/internal-test-utils';
import { spy } from 'sinon';
import { type RefObject } from '@mui/x-internals/types';
Expand All @@ -10,6 +11,7 @@ import {
gridColumnFieldsSelector,
type GridApi,
type GridAutosizeOptions,
type GridColDef,
} from '@mui/x-data-grid-pro';
import { useGridPrivateApiContext } from '@mui/x-data-grid-pro/internals';
import { getColumnHeaderCell, getCell, getRow } from 'test/utils/helperFn';
Expand Down Expand Up @@ -635,6 +637,59 @@ describe('<DataGridPro /> - Columns', () => {
});
});

// Regression test for https://github.com/mui/mui-x/issues/22505
it('should wait for all rows to be rendered on mount when rows fit the viewport', async () => {
const shortValue = 'Nike';
const wideValue = 'Lululemon Athletica International Collection';

function DeferredCellContent({ value }: { value: string }) {
const [showValue, setShowValue] = React.useState(value === shortValue);

React.useEffect(() => {
if (!showValue) {
// Hack to make the test fail similar to https://github.com/mui/mui-x/issues/22505
// in our test env
Promise.resolve().then(() => {
Promise.resolve().then(() => setShowValue(true));
});
}
}, [showValue]);
Comment thread
MBilalShafi marked this conversation as resolved.

return <span>{showValue ? value : shortValue}</span>;
}

const autosizeRows = [
{ id: 0, brand: 'Nike' },
{ id: 1, brand: 'Adidas' },
{ id: 2, brand: 'Puma' },
{ id: 3, brand: 'Reebok' },
{ id: 4, brand: 'Asics' },
{ id: 5, brand: 'New Balance' },
{ id: 6, brand: wideValue },
];
const autosizeColumns: GridColDef[] = [
{
field: 'brand',
renderCell: ({ value }) => <DeferredCellContent value={value} />,
},
];

render(
<Test
rows={autosizeRows}
columns={autosizeColumns}
autosizeOnMount
autosizeOptions={{ columns: ['brand'], includeOutliers: true }}
/>,
);

await waitFor(() => {
const wideCell = getCell(6, 0);
expect(wideCell.textContent).to.equal(wideValue);
expect(wideCell.scrollWidth).to.be.at.most(wideCell.clientWidth);
});
});

it('should work with flex columns', async () => {
const { user } = render(
<Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ import {
useGridSelector,
useOnMount,
} from '../../utils';
import { gridVirtualizationColumnEnabledSelector } from '../virtualization';
import {
gridRenderContextSelector,
gridVirtualizationColumnEnabledSelector,
} from '../virtualization';
import {
type ControllablePromise,
createControllablePromise,
Expand All @@ -51,6 +54,7 @@ import { GridPinnedColumnPosition } from '../columns/gridColumnsInterfaces';
import { gridColumnsStateSelector } from '../columns';
import { gridDimensionsSelector } from '../dimensions';
import { gridHeaderFilteringEnabledSelector } from '../headerFiltering';
import { gridVisibleRowsSelector } from '../pagination';
import type { DataGridProcessedProps } from '../../../models/props/DataGridProps';
import type { GridColumnResizeParams } from '../../../models/params/gridColumnResizeParams';
import type { GridStateColDef } from '../../../models/colDef/gridColDef';
Expand All @@ -62,6 +66,29 @@ type AutosizeOptionsRequired = Required<GridAutosizeOptions>;

type ResizeDirection = keyof typeof GridColumnHeaderSeparatorSides;

function isRenderContextReadyForAutosizeOnMount(apiRef: RefObject<GridPrivateApiCommunity>) {
const dimensions = gridDimensionsSelector(apiRef);
if (!dimensions.isReady) {
return false;
}

const { rows } = gridVisibleRowsSelector(apiRef);
if (rows.length === 0) {
return true;
}

const renderContext = gridRenderContextSelector(apiRef);
if (renderContext.lastRowIndex <= renderContext.firstRowIndex) {
return false;
}

if (!dimensions.hasScrollY) {
return renderContext.firstRowIndex === 0 && renderContext.lastRowIndex >= rows.length;
}

return true;
}

function trackFinger(event: any, currentTouchId: number | undefined): CursorCoordinates | boolean {
if (currentTouchId !== undefined && event.changedTouches) {
for (let i = 0; i < event.changedTouches.length; i += 1) {
Expand Down Expand Up @@ -851,10 +878,52 @@ export const useGridColumnResize = (

useOnMount(() => {
if (props.autosizeOnMount) {
Promise.resolve().then(() => {
let frameHandle: number | undefined;
let unsubscribeStateChange: (() => void) | undefined;
let unsubscribeRenderedRowsIntervalChange: (() => void) | undefined;

const cleanupListeners = () => {
unsubscribeStateChange?.();
unsubscribeRenderedRowsIntervalChange?.();
unsubscribeStateChange = undefined;
unsubscribeRenderedRowsIntervalChange = undefined;
};

const runAutosize = () => {
frameHandle = undefined;
cleanupListeners();
apiRef.current.autosizeColumns(props.autosizeOptions);
});
};

const scheduleAutosize = () => {
if (frameHandle === undefined) {
frameHandle = requestAnimationFrame(runAutosize);
}
};

const checkRenderContext = () => {
if (isRenderContextReadyForAutosizeOnMount(apiRef)) {
scheduleAutosize();
}
};

unsubscribeStateChange = apiRef.current.subscribeEvent('stateChange', checkRenderContext);
unsubscribeRenderedRowsIntervalChange = apiRef.current.subscribeEvent(
'renderedRowsIntervalChange',
checkRenderContext,
);

checkRenderContext();

return () => {
cleanupListeners();
if (frameHandle !== undefined) {
cancelAnimationFrame(frameHandle);
}
};
}

return undefined;
});

useGridNativeEventListener(
Expand Down
Loading