Selaa lähdekoodia

Merge pull request #2318 from Avaiga/bug/#2141-metric-width-height-css

Fix css syntax for Metric component
Nam Nguyen 5 kuukautta sitten
vanhempi
säilyke
bf6c3a4b6f

+ 136 - 10
frontend/taipy-gui/src/components/Taipy/Metric.spec.tsx

@@ -239,7 +239,7 @@ describe("Metric Component", () => {
     });
 
     it("applies style correctly when deltaColor is set", async () => {
-        const { container } = render(<Metric delta={10} deltaColor="#FF4136"  />);
+        const { container } = render(<Metric delta={10} deltaColor="#FF4136" />);
         await waitFor(() => {
             const elt = container.querySelector(".delta");
             expect(elt).toHaveStyle({
@@ -249,7 +249,7 @@ describe("Metric Component", () => {
     });
 
     it("applies style correctly when deltaColor is set invert", async () => {
-        const { container } = render(<Metric delta={10} deltaColor="invert"  />);
+        const { container } = render(<Metric delta={10} deltaColor="invert" />);
         await waitFor(() => {
             const elt = container.querySelector(".delta");
             expect(elt).toHaveStyle({
@@ -259,7 +259,7 @@ describe("Metric Component", () => {
     });
 
     it("processes type and threshold props correctly when type is linear", async () => {
-        const { container } = render(<Metric type="linear" threshold={50}  />);
+        const { container } = render(<Metric type="linear" threshold={50} />);
         await waitFor(() => {
             const elt = container.querySelector(".bullet");
             expect(elt).toBeInTheDocument();
@@ -267,7 +267,7 @@ describe("Metric Component", () => {
     });
 
     it("processes type and threshold props correctly when type is not linear", async () => {
-        const { container } = render(<Metric type="angular" threshold={50}  />);
+        const { container } = render(<Metric type="angular" threshold={50} />);
         await waitFor(() => {
             const elt = container.querySelector(".angular");
             expect(elt).toBeInTheDocument();
@@ -286,6 +286,132 @@ describe("Metric Component", () => {
         });
     });
 
+    it("applies style correctly when height is set to 100px", async () => {
+        const { container } = render(<Metric height="100px" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "100%",
+                height: "100px",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when height is set to 30em", async () => {
+        const { container } = render(<Metric height="30em" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "100%",
+                height: "30em",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when height is set to 30%", async () => {
+        const { container } = render(<Metric height="30%" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "100%",
+                height: "30%",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when height is set to 30vh", async () => {
+        const { container } = render(<Metric height="30vh" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "100%",
+                height: "30vh",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when height is set to 30vw", async () => {
+        const { container } = render(<Metric height="30vw" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "100%",
+                height: "30vw",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when width is set to 100px", async () => {
+        const { container } = render(<Metric width="100px" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "100px",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when width is set to 30em", async () => {
+        const { container } = render(<Metric width="30em" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "30em",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when width is set to 30%", async () => {
+        const { container } = render(<Metric width="30%" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "30%",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when width is set to 30vh", async () => {
+        const { container } = render(<Metric width="30vh" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "30vh",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+    it("applies style correctly when width is set to 30vw", async () => {
+        const { container } = render(<Metric width="30vw" />);
+        await waitFor(() => {
+            const elt = container.querySelector(".js-plotly-plot");
+            expect(elt).toHaveStyle({
+                width: "30vw",
+                position: "relative",
+                display: "inline-block",
+            });
+        });
+    });
+
+
     it("processes type prop correctly when type is none (string)", async () => {
         const { container } = render(<Metric type="none" />);
         await waitFor(() => {
@@ -295,7 +421,7 @@ describe("Metric Component", () => {
             expect(angularAxis).not.toBeInTheDocument();
         });
     });
-    
+
     it("processes type prop correctly when type is None", async () => {
         const { container } = render(<Metric type="None" />);
         await waitFor(() => {
@@ -315,8 +441,8 @@ describe("Metric Component", () => {
 
         const { container } = render(
             <ThemeProvider theme={darkTheme}>
-                <Metric template_Dark_={JSON.stringify(darkTemplate)}  />
-            </ThemeProvider>
+                <Metric template_Dark_={JSON.stringify(darkTemplate)} />
+            </ThemeProvider>,
         );
         await waitFor(() => {
             const elt = container.querySelector(".main-svg");
@@ -335,8 +461,8 @@ describe("Metric Component", () => {
 
         const { container } = render(
             <ThemeProvider theme={lightTheme}>
-                <Metric template_Light_={JSON.stringify(lightTemplate)}  />
-            </ThemeProvider>
+                <Metric template_Light_={JSON.stringify(lightTemplate)} />
+            </ThemeProvider>,
         );
         await waitFor(() => {
             const elt = container.querySelector(".main-svg");
@@ -348,7 +474,7 @@ describe("Metric Component", () => {
 
     it.skip("logs an error when template_Dark_ prop is not a valid JSON string", () => {
         const consoleSpy = jest.spyOn(console, "info");
-        render(<Metric template_Dark_="not a valid JSON string"/>);
+        render(<Metric template_Dark_="not a valid JSON string" />);
         expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error while parsing Metric.template"));
         consoleSpy.mockRestore();
     }); // TODO: Not working at the moment, need to fix

+ 35 - 18
frontend/taipy-gui/src/components/Taipy/Metric.tsx

@@ -56,6 +56,7 @@ const emptyLayout = {} as Partial<Layout>;
 const defaultStyle = { position: "relative", display: "inline-block", width: "100%" } as CSSProperties;
 const skeletonStyle = { ...defaultStyle, minHeight: "7em" };
 const plotConfig = { displaylogo: false };
+const boxStyle = { height: "100vh" };
 
 const Metric = (props: MetricProps) => {
     const { showValue = true } = props;
@@ -92,17 +93,17 @@ const Metric = (props: MetricProps) => {
         delta !== undefined && mode.push("delta");
         const deltaIncreasing = props.deltaColor
             ? {
-                  color: props.deltaColor == "invert" ? "#FF4136" : props.deltaColor,
-              }
+                color: props.deltaColor == "invert" ? "#FF4136" : props.deltaColor,
+            }
             : undefined;
         const deltaDecreasing =
             props.deltaColor == "invert"
                 ? {
-                      color: "#3D9970",
-                  }
+                    color: "#3D9970",
+                }
                 : props.negativeDeltaColor
-                  ? { color: props.negativeDeltaColor }
-                  : undefined;
+                    ? { color: props.negativeDeltaColor }
+                    : undefined;
         return [
             {
                 domain: { x: [0, 1], y: [0, 1] },
@@ -158,8 +159,6 @@ const Metric = (props: MetricProps) => {
     const layout = useMemo(() => {
         const layout = {
             ...baseLayout,
-            height: baseLayout.height !== undefined ? baseLayout.height : props.height,
-            width: baseLayout.width !== undefined ? baseLayout.width : props.width,
         };
         let template = undefined;
         try {
@@ -185,8 +184,6 @@ const Metric = (props: MetricProps) => {
         return layout as Partial<Layout>;
     }, [
         props.title,
-        props.height,
-        props.width,
         props.template,
         props.template_Dark_,
         props.template_Light_,
@@ -194,15 +191,35 @@ const Metric = (props: MetricProps) => {
         baseLayout,
     ]);
 
+    const style = useMemo(() => {
+        const normalizeSize = (val: string | number | undefined): string | undefined => {
+            if (typeof val === "number" || (typeof val === "string" && /^\d+$/.test(val))) {
+                return `${val}px`;
+            }
+            return val;
+        };
+
+        const width = props.width ? normalizeSize(props.width) : "100%";
+        const height = props.height ? normalizeSize(props.height) : undefined;
+
+        return { ...defaultStyle, width, height };
+    }, [props.width, props.height]);
+
     return (
-        <Tooltip title={hover || ""}>
-            <Box className={`${className} ${getComponentClassName(props.children)}`}>
-                <Suspense fallback={<Skeleton key="skeleton" sx={skeletonStyle} />}>
-                    <Plot data={data} layout={layout} style={defaultStyle} config={plotConfig} useResizeHandler />
-                </Suspense>
-                {props.children}
-            </Box>
-        </Tooltip>
+            <Tooltip title={hover || ""}>
+                <Box className={`${className} ${getComponentClassName(props.children)}`} style={boxStyle}>
+                    <Suspense fallback={<Skeleton key="skeleton" sx={skeletonStyle} />}>
+                        <Plot
+                            data={data}
+                            layout={layout}
+                            style={style}
+                            config={plotConfig}
+                            useResizeHandler
+                        />
+                    </Suspense>
+                    {props.children}
+                </Box>
+            </Tooltip>
     );
 };