diff --git a/USAGE.md b/USAGE.md index 6e9b21557..250a1f7ec 100644 --- a/USAGE.md +++ b/USAGE.md @@ -92,14 +92,15 @@ If remote SVG file contains CSS in ` + + CSS Styled + +`); + +const calculateWidth = (svgProps: SvgProps, desiredHeight: number) => { + let originalHeight = svgProps.height; + let originalWidth = svgProps.width; + if (originalWidth && originalHeight) { + return (Number(originalWidth) / Number(originalHeight)) * desiredHeight; + } +}; + +const ExampleWithSvgUri = () => { + const [width, setWidth] = useState(0); + const height = 12; + + const handleLoad = (svgProps: SvgProps) => { + const calculatedWidth = calculateWidth(svgProps, height); + if (calculatedWidth) { + setWidth(calculatedWidth); + } + }; + return ( + + SvgUri component + + Original Size ✅ + + + + Set different height ❌ + + + + + Preserve Aspect Ratio Meet ❌ + + + + + Preserve Aspect Ratio Slice ❌ + + + + + Preserve Aspect Ratio None ❌ + + + + + Auto calculate width ✅ + + + + ); +}; + +const ExampleWithSvgCssUri = () => { + const [width, setWidth] = useState(0); + const height = 25; + const handleLoad = (svgProps: SvgProps) => { + const calculatedWidth = calculateWidth(svgProps, height); + if (calculatedWidth) { + setWidth(calculatedWidth); + } + }; + + return ( + + SvgCssUri component + + Original Size ✅ + + + + Set different height ❌ + + + + + Preserve Aspect Ratio Meet ❌ + + + + + Preserve Aspect Ratio Slice ❌ + + + + + Preserve Aspect Ratio None ❌ + + + + + Auto calculate width ✅ + + + + ); +}; + +export default () => { + return ( + + + + + ); +}; diff --git a/apps/common/test/index.tsx b/apps/common/test/index.tsx index 2c1954cc9..1781c86d5 100644 --- a/apps/common/test/index.tsx +++ b/apps/common/test/index.tsx @@ -35,6 +35,7 @@ import Test2417 from './Test2417'; import Test2455 from './Test2455'; import Test2471 from './Test2471'; import Test2520 from './Test2520'; +import Test2540 from './SvgUriOnLoad'; import Test2670 from './Test2670'; export default function App() { diff --git a/src/css/css.tsx b/src/css/css.tsx index fba0e416c..83fafa0d4 100644 --- a/src/css/css.tsx +++ b/src/css/css.tsx @@ -766,17 +766,29 @@ export const inlineStyles: Middleware = function inlineStyles( }; export function SvgCss(props: XmlProps) { - const { xml, override, fallback, onError = err } = props; - try { - const ast = useMemo( - () => (xml !== null ? parse(xml, inlineStyles) : null), - [xml] - ); - return ; - } catch (error) { - onError(error); + const { xml, override, fallback, onError = err, onLoad } = props; + + const [ast, error] = useMemo<[JsxAST | null, unknown]>(() => { + try { + const parsed = xml !== null ? parse(xml, inlineStyles) : null; + return [parsed, null]; + } catch (exc) { + return [null, exc]; + } + }, [xml]); + + useEffect(() => { + if (!error && ast?.props) { + onLoad?.(ast.props); + } else if (error) { + onError(error as Error); + } + }, [ast, error, onLoad, onError]); + + if (error) { return fallback ?? null; } + return ; } export function SvgCssUri(props: UriProps) { @@ -788,7 +800,6 @@ export function SvgCssUri(props: UriProps) { ? fetchText(uri) .then((data) => { setXml(data); - onLoad?.(); }) .catch((e) => { onError(e); @@ -799,7 +810,9 @@ export function SvgCssUri(props: UriProps) { if (isError) { return fallback ?? null; } - return ; + return ( + + ); } // Extending Component is required for Animated support. diff --git a/src/xml.tsx b/src/xml.tsx index 073888c13..d46dad4b7 100644 --- a/src/xml.tsx +++ b/src/xml.tsx @@ -35,7 +35,7 @@ export interface JsxAST extends AST { export type AdditionalProps = { onError?: (error: Error) => void; override?: object; - onLoad?: () => void; + onLoad?: (svgProps: SvgProps) => void; fallback?: JSX.Element; }; @@ -65,18 +65,29 @@ export function SvgAst({ ast, override }: AstProps) { const err = console.error.bind(console); export function SvgXml(props: XmlProps) { - const { onError = err, xml, override, fallback } = props; + const { onError = err, xml, override, fallback, onLoad } = props; - try { - const ast = useMemo( - () => (xml !== null ? parse(xml) : null), - [xml] - ); - return ; - } catch (error) { - onError(error); + const [ast, error] = useMemo<[JsxAST | null, unknown]>(() => { + try { + const parsed = xml !== null ? parse(xml) : null; + return [parsed, null]; + } catch (exc) { + return [null, exc]; + } + }, [xml]); + + useEffect(() => { + if (!error && ast?.props) { + onLoad?.(ast.props); + } else if (error) { + onError(error as Error); + } + }, [ast, error, onError, onLoad]); + + if (error) { return fallback ?? null; } + return ; } export function SvgUri(props: UriProps) { @@ -89,7 +100,6 @@ export function SvgUri(props: UriProps) { .then((data) => { setXml(data); isError && setIsError(false); - onLoad?.(); }) .catch((e) => { onError(e); @@ -101,7 +111,9 @@ export function SvgUri(props: UriProps) { if (isError) { return fallback ?? null; } - return ; + return ( + + ); } // Extending Component is required for Animated support.