Skip to content

Commit 6c1cf58

Browse files
authored
Image - support SVG from uri (#1712)
1 parent 8462de9 commit 6c1cf58

File tree

4 files changed

+50
-10
lines changed

4 files changed

+50
-10
lines changed

demo/src/screens/componentScreens/ImageScreen.tsx

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const BROKEN_URL = 'file:///Desktop/website/img/cupcake.jpg';
99
const DEFAULT_SIZE = 100;
1010

1111
const file = Assets.svgs.demo.logo;
12+
const uri = {uri: 'http://thenewcode.com/assets/images/thumbnails/homer-simpson.svg'};
13+
const uriWithCss = {uri: 'http://thenewcode.com/assets/svg/accessibility.svg'};
1214
const xml = `
1315
<svg width="32" height="32" viewBox="0 0 32 32">
1416
<path
@@ -38,6 +40,13 @@ enum SizeType {
3840
Percentage = '50%'
3941
}
4042

43+
enum SvgType {
44+
File = 'file',
45+
Uri = 'uri',
46+
UriWithCss = 'use_with_css',
47+
Xml = 'xml'
48+
}
49+
4150
interface State {
4251
cover: boolean;
4352
showOverlayContent: boolean;
@@ -46,7 +55,7 @@ interface State {
4655
margin: number;
4756
showErrorImage: boolean;
4857
showSvg: boolean;
49-
isFile: boolean;
58+
svgType: SvgType;
5059
sizeType: SizeType;
5160
}
5261

@@ -59,10 +68,25 @@ class ImageScreen extends Component<{}, State> {
5968
margin: 0,
6069
showErrorImage: false,
6170
showSvg: false,
62-
isFile: false,
71+
svgType: SvgType.File,
6372
sizeType: SizeType.None
6473
};
6574

75+
getSvgSource() {
76+
const {svgType} = this.state;
77+
switch (svgType) {
78+
case SvgType.File:
79+
return file;
80+
case SvgType.Uri:
81+
return uri;
82+
case SvgType.UriWithCss:
83+
return uriWithCss;
84+
case SvgType.Xml:
85+
default:
86+
return xml;
87+
}
88+
}
89+
6690
renderOverlayContent() {
6791
const {cover, overlayType, showOverlayContent} = this.state;
6892
if (showOverlayContent) {
@@ -105,14 +129,15 @@ class ImageScreen extends Component<{}, State> {
105129
}
106130

107131
renderSvgImage() {
108-
const {isFile, sizeType} = this.state;
132+
const {sizeType} = this.state;
109133
const size: any = Number(sizeType) || sizeType;
134+
const source = this.getSvgSource();
110135
return (
111136
<>
112137
{size ? (
113-
<Image source={isFile ? file : xml} width={size} height={size}/>
138+
<Image source={source} width={size} height={size}/>
114139
) : (
115-
<Image source={isFile ? file : xml}/>
140+
<Image source={source}/>
116141
)}
117142
</>
118143
);
@@ -134,10 +159,9 @@ class ImageScreen extends Component<{}, State> {
134159
}
135160

136161
renderSvgOptions() {
137-
const {isFile} = this.state;
138162
return (
139163
<>
140-
{renderBooleanOption.call(this, isFile ? 'Load from file' : 'Use xml const', 'isFile')}
164+
{renderRadioGroup.call(this, 'SVG Type', 'svgType', SvgType, {isRow: true})}
141165
{renderRadioGroup.call(this, 'Size Type', 'sizeType', SizeType, {isRow: true})}
142166
</>
143167
);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
/// <reference types="react" />
2+
import { ImageProps } from 'react-native';
3+
export declare function isSvg(source: ImageProps['source']): any;
24
export interface SvgImageProps {
35
data: any;
46
}
57
declare function SvgImage(props: SvgImageProps): JSX.Element | null;
68
declare namespace SvgImage {
79
var displayName: string;
10+
var isSvg: typeof import("./SvgImage").isSvg;
811
}
912
export default SvgImage;

src/components/image/SvgImage.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import React from 'react';
2+
import {ImageProps} from 'react-native';
23
import {SvgPackage} from '../../optionalDependencies';
34
const SvgXml = SvgPackage?.SvgXml;
5+
const SvgCssUri = SvgPackage?.SvgCssUri;
46
// const SvgProps = SvgPackage?.SvgProps; TODO: not sure how (or if) we can use their props
57

8+
function isSvgUri(source: ImageProps['source']) {
9+
// @ts-expect-error
10+
return typeof source === 'object' && source?.uri?.endsWith('.svg');
11+
}
12+
13+
export function isSvg(source: ImageProps['source']) {
14+
return typeof source === 'string' || typeof source === 'function' || isSvgUri(source);
15+
}
16+
617
export interface SvgImageProps {
718
data: any; // TODO: I thought this should be string | React.ReactNode but it doesn't work properly
819
}
@@ -16,7 +27,9 @@ function SvgImage(props: SvgImageProps) {
1627
return null;
1728
}
1829

19-
if (typeof data === 'string') {
30+
if (isSvgUri(data)) {
31+
return <SvgCssUri {...others} uri={data.uri}/>;
32+
} else if (typeof data === 'string') {
2033
return <SvgXml xml={data} {...others}/>;
2134
} else if (data) {
2235
const File = data; // Must be with capital letter
@@ -27,5 +40,6 @@ function SvgImage(props: SvgImageProps) {
2740
}
2841

2942
SvgImage.displayName = 'IGNORE';
43+
SvgImage.isSvg = isSvg;
3044

3145
export default SvgImage;

src/components/image/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,7 @@ class Image extends PureComponent<Props, State> {
254254

255255
render() {
256256
const {source} = this.props;
257-
const isSvg = typeof source === 'string' || typeof source === 'function';
258-
if (isSvg) {
257+
if (SvgImage.isSvg(source)) {
259258
return this.renderSvg();
260259
} else {
261260
return this.renderRegularImage();

0 commit comments

Comments
 (0)