diff --git a/js/packages/react-ui/src/components/Charts/AreaChart/AreaChart.tsx b/js/packages/react-ui/src/components/Charts/AreaChart/AreaChart.tsx index 0569c76f0..d1c78b8b3 100644 --- a/js/packages/react-ui/src/components/Charts/AreaChart/AreaChart.tsx +++ b/js/packages/react-ui/src/components/Charts/AreaChart/AreaChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Area, AreaChart as RechartsAreaChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; import { SideBarChartData, SideBarTooltipProvider } from "../context/SideBarTooltipContext"; @@ -78,6 +79,9 @@ const AreaChartComponent = ({ height, width, }: AreaChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const dataKeys = useMemo(() => { return getDataKeys(data, categoryKey as string); }, [data, categoryKey]); diff --git a/js/packages/react-ui/src/components/Charts/AreaChartCondensed/AreaChartCondensed.tsx b/js/packages/react-ui/src/components/Charts/AreaChartCondensed/AreaChartCondensed.tsx index 8e32f2b32..ab111981f 100644 --- a/js/packages/react-ui/src/components/Charts/AreaChartCondensed/AreaChartCondensed.tsx +++ b/js/packages/react-ui/src/components/Charts/AreaChartCondensed/AreaChartCondensed.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { Area, AreaChart as RechartsAreaChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { AreaChartData, AreaChartVariant } from "../AreaChart/types"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; @@ -67,6 +68,9 @@ const AreaChartCondensedComponent = ({ height = CHART_HEIGHT, width, }: AreaChartCondensedProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const dataKeys = useMemo(() => { return getDataKeys(data, categoryKey as string); }, [data, categoryKey]); diff --git a/js/packages/react-ui/src/components/Charts/BarChart/BarChart.tsx b/js/packages/react-ui/src/components/Charts/BarChart/BarChart.tsx index a8ce71796..51cfdd236 100644 --- a/js/packages/react-ui/src/components/Charts/BarChart/BarChart.tsx +++ b/js/packages/react-ui/src/components/Charts/BarChart/BarChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Bar, BarChart as RechartsBarChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { useTheme } from "../../ThemeProvider"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; @@ -92,6 +93,9 @@ const BarChartComponent = ({ height, width, }: BarChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const widthOfGroup = getWidthOfGroup(data, categoryKey as string, variant); const maxLabelHeight = useMaxLabelHeight(data, categoryKey as string, tickVariant, widthOfGroup); diff --git a/js/packages/react-ui/src/components/Charts/BarChartCondensed/BarChartCondensed.tsx b/js/packages/react-ui/src/components/Charts/BarChartCondensed/BarChartCondensed.tsx index 79db5f7ad..1237ac4a8 100644 --- a/js/packages/react-ui/src/components/Charts/BarChartCondensed/BarChartCondensed.tsx +++ b/js/packages/react-ui/src/components/Charts/BarChartCondensed/BarChartCondensed.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Bar, BarChart as RechartsBarChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { useTheme } from "../../ThemeProvider"; import { BarChartData, BarChartVariant } from "../BarChart/types"; @@ -75,6 +76,9 @@ const BarChartCondensedComponent = ({ height = CHART_HEIGHT, width, }: BarChartCondensedProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const dataKeys = useMemo(() => { return getDataKeys(data, categoryKey as string); }, [data, categoryKey]); diff --git a/js/packages/react-ui/src/components/Charts/HorizontalBarChart/HorizontalBarChart.tsx b/js/packages/react-ui/src/components/Charts/HorizontalBarChart/HorizontalBarChart.tsx index 54e3fbc8f..1cfcf1e2a 100644 --- a/js/packages/react-ui/src/components/Charts/HorizontalBarChart/HorizontalBarChart.tsx +++ b/js/packages/react-ui/src/components/Charts/HorizontalBarChart/HorizontalBarChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Bar, BarChart as RechartsBarChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { useTheme } from "../../ThemeProvider"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; @@ -90,6 +91,9 @@ const HorizontalBarChartComponent = ({ height, width, }: HorizontalBarChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const maxCategoryLabelWidth = useMaxCategoryLabelWidth(data, categoryKey as string); const chartContainerRef = useRef(null); diff --git a/js/packages/react-ui/src/components/Charts/LineChart/LineChart.tsx b/js/packages/react-ui/src/components/Charts/LineChart/LineChart.tsx index eff6f40e8..ce90d8330 100644 --- a/js/packages/react-ui/src/components/Charts/LineChart/LineChart.tsx +++ b/js/packages/react-ui/src/components/Charts/LineChart/LineChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Line, LineChart as RechartsLineChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; import { SideBarChartData, SideBarTooltipProvider } from "../context/SideBarTooltipContext"; @@ -78,6 +79,9 @@ export const LineChart = ({ width, strokeWidth = 2, }: LineChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const dataKeys = useMemo(() => { return getDataKeys(data, categoryKey as string); }, [data, categoryKey]); diff --git a/js/packages/react-ui/src/components/Charts/LineChartCondensed/LineChartCondensed.tsx b/js/packages/react-ui/src/components/Charts/LineChartCondensed/LineChartCondensed.tsx index f425b74be..88fb02cbf 100644 --- a/js/packages/react-ui/src/components/Charts/LineChartCondensed/LineChartCondensed.tsx +++ b/js/packages/react-ui/src/components/Charts/LineChartCondensed/LineChartCondensed.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { Line, LineChart as RechartsLineChart, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; import { DEFAULT_X_AXIS_HEIGHT, X_AXIS_PADDING } from "../constants"; @@ -69,6 +70,9 @@ const LineChartCondensedComponent = ({ width, strokeWidth = 2, }: LineChartCondensedProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const dataKeys = useMemo(() => { return getDataKeys(data, categoryKey as string); }, [data, categoryKey]); diff --git a/js/packages/react-ui/src/components/Charts/MiniAreaChart/MiniAreaChart.tsx b/js/packages/react-ui/src/components/Charts/MiniAreaChart/MiniAreaChart.tsx index f2dfc7198..5ef81ec4c 100644 --- a/js/packages/react-ui/src/components/Charts/MiniAreaChart/MiniAreaChart.tsx +++ b/js/packages/react-ui/src/components/Charts/MiniAreaChart/MiniAreaChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import { useEffect, useMemo, useRef, useState } from "react"; import { Area, AreaChart as RechartsAreaChart, XAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { AreaChartVariant } from "../AreaChart/types"; import { ChartConfig, ChartContainer } from "../Charts"; @@ -41,6 +42,9 @@ export const MiniAreaChart = ({ areaColor, useGradient = true, }: MiniAreaChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const containerRef = useRef(null); const [containerWidth, setContainerWidth] = useState(0); diff --git a/js/packages/react-ui/src/components/Charts/MiniBarChart/MiniBarChart.tsx b/js/packages/react-ui/src/components/Charts/MiniBarChart/MiniBarChart.tsx index 7ef2fa1a4..dcd48073f 100644 --- a/js/packages/react-ui/src/components/Charts/MiniBarChart/MiniBarChart.tsx +++ b/js/packages/react-ui/src/components/Charts/MiniBarChart/MiniBarChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import { useEffect, useMemo, useRef, useState } from "react"; import { Bar, BarChart, XAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useTheme } from "../../ThemeProvider"; import { ChartConfig, ChartContainer } from "../Charts"; import { LineInBarShape } from "../shared"; @@ -40,6 +41,9 @@ export const MiniBarChart = ({ className, barColor, }: MiniBarChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const containerRef = useRef(null); const [containerWidth, setContainerWidth] = useState(0); diff --git a/js/packages/react-ui/src/components/Charts/MiniLineChart/MiniLineChart.tsx b/js/packages/react-ui/src/components/Charts/MiniLineChart/MiniLineChart.tsx index 4f9c5ce0e..e9fb469a5 100644 --- a/js/packages/react-ui/src/components/Charts/MiniLineChart/MiniLineChart.tsx +++ b/js/packages/react-ui/src/components/Charts/MiniLineChart/MiniLineChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import { useEffect, useMemo, useRef, useState } from "react"; import { Line, LineChart as RechartsLineChart, XAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { ChartConfig, ChartContainer } from "../Charts"; import { LineChartVariant } from "../LineChart/types"; import { @@ -38,6 +39,9 @@ export const MiniLineChart = ({ className, lineColor, }: MiniLineChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const containerRef = useRef(null); const [containerWidth, setContainerWidth] = useState(0); diff --git a/js/packages/react-ui/src/components/Charts/PieChart/PieChart.tsx b/js/packages/react-ui/src/components/Charts/PieChart/PieChart.tsx index d58aca959..8c30372f2 100644 --- a/js/packages/react-ui/src/components/Charts/PieChart/PieChart.tsx +++ b/js/packages/react-ui/src/components/Charts/PieChart/PieChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; -import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { memo, useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; import { Cell, Pie, PieChart as RechartsPieChart } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext.js"; import { useTheme } from "../../ThemeProvider/ThemeProvider.js"; import { ChartContainer, ChartTooltip, ChartTooltipContent } from "../Charts.js"; import { useTransformedKeys } from "../hooks/index.js"; @@ -72,6 +73,9 @@ const PieChartComponent = ({ height, width, }: PieChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const wrapperRef = useRef(null); const [wrapperRect, setWrapperRect] = useState({ width: 0, height: 0 }); const [hoveredLegendKey, setHoveredLegendKey] = useState(null); @@ -285,7 +289,8 @@ const PieChartComponent = ({ ], ); - useEffect(() => { + // Use ResizeObserver for subsequent size changes + useLayoutEffect(() => { const wrapper = wrapperRef.current; if (!wrapper) return; @@ -299,6 +304,10 @@ const PieChartComponent = ({ } }); observer.observe(wrapper); + + // Read initial dimensions synchronously before first paint to avoid size jump + const rect = wrapper.getBoundingClientRect(); + setWrapperRect({ width: rect.width, height: rect.height }); return () => observer.disconnect(); }, []); diff --git a/js/packages/react-ui/src/components/Charts/RadarChart/RadarChart.tsx b/js/packages/react-ui/src/components/Charts/RadarChart/RadarChart.tsx index e9b7e7e7c..a418534c8 100644 --- a/js/packages/react-ui/src/components/Charts/RadarChart/RadarChart.tsx +++ b/js/packages/react-ui/src/components/Charts/RadarChart/RadarChart.tsx @@ -1,5 +1,5 @@ import clsx from "clsx"; -import React, { memo, useEffect, useMemo, useRef, useState } from "react"; +import React, { memo, useLayoutEffect, useMemo, useRef, useState } from "react"; import { PolarAngleAxis, PolarGrid, @@ -7,6 +7,7 @@ import { RadarChart as RechartsRadarChart, ResponsiveContainer, } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; import { SideBarTooltipProvider } from "../context/SideBarTooltipContext"; import { useTransformedKeys } from "../hooks/useTransformKey"; @@ -51,6 +52,9 @@ const RadarChartComponent = ({ height, width, }: RadarChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const dataKeys = useMemo(() => { return getDataKeys(data, categoryKey as string); }, [data, categoryKey]); @@ -77,7 +81,7 @@ const RadarChartComponent = ({ const wrapperRef = useRef(null); const [wrapperRect, setWrapperRect] = useState({ width: 0, height: 0 }); - useEffect(() => { + useLayoutEffect(() => { const wrapper = wrapperRef.current; if (!wrapper) return; @@ -90,6 +94,11 @@ const RadarChartComponent = ({ }); } }); + + // Read initial dimensions synchronously before first paint to avoid size jump + const rect = wrapper.getBoundingClientRect(); + setWrapperRect({ width: rect.width, height: rect.height }); + observer.observe(wrapper); return () => observer.disconnect(); }, []); diff --git a/js/packages/react-ui/src/components/Charts/RadialChart/RadialChart.tsx b/js/packages/react-ui/src/components/Charts/RadialChart/RadialChart.tsx index 8b1ef34e5..b7b0114f0 100644 --- a/js/packages/react-ui/src/components/Charts/RadialChart/RadialChart.tsx +++ b/js/packages/react-ui/src/components/Charts/RadialChart/RadialChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Cell, PolarGrid, RadialBar, RadialBarChart, ResponsiveContainer } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { ChartContainer, ChartTooltip, ChartTooltipContent } from "../Charts"; import { useTransformedKeys } from "../hooks"; import { DefaultLegend } from "../shared/DefaultLegend/DefaultLegend"; @@ -67,6 +68,9 @@ export const RadialChart = ({ height, width, }: RadialChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const wrapperRef = useRef(null); const [wrapperRect, setWrapperRect] = useState({ width: 0, height: 0 }); const [hoveredLegendKey, setHoveredLegendKey] = useState(null); diff --git a/js/packages/react-ui/src/components/Charts/ScatterChart/ScatterChart.tsx b/js/packages/react-ui/src/components/Charts/ScatterChart/ScatterChart.tsx index 811f9e594..027b957d4 100644 --- a/js/packages/react-ui/src/components/Charts/ScatterChart/ScatterChart.tsx +++ b/js/packages/react-ui/src/components/Charts/ScatterChart/ScatterChart.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { Cell, ScatterChart as RechartsScatterChart, Scatter, XAxis, YAxis } from "recharts"; +import { usePrintContext } from "../../../context/PrintContext"; import { useId } from "../../../polyfills"; import { ChartConfig, ChartContainer, ChartTooltip } from "../Charts"; import { SideBarChartData, SideBarTooltipProvider } from "../context/SideBarTooltipContext"; @@ -61,6 +62,9 @@ export const ScatterChart = ({ width, shape = "circle", }: ScatterChartProps) => { + const printContext = usePrintContext(); + isAnimationActive = printContext ? false : isAnimationActive; + const datasets = useMemo(() => { return getScatterDatasets(data); }, [data]); diff --git a/js/packages/react-ui/src/context/PrintContext.tsx b/js/packages/react-ui/src/context/PrintContext.tsx new file mode 100644 index 000000000..0d28de589 --- /dev/null +++ b/js/packages/react-ui/src/context/PrintContext.tsx @@ -0,0 +1,16 @@ +import { createContext, useContext, useMemo } from "react"; + +type PrintContextType = {} | null; + +export const PrintContext = createContext(null); + +export const usePrintContext = () => { + const context = useContext(PrintContext); + return context; +}; + +export const PrintContextProvider = ({ children }: { children: React.ReactNode }) => { + const memoizedValue = useMemo(() => ({}), []); + + return {children}; +}; diff --git a/js/packages/react-ui/src/index.ts b/js/packages/react-ui/src/index.ts index ffe735d18..62411aeda 100644 --- a/js/packages/react-ui/src/index.ts +++ b/js/packages/react-ui/src/index.ts @@ -50,3 +50,5 @@ export { // this is the context providers that are used in the shell export * from "./context/LayoutContext"; + +export * from "./context/PrintContext";