import React, { useEffect, useRef, useState } from "react"; type AutoSizingSvgProps = { padding?: number; bgColor?: string; sizeToElement?: React.RefObject; children: JSX.Element | JSX.Element[]; }; function useResizeHandler(onResize: () => void) { useEffect(() => { window.addEventListener("resize", onResize); return () => { window.removeEventListener("resize", onResize); }; }); } /** * An SVG element with an optional background color that * automatically sizes itself to either its contents, or * if the `sizeToElement` prop is provided, to the given * container. */ export const AutoSizingSvg = React.forwardRef( (props: AutoSizingSvgProps, ref: React.ForwardedRef) => { const { bgColor, sizeToElement } = props; const [x, setX] = useState(0); const [y, setY] = useState(0); const [width, setWidth] = useState(1); const [height, setHeight] = useState(1); const gRef = useRef(null); const resizeToElement = () => { if (sizeToElement?.current) { const bbox = sizeToElement.current.getBoundingClientRect(); setX(-bbox.width / 2); setY(-bbox.height / 2); setWidth(bbox.width); setHeight(bbox.height); return true; } return false; }; useResizeHandler(resizeToElement); useEffect(() => { if (!resizeToElement()) { const svgEl = gRef.current; if (svgEl) { const bbox = svgEl.getBBox(); const padding = props.padding || 0; setX(bbox.x - padding); setY(bbox.y - padding); setWidth(bbox.width + padding * 2); setHeight(bbox.height + padding * 2); } } }); return ( {bgColor && ( )} {props.children} ); } );