Skip to content

Commit bd2df6a

Browse files
authored
fix: web load svg tag data (#2410)
* fix: web load svg tag data * fix typo * fix: svg base64 * fix: svg base64 * setting snapshoot version * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * jsCss optionaldep * CR comments * naming
1 parent 9aed4d7 commit bd2df6a

File tree

9 files changed

+112
-26
lines changed

9 files changed

+112
-26
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@
116116
"react-test-renderer": "^17.0.1",
117117
"reassure": "^0.4.1",
118118
"shell-utils": "^1.0.10",
119-
"typescript": "4.3.2"
119+
"typescript": "4.3.2",
120+
"postcss": "^8.4.21",
121+
"postcss-js": "^4.0.0"
120122
},
121123
"peerDependencies": {
122124
"react": ">=17.0.1",

src/components/button/ButtonConstants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ButtonSize} from './ButtonTypes';
22

3+
34
export const PADDINGS = {
45
XSMALL: 3,
56
SMALL: 4.5,

src/components/svgImage/index.web.tsx

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,59 @@
1-
import React from 'react';
2-
import {isSvg, isSvgUri} from '../../utils/imageUtils';
3-
// import {SvgPackage} from '../../optionalDependencies';
4-
5-
// const SvgXml = SvgPackage?.SvgXml;
6-
// const SvgCssUri = SvgPackage?.SvgCssUri;
7-
// const SvgProps = SvgPackage?.SvgProps; TODO: not sure how (or if) we can use their props
1+
import React, {useState} from 'react';
2+
import {isSvg, isSvgUri, isBase64ImageContent} from '../../utils/imageUtils';
83

4+
const EMPTY_STYLE = '{}';
95
export interface SvgImageProps {
106
/**
117
* the asset tint
128
*/
139
tintColor?: string | null;
1410
data: any; // TODO: I thought this should be string | React.ReactNode but it doesn't work properly
11+
style?: object[];
1512
}
1613

1714
function SvgImage(props: SvgImageProps) {
18-
// tintColor crashes Android, so we're removing this until we properly support it.
19-
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
20-
// const {data, tintColor, ...others} = props;
21-
const {data} = props;
15+
const {
16+
data,
17+
style,
18+
...other
19+
} = props;
20+
21+
const styleObj = Object.assign({}, ...(style || []));
2222

23-
// if (!SvgXml) {
24-
// // eslint-disable-next-line max-len
25-
// console.error(`RNUILib Image "svg" prop requires installing "react-native-svg" and "react-native-svg-transformer" dependencies`);
26-
// return null;
27-
// }
23+
24+
const [svgStyleCss, setSvgStyleCss] = useState<string>(EMPTY_STYLE);
25+
const [postCssStyleCalled, setPostCssStyleCalled] = useState(false);
26+
27+
const createStyleSvgCss = async (PostCssPackage: {postcss: any, cssjs:any}) => {
28+
setPostCssStyleCalled(true);
29+
const {postcss, cssjs} = PostCssPackage;
30+
postcss().process(styleObj, {parser: cssjs})
31+
.then((style: {css: any}) => setSvgStyleCss(`{${style.css}}`));
32+
};
2833

2934
if (isSvgUri(data)) {
30-
return <img src={data.uri}/>;
31-
// return <SvgCssUri {...others} uri={data.uri}/>;
32-
// }
33-
// else if (typeof data === 'string') {
34-
// return <SvgXml xml={data} {...others}/>;
35+
return <img {...other} src={data.uri} style={styleObj}/>;
36+
} else if (isBase64ImageContent(data)) {
37+
return <img {...other} src={data} style={styleObj}/>;
3538
} else if (data) {
36-
return <img src={data}/>;
39+
const PostCssPackage = require('../../optionalDependencies').PostCssPackage;
40+
if (PostCssPackage) {
41+
if (!postCssStyleCalled) {
42+
createStyleSvgCss(PostCssPackage);
43+
return null;
44+
}
45+
const svgStyleTag = `<style> svg ${svgStyleCss} </style>`;
46+
47+
return (
48+
<div
49+
{...other}
50+
// eslint-disable-next-line react/no-danger
51+
dangerouslySetInnerHTML={{__html: svgStyleTag + data}}
52+
/>
53+
);
54+
}
55+
3756
}
38-
3957
return null;
4058
}
4159

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
let PostCssPackage: {postcss: any, cssjs: any} | undefined;
2+
try {
3+
const postcss = require('postcss');
4+
const cssjs = require('postcss-js');
5+
6+
7+
PostCssPackage = {
8+
postcss,
9+
cssjs
10+
};
11+
} catch (error) {}
12+
13+
export default PostCssPackage;

src/optionalDependencies/index.web.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export {default as NetInfoPackage} from './NetInfoPackage';
2+
export {default as HapticFeedbackPackage} from './HapticFeedbackPackage';
3+
export {PickerPackage, CommunityPickerPackage} from './PickerPackage';
4+
export {default as SvgPackage} from './SvgPackage';
5+
export {createShimmerPlaceholder} from './ShimmerPackage';
6+
export {default as LinearGradientPackage} from './LinearGradientPackage';
7+
export {default as AsyncStoragePackage} from './AsyncStoragePackage';
8+
export {default as PostCssPackage} from './PostCssPackage';
9+

src/utils/imageUtils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ export function isSvg(source: ImageProps['source']) {
1111
return typeof source === 'string' || typeof source === 'function' || isSvgUri(source);
1212
}
1313

14+
export function isBase64ImageContent(data: string) {
15+
const base64Content = data.split(',')[1];
16+
const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
17+
return base64regex.test(base64Content);
18+
}
19+
1420
export function getAsset(assetName = '', assetGroup = '') {
1521
return get(Assets, `${assetGroup}.${assetName}`);
1622
}
23+

webDemo/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
"react-native-svg-transformer": "^0.14.3",
3131
"react-native-ui-lib": "snapshot",
3232
"react-native-web": "^0.18.6",
33-
"typescript": "^4.4.2"
33+
"typescript": "^4.4.2",
34+
"postcss": "^8.4.21",
35+
"postcss-js": "^4.0.0"
3436
},
3537
"devDependencies": {
3638
"@babel/core": "^7.14.8",

webDemo/src/App.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,24 @@ interface ItemToRender {
3838
title: string,
3939
FC: React.FC
4040
}
41+
const svgData = `<?xml version="1.0" encoding="UTF-8"?>
42+
<svg data-bbox="2 2 28 28" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" height="800" width="800" data-type="ugc">
43+
<g>
44+
<defs>
45+
<linearGradient gradientUnits="userSpaceOnUse" gradientTransform="matrix(.893 0 0 .893 -64.139 -782.556)" y2="878.134" x2="105.452" y1="910.226" x1="73.714" id="1c6ca7ff-eba0-4dd0-82e3-63fdfa256791">
46+
<stop stop-color="#0296d8" offset="0"/>
47+
<stop stop-color="#8371d9" offset="1"/>
48+
</linearGradient>
49+
<linearGradient gradientUnits="userSpaceOnUse" gradientTransform="matrix(.893 0 0 .893 -64.139 -782.556)" y2="875.745" x2="102.279" y1="905.226" x1="69.813" id="85cd62d4-a6c1-4ded-b1ca-e6c438f49e1b">
50+
<stop stop-color="#cb55c0" offset="0"/>
51+
<stop stop-color="#f28e0e" offset="1"/>
52+
</linearGradient>
53+
</defs>
54+
<path d="M2 2v28h28v-.047l-6.95-7-6.95-7.007 6.95-7.012L29.938 2Z" fill="url(#1c6ca7ff-eba0-4dd0-82e3-63fdfa256791)"/>
55+
<path d="M16.318 2 2 16.318V30h.124l14.008-14.008-.031-.031L23.05 8.95 29.938 2Z" fill="url(#85cd62d4-a6c1-4ded-b1ca-e6c438f49e1b)"/>
56+
</g>
57+
</svg>
58+
`;
4159

4260
const itemsToRender: ItemToRender[] = [
4361
{
@@ -91,6 +109,20 @@ const itemsToRender: ItemToRender[] = [
91109
/>
92110
)
93111
},
112+
{
113+
title: 'Button with Svg as <svg> data tag',
114+
FC: () => (
115+
<Button
116+
label={'Svg tag'}
117+
size={Button.sizes.large}
118+
iconSource={svgData}
119+
iconStyle={{
120+
width: 24,
121+
height: 24
122+
}}
123+
/>
124+
)
125+
},
94126
{
95127
title: 'Link Button',
96128
FC: () => (

webDemo/webpack.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ const baseProjectSource = [
2222
path.resolve(appDirectory, 'node_modules/@react-native-community/netinfo'),
2323
path.resolve(appDirectory, 'node_modules/@react-native-community/datetimepicker'),
2424
path.resolve(appDirectory, 'node_modules/react-native-color'),
25-
path.resolve(appDirectory, 'node_modules/react-native-ui-lib')
25+
path.resolve(appDirectory, 'node_modules/react-native-ui-lib'),
26+
path.resolve(appDirectory, 'node_modules/postcss'),
27+
path.resolve(appDirectory, 'node_modules/postcss-js')
2628
];
2729

2830
const useBabelForRN = {

0 commit comments

Comments
 (0)