Merge pull request #318 from unslothai/fix/recharts-dimension-warning
Fix Recharts -1 dimension warning on chart mount
This commit is contained in:
commit
ff56a5f785
2 changed files with 109 additions and 37 deletions
|
|
@ -46,22 +46,94 @@ function ChartContainer({
|
|||
}) {
|
||||
const uniqueId = React.useId();
|
||||
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
|
||||
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
||||
const [containerSize, setContainerSize] = React.useState<{
|
||||
width: number;
|
||||
height: number;
|
||||
} | null>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
const element = containerRef.current;
|
||||
if (!element) return;
|
||||
|
||||
const updateSizeState = () => {
|
||||
const { width, height } = element.getBoundingClientRect();
|
||||
const nextSize =
|
||||
width > 0 && height > 0
|
||||
? {
|
||||
width: Math.round(width),
|
||||
height: Math.round(height),
|
||||
}
|
||||
: null;
|
||||
|
||||
setContainerSize((currentSize) => {
|
||||
if (!nextSize) {
|
||||
// Keep the last valid size once mounted to avoid unmount/remount thrash.
|
||||
return currentSize;
|
||||
}
|
||||
if (
|
||||
currentSize &&
|
||||
currentSize.width === nextSize.width &&
|
||||
currentSize.height === nextSize.height
|
||||
) {
|
||||
return currentSize;
|
||||
}
|
||||
return nextSize;
|
||||
});
|
||||
};
|
||||
|
||||
updateSizeState();
|
||||
|
||||
if (typeof ResizeObserver === "undefined") {
|
||||
const recheckSize = () => {
|
||||
if (document.visibilityState === "visible") {
|
||||
updateSizeState();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("resize", recheckSize);
|
||||
window.addEventListener("orientationchange", recheckSize);
|
||||
document.addEventListener("visibilitychange", recheckSize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", recheckSize);
|
||||
window.removeEventListener("orientationchange", recheckSize);
|
||||
document.removeEventListener("visibilitychange", recheckSize);
|
||||
};
|
||||
}
|
||||
|
||||
const observer = new ResizeObserver(() => {
|
||||
updateSizeState();
|
||||
});
|
||||
observer.observe(element);
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ChartContext.Provider value={{ config }}>
|
||||
<div
|
||||
ref={containerRef}
|
||||
data-slot="chart"
|
||||
data-chart={chartId}
|
||||
className={cn(
|
||||
"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
|
||||
"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex min-w-0 aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChartStyle id={chartId} config={config} />
|
||||
<RechartsPrimitive.ResponsiveContainer>
|
||||
{children}
|
||||
</RechartsPrimitive.ResponsiveContainer>
|
||||
{containerSize ? (
|
||||
<RechartsPrimitive.ResponsiveContainer
|
||||
width="100%"
|
||||
height="100%"
|
||||
minWidth={0}
|
||||
minHeight={1}
|
||||
initialDimension={containerSize}
|
||||
>
|
||||
{children}
|
||||
</RechartsPrimitive.ResponsiveContainer>
|
||||
) : null}
|
||||
</div>
|
||||
</ChartContext.Provider>
|
||||
);
|
||||
|
|
@ -100,30 +172,30 @@ ${colorConfig
|
|||
);
|
||||
};
|
||||
|
||||
const ChartTooltip = RechartsPrimitive.Tooltip;
|
||||
|
||||
function ChartTooltipContent({
|
||||
active,
|
||||
payload,
|
||||
className,
|
||||
const ChartTooltip = RechartsPrimitive.Tooltip;
|
||||
|
||||
function ChartTooltipContent({
|
||||
active,
|
||||
payload,
|
||||
className,
|
||||
indicator = "dot",
|
||||
hideLabel = false,
|
||||
hideIndicator = false,
|
||||
label,
|
||||
labelFormatter,
|
||||
labelClassName,
|
||||
formatter,
|
||||
color,
|
||||
nameKey,
|
||||
labelKey,
|
||||
}: Partial<RechartsPrimitive.TooltipContentProps<any, any>> &
|
||||
React.ComponentProps<"div"> & {
|
||||
hideLabel?: boolean;
|
||||
hideIndicator?: boolean;
|
||||
indicator?: "line" | "dot" | "dashed";
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}) {
|
||||
formatter,
|
||||
color,
|
||||
nameKey,
|
||||
labelKey,
|
||||
}: Partial<RechartsPrimitive.TooltipContentProps<any, any>> &
|
||||
React.ComponentProps<"div"> & {
|
||||
hideLabel?: boolean;
|
||||
hideIndicator?: boolean;
|
||||
indicator?: "line" | "dot" | "dashed";
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}) {
|
||||
const { config } = useChart();
|
||||
|
||||
const tooltipLabel = React.useMemo(() => {
|
||||
|
|
@ -248,20 +320,20 @@ function ChartTooltipContent({
|
|||
);
|
||||
}
|
||||
|
||||
const ChartLegend = RechartsPrimitive.Legend;
|
||||
|
||||
function ChartLegendContent({
|
||||
className,
|
||||
hideIcon = false,
|
||||
payload,
|
||||
verticalAlign = "bottom",
|
||||
nameKey,
|
||||
}: React.ComponentProps<"div"> &
|
||||
Pick<RechartsPrimitive.DefaultLegendContentProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}) {
|
||||
const { config } = useChart();
|
||||
const ChartLegend = RechartsPrimitive.Legend;
|
||||
|
||||
function ChartLegendContent({
|
||||
className,
|
||||
hideIcon = false,
|
||||
payload,
|
||||
verticalAlign = "bottom",
|
||||
nameKey,
|
||||
}: React.ComponentProps<"div"> &
|
||||
Pick<RechartsPrimitive.DefaultLegendContentProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}) {
|
||||
const { config } = useChart();
|
||||
|
||||
if (!payload?.length) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ export function TrainingSection() {
|
|||
<div className="relative ">
|
||||
<ChartContainer
|
||||
config={chartConfig}
|
||||
className="min-h-[180px] w-full relative right-8 w-full blur "
|
||||
className="h-[180px] w-full relative right-8 blur"
|
||||
>
|
||||
<LineChart data={placeholderData} accessibilityLayer={true}>
|
||||
<CartesianGrid vertical={false} strokeDasharray="3 3" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue