From 23e5ee7ba3f73d603c326d774b2bf66ad1400fc6 Mon Sep 17 00:00:00 2001 From: ankurrsinghal Date: Tue, 1 Nov 2022 13:48:51 +0530 Subject: [PATCH] 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 --- .../autoHeight/AutoHeightContainer.test.tsx | 72 +++++++++++++++++ .../autoHeight/AutoHeightContainer.tsx | 78 +++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 app/client/src/components/autoHeight/AutoHeightContainer.test.tsx create mode 100644 app/client/src/components/autoHeight/AutoHeightContainer.tsx diff --git a/app/client/src/components/autoHeight/AutoHeightContainer.test.tsx b/app/client/src/components/autoHeight/AutoHeightContainer.test.tsx new file mode 100644 index 0000000000..33098fed23 --- /dev/null +++ b/app/client/src/components/autoHeight/AutoHeightContainer.test.tsx @@ -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("", () => { + it("should wrap the children in a div whose height is auto.", async () => { + const tree = renderer + .create( + {}} + > +
+ , + ) + .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 = () => ( + {}} + > +
+ + ); + 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 = () => ( + {}} + > +
+ + ); + 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); + }); + }); +}); diff --git a/app/client/src/components/autoHeight/AutoHeightContainer.tsx b/app/client/src/components/autoHeight/AutoHeightContainer.tsx new file mode 100644 index 0000000000..30b91d1af5 --- /dev/null +++ b/app/client/src/components/autoHeight/AutoHeightContainer.tsx @@ -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) { + const [expectedHeight, setExpectedHeight] = useState(0); + + const ref = useRef(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 ( + + + {children} + + + ); + } + + return ( + + {children} + + ); +}