Skip to content
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

Expand cell height if there is only one row #537

Merged
merged 18 commits into from
Feb 11, 2025
Merged
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
35 changes: 25 additions & 10 deletions src/components/Grid/Cell.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { memo } from "react";
import { memo, useEffect, useRef } from "react";
import { GridChildComponentProps, areEqual } from "react-window";
import { ItemDataType } from "./types";
import { StyledCell } from "./StyledCell";

type CellProps = GridChildComponentProps<ItemDataType> & {
width: number;
}
};

export const Cell = memo(
({
data,
rowIndex,
columnIndex,
style,
...props
}: CellProps) => {
({ data, rowIndex, columnIndex, style, ...props }: CellProps) => {
const {
cell: CellData,
getSelectionType,
Expand All @@ -25,6 +19,8 @@ export const Cell = memo(
showHeader,
rowHeight,
rowStart,
rowAutoHeight,
updateRowHeight,
} = data;

const currentRowIndex = rowIndex + rowStart;
Expand Down Expand Up @@ -60,11 +56,29 @@ export const Cell = memo(
const selectionBorderLeft = rightOfSelectionBorder || rightOfFocus || isFocused;
const selectionBorderTop = belowSelectionBorder || belowFocus || isFocused;

const cellRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!rowAutoHeight) {
return;
}
if (cellRef.current) {
const height = cellRef.current.getBoundingClientRect().height;
updateRowHeight(rowIndex, height);
}
}, [updateRowHeight, rowIndex, rowAutoHeight]);

const styleWithHeight = {
...style,
height: "auto",
};

return (
<div
style={style}
style={styleWithHeight}
data-row={currentRowIndex}
data-column={columnIndex}
ref={cellRef}
>
<StyledCell
as={CellData}
Expand All @@ -85,6 +99,7 @@ export const Cell = memo(
data-grid-row={currentRowIndex}
data-grid-column={columnIndex}
$showBorder
$rowAutoHeight={rowAutoHeight}
{...props}
/>
</div>
Expand Down
11 changes: 10 additions & 1 deletion src/components/Grid/Grid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { useCallback, useEffect, useState } from "react";
import { CellProps, GridContextMenuItemProps, SelectedRegion, SelectionFocus } from "..";
import { Grid as CUIGrid } from "./Grid";

const Cell: CellProps = ({ type, rowIndex, columnIndex, isScrolling, width, ...props }) => {
const Cell: CellProps = ({
type,
rowIndex,
columnIndex,
isScrolling,
width,
...props
}) => {
return (
<div
data-scrolling={isScrolling}
Expand All @@ -20,6 +27,7 @@ interface Props {
row: number;
column: number;
};
rowAutoHeight?: boolean;
}
const Grid = ({ columnCount, rowCount, focus: focusProp, ...props }: Props) => {
const [focus, setFocus] = useState(focusProp);
Expand Down Expand Up @@ -71,6 +79,7 @@ const Grid = ({ columnCount, rowCount, focus: focusProp, ...props }: Props) => {
});
}}
getMenuOptions={getMenuOptions}
rowAutoHeight={props.rowAutoHeight}
{...props}
/>
</div>
Expand Down
56 changes: 51 additions & 5 deletions src/components/Grid/Grid.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import {CellProps, Grid, GridProps} from "@/components";
import {renderCUI} from "@/utils/test-utils";
import {SelectionFocus} from "./types";
import {ReactNode} from "react";
import { CellProps, Grid, GridProps } from "@/components";
import { renderCUI } from "@/utils/test-utils";
import { SelectionFocus } from "./types";
import { ReactNode } from "react";

const Cell: CellProps = ({ type, rowIndex, columnIndex, isScrolling, ...props }) => {
let content = `${rowIndex} ${columnIndex} - ${type}`;

if (rowIndex === 0 && columnIndex === 0) {
content = `CREATE TABLE random_user_events (
user_id UInt32,
event_time DateTime,
event_type Enum8('click' = 1, 'view' = 2, 'purchase' = 3),
item_id String,
price Decimal(10,2),
quantity UInt16
) ENGINE = MergeTree()
ORDER BY (user_id, event_time)
PARTITION BY toYYYYMM(event_time)
SETTINGS index_granularity = 8192;`;
}

return (
<div
data-scrolling={isScrolling}
{...props}
data-testid={`${type}-${rowIndex ?? "x"}-${columnIndex ?? "x"}`}
>
{rowIndex} {columnIndex} - {type}
{content}
</div>
);
};
Expand All @@ -31,6 +47,7 @@ interface Props
focus?: SelectionFocus;
onFocusChange?: (rowIndex: number, columnIndex: number) => void;
onColumnResize?: () => void;
rowAutoHeight?: boolean;
}
type AutoSizerModule = typeof import("react-virtualized-auto-sizer");

Expand Down Expand Up @@ -60,6 +77,7 @@ describe("Grid", () => {
onColumnResize,
focus,
onFocusChange,
rowAutoHeight,
...props
}: Props) =>
renderCUI(
Expand All @@ -72,6 +90,7 @@ describe("Grid", () => {
onColumnResize={onColumnResize ?? onColumnResizeTestFn}
onFocusChange={onFocusChange ?? onFocusChangeTestFn}
getMenuOptions={getMenuOptions}
rowAutoHeight={rowAutoHeight}
{...props}
/>
);
Expand Down Expand Up @@ -99,4 +118,31 @@ describe("Grid", () => {
cell && expect(cell.dataset.selected).toEqual("true");
cell && expect(cell.dataset.focused).toEqual("true");
});

it("should set row height to default (33px) when rowAutoHeight is false", async () => {
const { getByTestId } = renderGrid({
rowCount: 10,
columnCount: 10,
rowAutoHeight: false,
});

const cell = getByTestId("row-cell-0-0");

const computedHeight = window.getComputedStyle(cell).height;
const heightValue = parseFloat(computedHeight);
expect(heightValue).toBe(33);
});

it("should expand row height to 100% when rowAutoHeight is true", async () => {
const { getByTestId } = renderGrid({
rowCount: 1,
columnCount: 1,
rowAutoHeight: true,
});

const cell = getByTestId("row-cell-0-0");

const computedHeight = window.getComputedStyle(cell).height;
expect(computedHeight).toBe("100%");
});
});
43 changes: 41 additions & 2 deletions src/components/Grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
onContextMenu: onContextMenuProp,
forwardedGridRef,
onItemsRendered: onItemsRenderedProp,
rowAutoHeight,
...props
},
forwardedRef
Expand Down Expand Up @@ -212,6 +213,34 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
onCopyCallback,
]);

const rowHeightsRef = useRef(new Map());

const getRowHeight = useCallback(
(index: number) => {
if (rowAutoHeight && rowHeightsRef.current.get(index)) {
return rowHeightsRef.current.get(index) + rowHeight;
}
return rowHeight;
},
[rowHeight, rowAutoHeight]
);

const updateRowHeight = useCallback(
(rowIndex: number, height: number) => {
if (!rowAutoHeight) {
return;
}
const prevHeight = rowHeightsRef.current.get(rowIndex) ?? 0;
if (height > prevHeight) {
rowHeightsRef.current.set(rowIndex, height);
if (gridRef.current) {
gridRef.current.resetAfterRowIndex(rowIndex);
}
}
},
[rowAutoHeight]
);

const customOnCopy: () => Promise<void> = useMemo(() => {
const result = async () => {
if (onCopyProp) {
Expand Down Expand Up @@ -405,6 +434,9 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
headerHeight,
rowNumberWidth,
rowStart,
rowAutoHeight,
updateRowHeight,
getRowHeight,
};

const InnerElementType = forwardRef<HTMLDivElement, InnerElementTypeTypes>(
Expand Down Expand Up @@ -435,6 +467,7 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
showHeader={showHeader}
rowStart={rowStart}
showBorder={showBorder}
rowAutoHeight={rowAutoHeight}
/>
)}

Expand Down Expand Up @@ -755,7 +788,6 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
const onItemsRendered = useCallback(
(props: GridOnItemsRenderedProps) => {
lastItemsRenderedProps.current = props;

return onItemsRenderedProp?.({
...props,
visibleRowStartIndex: props.visibleRowStartIndex + rowStart,
Expand Down Expand Up @@ -786,6 +818,13 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
);
};

// Handles the case when rowCount/columnCount changes, rerenders styles
useEffect(() => {
if (gridRef.current) {
gridRef.current.resetAfterRowIndex(0);
}
}, [rowCount, columnCount]);

return (
<ContextMenu
modal={false}
Expand Down Expand Up @@ -820,7 +859,7 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
height={height}
width={width}
columnCount={columnCount}
rowHeight={() => rowHeight}
rowHeight={getRowHeight}
useIsScrolling={useIsScrolling}
innerElementType={InnerElementType}
itemData={data}
Expand Down
5 changes: 3 additions & 2 deletions src/components/Grid/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const RowColumnContainer = styled(HeaderCellContainer)<{
const RowColumn = styled(StyledCell)`
width: 100%;
text-align: right;
overflow: hidden;
`;

const Column = ({
Expand Down Expand Up @@ -130,7 +131,7 @@ const Column = ({
(leftSelectionType === "selectDirect" || isSelected) &&
leftSelectionType !== selectionType;

const columnWidth = getColumnWidth(columnIndex)
const columnWidth = getColumnWidth(columnIndex);
return (
<HeaderCellContainer
$width={columnWidth}
Expand Down Expand Up @@ -186,7 +187,7 @@ const Header = ({
getColumnHorizontalPosition,
getResizerPosition,
showBorder,
resizingState
resizingState,
}: HeaderProps) => {
const selectedAllType = getSelectionType({
type: "all",
Expand Down
Loading