react-native-svg
Version:
SVG library for react-native
76 lines (71 loc) • 2.36 kB
text/typescript
import {
ImageResolvedAssetSource,
PixelRatio,
type ImageProps as RNImageProps,
} from 'react-native';
// @ts-expect-error react-native/assets-registry doesn't export types.
import { getAssetByID } from '@react-native/assets-registry/registry';
export type PackagerAsset = {
__packager_asset: boolean;
fileSystemLocation: string;
httpServerLocation: string;
width?: number;
height?: number;
scales: Array<number>;
hash: string;
name: string;
type: string;
};
const svgDataUriPattern = /^(data:image\/svg\+xml;utf8,)(.*)/;
// Based on that function: https://github.com/necolas/react-native-web/blob/54c14d64dabd175e8055e1dc92e9196c821f9b7d/packages/react-native-web/src/exports/Image/index.js#L118-L156
export function resolveAssetUri(
source?: RNImageProps['source'] | string | number
): Partial<ImageResolvedAssetSource> | null {
let src: Partial<ImageResolvedAssetSource> = {};
if (typeof source === 'number') {
// get the URI from the packager
const asset: PackagerAsset | null = getAssetByID(source);
if (asset == null) {
throw new Error(
`Image: asset with ID "${source}" could not be found. Please check the image source or packager.`
);
}
src = {
width: asset.width,
height: asset.height,
scale: asset.scales[0],
};
if (asset.scales.length > 1) {
const preferredScale = PixelRatio.get();
// Get the scale which is closest to the preferred scale
src.scale = asset.scales.reduce((prev, curr) =>
Math.abs(curr - preferredScale) < Math.abs(prev - preferredScale)
? curr
: prev
);
}
const scaleSuffix = src.scale !== 1 ? `@${src.scale}x` : '';
src.uri = asset
? `${asset.httpServerLocation}/${asset.name}${scaleSuffix}.${asset.type}`
: '';
} else if (typeof source === 'string') {
src.uri = source;
} else if (
source &&
!Array.isArray(source) &&
typeof source.uri === 'string'
) {
src.uri = source.uri;
}
if (src.uri) {
const match = src?.uri?.match(svgDataUriPattern);
// inline SVG markup may contain characters (e.g., #, ") that need to be escaped
if (match) {
const [, prefix, svg] = match;
const encodedSvg = encodeURIComponent(svg);
src.uri = `${prefix}${encodedSvg}`;
return src;
}
}
return src;
}