Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
ec08ef0
Add support for "auto" width
Feb 22, 2022
ff6ae11
Calculate columns when grid width is set
Feb 23, 2022
9a8f6f3
Remove unnecessary code
Feb 23, 2022
04d61cb
Merge branch 'main' into am-auto-columns
Feb 23, 2022
f1d9109
Merge branch 'main' into am-auto-columns
amanmahajan7 Feb 23, 2022
a291318
Add support for css column units (fr, %, max-content)
Feb 25, 2022
e6e3230
Bring back virtualization
Feb 25, 2022
def96f2
Remove console
Feb 25, 2022
c5634e5
Fix minWidth and examples
Feb 26, 2022
391e780
Merge branch 'main' into am-auto-columns
amanmahajan7 Feb 28, 2022
efafea7
Add min width
Mar 14, 2022
358b7ad
Disable @typescript-eslint/naming-convention
Mar 15, 2022
4ab2529
Merge branch 'main' into am-auto-columns
amanmahajan7 Mar 15, 2022
085fd02
Add comments
Mar 15, 2022
41bea02
Revent some changes
Mar 15, 2022
a701693
Use getBoundingClientRect
Mar 15, 2022
dfb71aa
Rename variables
Mar 15, 2022
d7a6edf
Merge branch 'main' into am-auto-columns
Mar 31, 2022
fd6db55
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 4, 2022
7fa2267
Merge branch 'main' into am-auto-columns
Apr 6, 2022
9bc8500
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 7, 2022
45799e2
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 7, 2022
801b956
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 8, 2022
b34375d
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 12, 2022
e0a8624
support flex width on all the columns
Apr 18, 2022
6b1233b
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 20, 2022
ff24d72
Merge branch 'main' into am-auto-columns
amanmahajan7 Apr 21, 2022
dabb46e
Merge branch 'main' into am-auto-columns
amanmahajan7 May 4, 2022
07212fa
Merge branch 'main' into am-auto-columns
Aug 15, 2022
e76c3aa
Merge branch 'main' into am-auto-columns
amanmahajan7 Aug 15, 2022
8ef79be
Catchup main
amanmahajan7 Sep 14, 2022
0bd458b
Fix tests
amanmahajan7 Sep 14, 2022
b0abe58
Merge branch 'main' into am-auto-columns
amanmahajan7 Sep 15, 2022
f17731a
Update src/DataGrid.tsx
amanmahajan7 Sep 15, 2022
aa8485a
Address a few comments
amanmahajan7 Sep 15, 2022
eb899a9
Move width type close to minWidth
amanmahajan7 Sep 15, 2022
40a1c75
Merge branch 'main' into am-auto-columns
amanmahajan7 Sep 15, 2022
76aee36
Do not reset max-content columns
amanmahajan7 Sep 15, 2022
740ff89
Merge branch 'main' into am-auto-columns
amanmahajan7 Sep 16, 2022
05a4521
Remove flexColumnWidths state
amanmahajan7 Sep 16, 2022
2e38b07
Add max-content example
amanmahajan7 Sep 16, 2022
284dae9
Merge branch 'main' into am-auto-columns
amanmahajan7 Sep 16, 2022
4691248
Update src/DataGrid.tsx
amanmahajan7 Sep 16, 2022
a226262
Fix classname
amanmahajan7 Sep 16, 2022
0a6aaf4
Update src/hooks/useGridDimensions.ts
amanmahajan7 Sep 16, 2022
e34a87d
Remove useMemo
amanmahajan7 Sep 16, 2022
945f776
Add back useMemo
amanmahajan7 Sep 16, 2022
151d724
tweak autosizeColumnsClassname for better measuring
nstepien Sep 16, 2022
edc46e7
Revert "tweak autosizeColumnsClassname for better measuring"
nstepien Sep 16, 2022
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
43 changes: 35 additions & 8 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
rootClassname,
viewportDraggingClassname,
focusSinkClassname,
cellAutoResizeClassname,
autosizeColumnsClassname,
rowSelected,
rowSelectedWithFrozenCell
} from './style';
Expand Down Expand Up @@ -282,7 +282,7 @@ function DataGrid<R, SR, K extends Key>(
/**
* computed values
*/
const [gridRef, gridWidth, gridHeight] = useGridDimensions();
const [gridRef, gridWidth, gridHeight, isWidthInitialized] = useGridDimensions();
const headerRowsCount = 1;
const topSummaryRowsCount = topSummaryRows?.length ?? 0;
const bottomSummaryRowsCount = bottomSummaryRows?.length ?? 0;
Expand Down Expand Up @@ -355,7 +355,7 @@ function DataGrid<R, SR, K extends Key>(
enableVirtualization
});

const viewportColumns = useViewportColumns({
const { viewportColumns, flexWidthViewportColumns } = useViewportColumns({
columns,
colSpanColumns,
colOverscanStartIdx,
Expand All @@ -366,6 +366,7 @@ function DataGrid<R, SR, K extends Key>(
rows,
topSummaryRows,
bottomSummaryRows,
columnWidths,
isGroupRow
});

Expand Down Expand Up @@ -432,6 +433,25 @@ function DataGrid<R, SR, K extends Key>(
}
});

useLayoutEffect(() => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This effect is run if the viewport has any flex columns.

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) {
// Set the actual width of the column after it is rendered
const { width } = columnElement.getBoundingClientRect();
newColumnWidths.set(column.key, width);
}
}
if (newColumnWidths.size === 0) return;
setColumnWidths((columnWidths) => {
return new Map([...columnWidths, ...newColumnWidths]);
});
}, [isWidthInitialized, flexWidthViewportColumns, gridRef]);

useLayoutEffect(() => {
if (autoResizeColumn === null) return;
const columnElement = gridRef.current!.querySelector(
Expand Down Expand Up @@ -465,8 +485,8 @@ function DataGrid<R, SR, K extends Key>(
* callbacks
*/
const handleColumnResize = useCallback(
(column: CalculatedColumn<R, SR>, width: number | 'auto') => {
if (width === 'auto') {
(column: CalculatedColumn<R, SR>, width: number | 'max-content') => {
if (width === 'max-content') {
setAutoResizeColumn(column);
return;
}
Expand Down Expand Up @@ -909,10 +929,16 @@ function DataGrid<R, SR, K extends Key>(
}

function getLayoutCssVars() {
if (autoResizeColumn === null) return layoutCssVars;
if (autoResizeColumn === null && flexWidthViewportColumns.length === 0) return layoutCssVars;
const { gridTemplateColumns } = layoutCssVars;
const newSizes = gridTemplateColumns.split(' ');
newSizes[autoResizeColumn.idx] = 'max-content';
if (autoResizeColumn !== null) {
newSizes[autoResizeColumn.idx] = 'max-content';
}
for (const column of flexWidthViewportColumns) {
newSizes[column.idx] = column.width as string;
}

return {
...layoutCssVars,
gridTemplateColumns: newSizes.join(' ')
Expand Down Expand Up @@ -1146,7 +1172,8 @@ function DataGrid<R, SR, K extends Key>(
rootClassname,
{
[viewportDraggingClassname]: isDragging,
[cellAutoResizeClassname]: autoResizeColumn !== null
[autosizeColumnsClassname]:
autoResizeColumn !== null || flexWidthViewportColumns.length > 0
},
className
)}
Expand Down
2 changes: 1 addition & 1 deletion src/HeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export default function HeaderCell<R, SR>({
return;
}

onColumnResize(column, 'auto');
onColumnResize(column, 'max-content');
}

function handleFocus(event: React.FocusEvent<HTMLDivElement>) {
Expand Down
2 changes: 1 addition & 1 deletion src/HeaderRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface HeaderRowProps<R, SR, K extends React.Key> extends SharedDataGr
columns: readonly CalculatedColumn<R, SR>[];
allRowsSelected: boolean;
onAllRowsSelectionChange: (checked: boolean) => void;
onColumnResize: (column: CalculatedColumn<R, SR>, width: number | 'auto') => void;
onColumnResize: (column: CalculatedColumn<R, SR>, width: number | 'max-content') => void;
selectCell: (columnIdx: number) => void;
lastFrozenColumnIndex: number;
selectedCellIdx: number | undefined;
Expand Down
63 changes: 14 additions & 49 deletions src/hooks/useCalculatedColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { CalculatedColumn, Column, Maybe } from '../types';
import type { DataGridProps } from '../DataGrid';
import { valueFormatter, toggleGroupFormatter } from '../formatters';
import { SELECT_COLUMN_KEY } from '../Columns';
import { clampColumnWidth, floor, max, min, round } from '../utils';
import { clampColumnWidth, max, min } from '../utils';

type Mutable<T> = {
-readonly [P in keyof T]: T[P];
Expand All @@ -15,6 +15,9 @@ interface ColumnMetric {
left: number;
}

const DEFAULT_COLUMN_WIDTH = 'auto';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before
image

After
image

const DEFAULT_COLUMN_MIN_WIDTH = 80;

interface CalculatedColumnsArgs<R, SR> extends Pick<DataGridProps<R, SR>, 'defaultColumnOptions'> {
rawColumns: readonly Column<R, SR>[];
rawGroupBy: Maybe<readonly string[]>;
Expand All @@ -33,8 +36,8 @@ export function useCalculatedColumns<R, SR>({
rawGroupBy,
enableVirtualization
}: CalculatedColumnsArgs<R, SR>) {
const defaultWidth = defaultColumnOptions?.width;
const defaultMinWidth = defaultColumnOptions?.minWidth ?? 80;
const defaultWidth = defaultColumnOptions?.width ?? DEFAULT_COLUMN_WIDTH;
const defaultMinWidth = defaultColumnOptions?.minWidth ?? DEFAULT_COLUMN_MIN_WIDTH;
const defaultMaxWidth = defaultColumnOptions?.maxWidth;
const defaultFormatter = defaultColumnOptions?.formatter ?? valueFormatter;
const defaultSortable = defaultColumnOptions?.sortable ?? false;
Expand Down Expand Up @@ -148,38 +151,19 @@ export function useCalculatedColumns<R, SR>({
let left = 0;
let totalFrozenColumnWidth = 0;
let templateColumns = '';
let allocatedWidth = 0;
let unassignedColumnsCount = 0;

for (const column of columns) {
let width = getSpecifiedWidth(column, columnWidths, viewportWidth);

if (width === undefined) {
unassignedColumnsCount++;
} else {
let width = columnWidths.get(column.key) ?? column.width;
if (typeof width === 'number') {
width = clampColumnWidth(width, column);
allocatedWidth += width;
columnMetrics.set(column, { width, left: 0 });
}
}

for (const column of columns) {
let width: number;
if (columnMetrics.has(column)) {
const columnMetric = columnMetrics.get(column)!;
columnMetric.left = left;
({ width } = columnMetric);
} else {
// avoid decimals as subpixel positioning can lead to cell borders not being displayed
const unallocatedWidth = viewportWidth - allocatedWidth;
const unallocatedColumnWidth = round(unallocatedWidth / unassignedColumnsCount);
width = clampColumnWidth(unallocatedColumnWidth, column);
allocatedWidth += width;
unassignedColumnsCount--;
columnMetrics.set(column, { width, left });
// This is a placeholder width so we can continue to use virtualization.
// The actual value is set after the column is rendered
width = column.minWidth;
}
left += width;
templateColumns += `${width}px `;
columnMetrics.set(column, { width, left });
left += width;
}

if (lastFrozenColumnIndex !== -1) {
Expand All @@ -197,7 +181,7 @@ export function useCalculatedColumns<R, SR>({
}

return { layoutCssVars, totalFrozenColumnWidth, columnMetrics };
}, [columnWidths, columns, viewportWidth, lastFrozenColumnIndex]);
}, [columnWidths, columns, lastFrozenColumnIndex]);

const [colOverscanStartIdx, colOverscanEndIdx] = useMemo((): [number, number] => {
if (!enableVirtualization) {
Expand Down Expand Up @@ -265,22 +249,3 @@ export function useCalculatedColumns<R, SR>({
groupBy
};
}

function getSpecifiedWidth<R, SR>(
{ key, width }: Column<R, SR>,
columnWidths: ReadonlyMap<string, number>,
viewportWidth: number
): number | undefined {
if (columnWidths.has(key)) {
// Use the resized width if available
return columnWidths.get(key);
}

if (typeof width === 'number') {
return width;
}
if (typeof width === 'string' && /^\d+%$/.test(width)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed as we get the width after the columns are rendered

return floor((viewportWidth * parseInt(width, 10)) / 100);
}
return undefined;
}
7 changes: 5 additions & 2 deletions src/hooks/useGridDimensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { ceil } from '../utils';
export function useGridDimensions(): [
ref: React.RefObject<HTMLDivElement>,
width: number,
height: number
height: number,
isWidthInitialized: boolean
] {
const gridRef = useRef<HTMLDivElement>(null);
const [inlineSize, setInlineSize] = useState(1);
const [blockSize, setBlockSize] = useState(1);
const [isWidthInitialized, setWidthInitialized] = useState(false);

useLayoutEffect(() => {
const { ResizeObserver } = window;
Expand All @@ -31,6 +33,7 @@ export function useGridDimensions(): [
const size = entries[0].contentBoxSize[0];
setInlineSize(handleDevicePixelRatio(size.inlineSize));
setBlockSize(size.blockSize);
setWidthInitialized(true);
});
resizeObserver.observe(gridRef.current!);

Expand All @@ -39,7 +42,7 @@ export function useGridDimensions(): [
};
}, []);

return [gridRef, inlineSize, blockSize];
return [gridRef, inlineSize, blockSize, isWidthInitialized];
}

// TODO: remove once fixed upstream
Expand Down
22 changes: 20 additions & 2 deletions src/hooks/useViewportColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface ViewportColumnsArgs<R, SR> {
lastFrozenColumnIndex: number;
rowOverscanStartIdx: number;
rowOverscanEndIdx: number;
columnWidths: ReadonlyMap<string, number>;
isGroupRow: (row: R | GroupRow<R>) => row is GroupRow<R>;
}

Expand All @@ -28,6 +29,7 @@ export function useViewportColumns<R, SR>({
lastFrozenColumnIndex,
rowOverscanStartIdx,
rowOverscanEndIdx,
columnWidths,
isGroupRow
}: ViewportColumnsArgs<R, SR>) {
// find the column that spans over a column within the visible columns range and adjust colOverscanStartIdx
Expand Down Expand Up @@ -104,15 +106,31 @@ export function useViewportColumns<R, SR>({
isGroupRow
]);

return useMemo((): readonly CalculatedColumn<R, SR>[] => {
const { viewportColumns, flexWidthViewportColumns } = useMemo((): {
viewportColumns: readonly CalculatedColumn<R, SR>[];
flexWidthViewportColumns: readonly CalculatedColumn<R, SR>[];
} => {
const viewportColumns: CalculatedColumn<R, SR>[] = [];
const flexWidthViewportColumns: CalculatedColumn<R, SR>[] = [];
for (let colIdx = 0; colIdx <= colOverscanEndIdx; colIdx++) {
const column = columns[colIdx];

if (colIdx < startIdx && !column.frozen) continue;
viewportColumns.push(column);
if (typeof column.width === 'string') {
flexWidthViewportColumns.push(column);
}
}

return viewportColumns;
return { viewportColumns, flexWidthViewportColumns };
}, [startIdx, colOverscanEndIdx, columns]);

const unsizedFlexWidthViewportColumns = useMemo((): readonly CalculatedColumn<R, SR>[] => {
return flexWidthViewportColumns.filter((column) => !columnWidths.has(column.key));
}, [flexWidthViewportColumns, columnWidths]);

return {
viewportColumns,
flexWidthViewportColumns: unsizedFlexWidthViewportColumns
};
}
2 changes: 1 addition & 1 deletion src/style/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const cell = css`
export const cellClassname = `rdg-cell ${cell}`;

// max-content does not calculate width when contain is set to style or size
export const cellAutoResizeClassname = css`
export const autosizeColumnsClassname = css`
@layer rdg.Root {
.${cell} {
contain: content;
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export interface Column<TRow, TSummaryRow = unknown> {

export interface CalculatedColumn<TRow, TSummaryRow = unknown> extends Column<TRow, TSummaryRow> {
readonly idx: number;
readonly width: number | string;
readonly minWidth: number;
readonly resizable: boolean;
readonly sortable: boolean;
Expand Down
2 changes: 1 addition & 1 deletion test/column/formatter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('Custom formatter component', () => {
resizable: false,
rowGroup: false,
sortable: false,
width: undefined
width: 'auto'
},
indexes: [0]
});
Expand Down
6 changes: 3 additions & 3 deletions website/demos/AllFeatures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const columns: readonly Column<Row>[] = [
{
key: 'email',
name: 'Email',
width: 200,
width: 'max-content',
resizable: true,
editor: textEditor
},
Expand Down Expand Up @@ -124,7 +124,7 @@ const columns: readonly Column<Row>[] = [
{
key: 'catchPhrase',
name: 'Catch Phrase',
width: 200,
width: 'max-content',
resizable: true,
editor: textEditor
},
Expand All @@ -138,7 +138,7 @@ const columns: readonly Column<Row>[] = [
{
key: 'sentence',
name: 'Sentence',
width: 200,
width: 'max-content',
resizable: true,
editor: textEditor
}
Expand Down
1 change: 1 addition & 0 deletions website/demos/ColumnSpanning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default function ColumnSpanning({ direction }: Props) {
key,
name: key,
frozen: i < 5,
width: 80,
resizable: true,
formatter: cellFormatter,
colSpan(args) {
Expand Down
1 change: 1 addition & 0 deletions website/demos/ColumnsReordering.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export default function ColumnsReordering({ direction }: Props) {
sortColumns={sortColumns}
onSortColumnsChange={onSortColumnsChange}
direction={direction}
defaultColumnOptions={{ width: '1fr' }}
/>
</DndProvider>
);
Expand Down
2 changes: 1 addition & 1 deletion website/demos/CommonFeatures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function getColumns(countries: string[], direction: Direction): readonly Column<
{
key: 'client',
name: 'Client',
width: 220,
width: 'max-content',
editor: textEditor
},
{
Expand Down
1 change: 1 addition & 0 deletions website/demos/MillionCells.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function MillionCells({ direction }: Props) {
key,
name: key,
frozen: i < 5,
width: 80,
resizable: true,
formatter: cellFormatter
});
Expand Down