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:
parent
59fc70b36b
commit
23e5ee7ba3
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
78
app/client/src/components/autoHeight/AutoHeightContainer.tsx
Normal file
78
app/client/src/components/autoHeight/AutoHeightContainer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user