Skip to content

Commit

Permalink
Add invisible cells to measure column widths regardless of column spa…
Browse files Browse the repository at this point in the history
…nning (adazzle#3024)

* Add invisible cells to measure column widths regardless of column spanning

* rm log

* tweak comment

* fix odd subpixel rendering

* tweaked comment

* typo

* add layer
  • Loading branch information
nstepien authored Sep 16, 2022
1 parent 4a136ad commit 88df30b
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 23 deletions.
31 changes: 17 additions & 14 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
sign,
abs,
getSelectedCellColSpan,
renderMeasuringCells,
scrollIntoView
} from './utils';

Expand Down Expand Up @@ -435,29 +436,28 @@ function DataGrid<R, SR, K extends Key>(

useLayoutEffect(() => {
if (!isWidthInitialized || flexWidthViewportColumns.length === 0) return;
const newColumnWidths = new Map<string, number>();
for (const column of flexWidthViewportColumns) {
const columnElement = gridRef.current!.querySelector<HTMLDivElement>(
`[aria-colindex="${column.idx + 1}"]`
);
if (columnElement) {

setColumnWidths((columnWidths) => {
const newColumnWidths = new Map(columnWidths);
const grid = gridRef.current!;

for (const column of flexWidthViewportColumns) {
const measuringCell = grid.querySelector(`[data-measuring-cell-key="${column.key}"]`)!;
// Set the actual width of the column after it is rendered
const { width } = columnElement.getBoundingClientRect();
const { width } = measuringCell.getBoundingClientRect();
newColumnWidths.set(column.key, width);
}
}
if (newColumnWidths.size === 0) return;
setColumnWidths((columnWidths) => {
return new Map([...columnWidths, ...newColumnWidths]);

return newColumnWidths;
});
}, [isWidthInitialized, flexWidthViewportColumns, gridRef]);

useLayoutEffect(() => {
if (autoResizeColumn === null) return;
const columnElement = gridRef.current!.querySelector(
`[aria-colindex="${autoResizeColumn.idx + 1}"]`
const measuringCell = gridRef.current!.querySelector(
`[data-measuring-cell-key="${autoResizeColumn.key}"]`
)!;
const { width } = columnElement.getBoundingClientRect();
const { width } = measuringCell.getBoundingClientRect();
setColumnWidths((columnWidths) => {
const newColumnWidths = new Map(columnWidths);
newColumnWidths.set(autoResizeColumn.key, width);
Expand Down Expand Up @@ -1295,6 +1295,9 @@ function DataGrid<R, SR, K extends Key>(
})}
</>
)}

{/* render empty cells that span only 1 column so we can safely measure column widths, regardless of colSpan */}
{renderMeasuringCells({ viewportColumns })}
</DataGridDefaultComponentsProvider>
</div>
);
Expand Down
6 changes: 1 addition & 5 deletions src/HeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,7 @@ export default function HeaderCell<R, SR>({
// set the tabIndex to 0 when there is no selected cell so grid can receive focus
tabIndex={shouldFocusGrid ? 0 : tabIndex}
className={className}
style={{
...getCellStyle(column, colSpan),
minWidth: column.minWidth,
maxWidth: column.maxWidth ?? undefined
}}
style={getCellStyle(column, colSpan)}
onFocus={handleFocus}
onClick={onClick}
onDoubleClick={column.resizable ? onDoubleClick : undefined}
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useCalculatedColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function useCalculatedColumns<R, SR>({
}: CalculatedColumnsArgs<R, SR>) {
const defaultWidth = defaultColumnOptions?.width ?? DEFAULT_COLUMN_WIDTH;
const defaultMinWidth = defaultColumnOptions?.minWidth ?? DEFAULT_COLUMN_MIN_WIDTH;
const defaultMaxWidth = defaultColumnOptions?.maxWidth;
const defaultMaxWidth = defaultColumnOptions?.maxWidth ?? undefined;
const defaultFormatter = defaultColumnOptions?.formatter ?? valueFormatter;
const defaultSortable = defaultColumnOptions?.sortable ?? false;
const defaultResizable = defaultColumnOptions?.resizable ?? false;
Expand Down
5 changes: 3 additions & 2 deletions src/style/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ export const cell = css`

export const cellClassname = `rdg-cell ${cell}`;

// max-content does not calculate width when contain is set to style or size
// max-content does not work when size containment is enabled
// `contain: content` leads to odd subpixel mismatches when combined with colSpan
export const autosizeColumnsClassname = css`
@layer rdg.Root {
.${cell} {
contain: content;
contain: style;
}
}
`;
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface CalculatedColumn<TRow, TSummaryRow = unknown> extends Column<TR
readonly idx: number;
readonly width: number | string;
readonly minWidth: number;
readonly maxWidth: number | undefined;
readonly resizable: boolean;
readonly sortable: boolean;
readonly frozen: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { CalculatedColumn } from '../types';
export * from './colSpanUtils';
export * from './domUtils';
export * from './keyboardUtils';
export * from './renderMeasuringCells';
export * from './selectedCellUtils';
export * from './styleUtils';

Expand Down
29 changes: 29 additions & 0 deletions src/utils/renderMeasuringCells.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { css } from '@linaria/core';
import type { CalculatedColumn } from '../types';

const measuringCellClassname = css`
@layer rdg.MeasuringCell {
contain: strict;
grid-row: 1;
visibility: hidden;
}
`;

export function renderMeasuringCells<R, SR>({
viewportColumns
}: {
viewportColumns: readonly CalculatedColumn<R, SR>[];
}) {
return (
<>
{viewportColumns.map(({ key, idx, minWidth, maxWidth }) => (
<div
key={key}
className={measuringCellClassname}
style={{ gridColumnStart: idx + 1, minWidth, maxWidth }}
data-measuring-cell-key={key}
/>
))}
</>
);
}
1 change: 0 additions & 1 deletion website/demos/ColumnSpanning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export default function ColumnSpanning({ direction }: Props) {
key,
name: key,
frozen: i < 5,
width: 80,
resizable: true,
formatter: cellFormatter,
colSpan(args) {
Expand Down

0 comments on commit 88df30b

Please sign in to comment.