diff --git a/app/components/Base/RemoteImage/index.js b/app/components/Base/RemoteImage/index.js
index 53aba49ae0d..f47269f60ce 100644
--- a/app/components/Base/RemoteImage/index.js
+++ b/app/components/Base/RemoteImage/index.js
@@ -10,6 +10,7 @@ import ComponentErrorBoundary from '../../UI/ComponentErrorBoundary';
import useIpfsGateway from '../../hooks/useIpfsGateway';
import { getFormattedIpfsUrl } from '@metamask/assets-controllers';
import Identicon from '../../UI/Identicon';
+import useSvgUriViewBox from '../../hooks/useSvgUriViewBox';
const createStyles = () =>
StyleSheet.create({
@@ -40,16 +41,19 @@ const RemoteImage = (props) => {
const onError = ({ nativeEvent: { error } }) => setError(error);
+ const isSVG =
+ source &&
+ source.uri &&
+ source.uri.match('.svg') &&
+ (isImageUrl || resolvedIpfsUrl);
+
+ const viewbox = useSvgUriViewBox(uri, isSVG);
+
if (error && props.address) {
return ;
}
- if (
- source &&
- source.uri &&
- source.uri.match('.svg') &&
- (isImageUrl || resolvedIpfsUrl)
- ) {
+ if (isSVG) {
const style = props.style || {};
if (source.__packager_asset && typeof style !== 'number') {
if (!style.width) {
@@ -66,7 +70,13 @@ const RemoteImage = (props) => {
componentLabel="RemoteImage-SVG"
>
-
+
);
diff --git a/app/components/hooks/useSvgUriViewBox.test.ts b/app/components/hooks/useSvgUriViewBox.test.ts
new file mode 100644
index 00000000000..30bf04a88f8
--- /dev/null
+++ b/app/components/hooks/useSvgUriViewBox.test.ts
@@ -0,0 +1,42 @@
+import { renderHook, waitFor } from '@testing-library/react-native';
+import useSvgUriViewBox from './useSvgUriViewBox';
+
+describe('useSvgUriViewBox()', () => {
+ const MOCK_SVG_WITH_VIEWBOX = ``;
+ const MOCK_SVG_WITHOUT_VIEWBOX = ``;
+
+ function arrangeMocks() {
+ const mockResponseTextFn = jest
+ .fn()
+ .mockResolvedValue(MOCK_SVG_WITHOUT_VIEWBOX);
+ jest
+ .spyOn(global, 'fetch')
+ .mockResolvedValue({ text: mockResponseTextFn } as unknown as Response);
+
+ return { mockText: mockResponseTextFn };
+ }
+
+ it('should return view-box if svg if missing a view-box', async () => {
+ const { mockText } = arrangeMocks();
+ mockText.mockResolvedValueOnce(MOCK_SVG_WITHOUT_VIEWBOX);
+
+ const hook = renderHook(() => useSvgUriViewBox('URI', true));
+ await waitFor(() => expect(hook.result.current).toBeDefined());
+ });
+
+ it('should return view-box if svg already has view-box', async () => {
+ const { mockText } = arrangeMocks();
+ mockText.mockResolvedValueOnce(MOCK_SVG_WITH_VIEWBOX);
+
+ const hook = renderHook(() => useSvgUriViewBox('URI', true));
+ await waitFor(() => expect(hook.result.current).toBeDefined());
+ });
+
+ it('should not make async calls if image is not an svg', async () => {
+ const mocks = arrangeMocks();
+ const hook = renderHook(() => useSvgUriViewBox('URI', false));
+
+ await waitFor(() => expect(hook.result.current).toBeUndefined());
+ expect(mocks.mockText).not.toHaveBeenCalled();
+ });
+});
diff --git a/app/components/hooks/useSvgUriViewBox.ts b/app/components/hooks/useSvgUriViewBox.ts
new file mode 100644
index 00000000000..bbfb1ee2bc3
--- /dev/null
+++ b/app/components/hooks/useSvgUriViewBox.ts
@@ -0,0 +1,49 @@
+import { useEffect, useState } from 'react';
+
+/**
+ * Support svg images urls that do not have a view box
+ * See: https://github.com/software-mansion/react-native-svg/issues/1202#issuecomment-1891110599
+ *
+ * This will return the default SVG ViewBox from an SVG URI
+ * @param uri - uri to fetch
+ * @param isSVG - check to see if the uri is an svg
+ * @returns viewbox string
+ */
+export default function useSvgUriViewBox(
+ uri: string,
+ isSVG: boolean,
+): string | undefined {
+ const [viewBox, setViewBox] = useState(undefined);
+
+ useEffect(() => {
+ if (!isSVG) {
+ return;
+ }
+
+ fetch(uri)
+ .then((response) => response.text())
+ .then((svgContent) => {
+ const widthMatch = svgContent.match(/width="([^"]+)"/);
+ const heightMatch = svgContent.match(/height="([^"]+)"/);
+ const viewBoxMatch = svgContent.match(/viewBox="([^"]+)"/);
+
+ if (viewBoxMatch?.[1]) {
+ setViewBox(viewBoxMatch[1]);
+ return;
+ }
+
+ if (widthMatch?.[1] && heightMatch?.[1]) {
+ const width = widthMatch[1];
+ const height = heightMatch[1];
+ setViewBox(`0 0 ${width} ${height}`);
+ }
+ })
+ .catch((error) => console.error('Error fetching SVG:', error));
+ }, [isSVG, uri]);
+
+ if (!viewBox) {
+ return undefined;
+ }
+
+ return viewBox;
+}