-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix column auto resize #3746
base: main
Are you sure you want to change the base?
Fix column auto resize #3746
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3746 +/- ##
==========================================
+ Coverage 98.65% 98.75% +0.09%
==========================================
Files 47 47
Lines 3426 3451 +25
Branches 742 753 +11
==========================================
+ Hits 3380 3408 +28
+ Misses 46 43 -3
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}); | ||
|
||
function updateMeasuredWidths(columnsToMeasure: readonly string[]) { | ||
if (columnsToMeasure.length === 0) return; | ||
function updateMeasuredAndResizedWidths() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could inline this in the layout effect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add dependencies and useMemo
for columnsToMeasure
but not sure it is worth. Wdyt?
// need flushSync to keep frozen column offsets in sync | ||
// we may be able to use `startTransition` or even `requestIdleCallback` instead | ||
flushSync(() => { | ||
if (typeof nextWidth === 'number') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this will correctly handle min/max-widths
We need to set the width, render, measure the cell, store the measured width instead of trusting nextWidth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it does. I will double check
https://github.com/adazzle/react-data-grid/blob/main/src/HeaderCell.tsx#L128
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works. We should put the min/max logic in one place
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
min / max can't overflow in case styles are applied to the measurement cells correctly, and grid re-render is synchronized
I also found it helpful to use styles instead of JS for this, especially when you can have different styles for cells while measuring (when we set its size to "max-content" for example, and will measure its size after):
You want to have a grid with auto-sized columns but with some rules for this auto-size mechanism:
min: 50px
max: 300px
But at the same time, you want to be able to resize columns to exceed these values manually.
In this situation, you will have different rules for measured cells and while measuring:
When measuring cells (like "max-content" or "auto"), we want to apply these rules to that cell
but when we resize manually, we don't
.measuringCellClassname {
min-width: 20px;
}
.measuringCellClassname[measuring] {
min-width: 50px;
max-width: 300px
}
This is why I've added this code also:
https://github.com/adazzle/react-data-grid/pull/3724/files#diff-62e848727f791df23e85ccc2140643630d80c20c5140f073aba8f581eb122019L13-R26
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But at the same time, you want to be able to resize columns to exceed these values manually.
We want the same rules for bot cases. If maxWidth
is specified then users should not be able to increase the width past that value.
I also found it helpful to use styles instead of JS
We already setmin/maxWidth
on the measuring cell
https://github.com/adazzle/react-data-grid/blob/main/src/utils/renderMeasuringCells.tsx#L18
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, but I'm talking about cases when you have not specified maxWidth for the column, and this max-width
only applies to the moment when we calculate the size of the column in cases when both are specified:
column.maxWidth: 100px
measuringCellClassname[measuring] { max-width: 200px; }
then it should not exceed 100px
But in case:
column.maxWidth: 100px
measuringCellClassname[measuring] { max-width: 50px; }
the auto-sized width will not exceed 50px but can be re-sized up to 100px manually
const grid = getGrid(); | ||
expect(onColumnResize).not.toHaveBeenCalled(); | ||
await expect.element(grid).toHaveStyle({ gridTemplateColumns: '100px 200px' }); | ||
const [, col2] = getHeaderCells(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand, surely the cell element should still be in the document if we get it earlier, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be. I will investigate in a separate PR
await autoResize(col2); | ||
await expect.element(grid).toHaveStyle({ gridTemplateColumns: '100px 327.703px' }); | ||
// This is called twice in strict mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it? Do we not check to only call the function if the width has changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does call it twice. May be the state updates after the useLayoutEffect
has run twice
if (columnToAutoResize !== null) { |
@@ -16,6 +15,7 @@ export function useColumnWidths<R, SR>( | |||
setMeasuredColumnWidths: StateSetter<ReadonlyMap<string, number>>, | |||
onColumnResize: DataGridProps<R, SR>['onColumnResize'] | |||
) { | |||
const [columnToAutoResize, setColumnToAutoResize] = useState<string | null>(null); | |||
const prevGridWidthRef = useRef(gridWidth); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@amanmahajan7
I think you better not use ref for the previous grid width. There is a bug with the initial render when:
- table rendered with a different width from the previous
- columns calculated + updated
- table rendered with a different width from the previous
- columns calculated but aren't updated (because of the same widths) -> there are no re-render -> cells will have "measurement" size (like "max-content") and will change size on content size
This issue is reflected in my video from this comment: #3723 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check if this issues still exists in my PR? I think the issue you are describing was related to #3724 (comment)
}); | ||
|
||
onColumnResize?.(column, measuredWidth); | ||
onColumnResize?.(column, nextWidth); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will suggest moving the onColumnResize call to the setter function to have the same possible behavior for resizing
https://github.com/adazzle/react-data-grid/pull/3746/files#diff-e002f181d41ce4fd6e070724347a44e4220d0332c37e5964d04cb3fc5d60d416R77
(or vice-versa)
This exists in main also. I believe the reason is that we are not restricting width calculation using grid columns and instead we are using |
Fixes #3723
Root cause: #3724 (comment)