feat: wrap widgets into a component which listens to content height changes (#17729)

* added the DynamicHeightContainer component which is responsible for sending the height changing events to the store

* removed the dependency on widget features

* removed a console log statement

* also added an effect to track the changes in the min and max dynamic height properties

* changed the name of the container from DynamicHeightContainer to AutoHeightContainer

* a dummy commit

Co-authored-by: Ankur Singhal <ankurrsinghal@gmail.com>
This commit is contained in:
ankurrsinghal 2022-11-01 13:48:51 +05:30 committed by GitHub
parent 59fc70b36b
commit 23e5ee7ba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 150 additions and 0 deletions

View File

@ -0,0 +1,72 @@
import React from "react";
import "@testing-library/jest-dom";
import { render } from "@testing-library/react";
import AutoHeightContainer from "./AutoHeightContainer";
import "jest-styled-components";
import renderer from "react-test-renderer";
describe("<AutoHeightContainer />", () => {
it("should wrap the children in a div whose height is auto.", async () => {
const tree = renderer
.create(
<AutoHeightContainer
maxDynamicHeight={0}
minDynamicHeight={0}
isAutoHeightWithLimits={false}
onHeightUpdate={() => {}}
>
<div data-testid="test" />
</AutoHeightContainer>,
)
.toJSON();
expect(tree).toHaveStyleRule("height", "auto");
});
describe("when isAutoHeightWithLimits is false", () => {
it("should wrap the children in a simple div with class auto-height-container", async () => {
const getTestComponent = () => (
<AutoHeightContainer
maxDynamicHeight={0}
minDynamicHeight={0}
isAutoHeightWithLimits={false}
onHeightUpdate={() => {}}
>
<div data-testid="test" />
</AutoHeightContainer>
);
const component = getTestComponent();
const renderResult = render(component);
const child = await renderResult.findByTestId("test");
expect(
child.parentElement?.classList.contains("auto-height-container"),
).toBe(true);
});
});
describe("when isAutoHeightWithLimits is true", () => {
it("should wrap the children in a div of class auto-height-container and then a div with class auto-height-scroll-container", async () => {
const getTestComponent = () => (
<AutoHeightContainer
maxDynamicHeight={0}
minDynamicHeight={0}
isAutoHeightWithLimits={true}
onHeightUpdate={() => {}}
>
<div data-testid="test" />
</AutoHeightContainer>
);
const component = getTestComponent();
const renderResult = render(component);
const child = await renderResult.findByTestId("test");
expect(child.parentElement?.tagName).toBe("DIV");
expect(
child.parentElement?.classList.contains("auto-height-container"),
).toBe(true);
expect(
child.parentElement?.parentElement?.classList.contains(
"auto-height-scroll-container",
),
).toBe(true);
});
});
});

View File

@ -0,0 +1,78 @@
import React, { PropsWithChildren, useRef, useEffect, useState } from "react";
import { GridDefaults } from "constants/WidgetConstants";
import styled from "styled-components";
const StyledAutoHeightContainer = styled.div<{ isOverflow?: boolean }>`
overflow-y: ${(props) => (props.isOverflow ? "auto" : "unset")};
overflow-x: ${(props) => (props.isOverflow ? "hidden" : "unset")};
`;
interface AutoHeightContainerProps {
maxDynamicHeight: number;
minDynamicHeight: number;
isAutoHeightWithLimits: boolean;
onHeightUpdate: (height: number) => void;
}
const SimpleContainer = styled.div`
height: auto;
`;
export default function AutoHeightContainer({
children,
isAutoHeightWithLimits,
maxDynamicHeight,
minDynamicHeight,
onHeightUpdate,
}: PropsWithChildren<AutoHeightContainerProps>) {
const [expectedHeight, setExpectedHeight] = useState(0);
const ref = useRef<HTMLDivElement>(null);
const observer = useRef(
new ResizeObserver((entries) => {
const height = entries[0].contentRect.height;
setExpectedHeight(height);
onHeightUpdate(height);
}),
);
useEffect(() => {
if (ref.current) {
observer.current.observe(ref.current);
}
return () => {
if (ref.current) {
observer.current.unobserve(ref.current);
}
};
}, []);
useEffect(() => {
onHeightUpdate(expectedHeight);
}, [minDynamicHeight, maxDynamicHeight]);
if (isAutoHeightWithLimits) {
const expectedHeightInRows = Math.ceil(
expectedHeight / GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
);
return (
<StyledAutoHeightContainer
className="auto-height-scroll-container"
isOverflow={maxDynamicHeight < expectedHeightInRows}
>
<SimpleContainer className="auto-height-container" ref={ref}>
{children}
</SimpleContainer>
</StyledAutoHeightContainer>
);
}
return (
<SimpleContainer className="auto-height-container" ref={ref}>
{children}
</SimpleContainer>
);
}