Skip to content

fix: web load svg tag data #2410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/components/button/ButtonConstants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {Constants} from '../../../src/commons/new';
import {ButtonSize} from './ButtonTypes';


export const PADDINGS = {
XSMALL: 3,
SMALL: 4.5,
Expand All @@ -22,3 +24,8 @@ export const MIN_WIDTH = {
};

export const DEFAULT_SIZE = ButtonSize.large;

export const ICON_SOURCE_MARGIN = {
LARGE: Constants.isWeb ? '8px' : 8,
SMALL: Constants.isWeb ? '4px' : 4
};
5 changes: 3 additions & 2 deletions src/components/button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Image from '../image';
import {ButtonSize, ButtonAnimationDirection, ButtonProps, ButtonState, Props, DEFAULT_PROPS} from './ButtonTypes';
export {ButtonSize, ButtonAnimationDirection, ButtonProps};

import {PADDINGS, HORIZONTAL_PADDINGS, MIN_WIDTH, DEFAULT_SIZE} from './ButtonConstants';
import {PADDINGS, HORIZONTAL_PADDINGS, MIN_WIDTH, DEFAULT_SIZE, ICON_SOURCE_MARGIN} from './ButtonConstants';

class Button extends PureComponent<Props, ButtonState> {
static displayName = 'Button';
Expand Down Expand Up @@ -246,7 +246,8 @@ class Button extends PureComponent<Props, ButtonState> {
const iconStyle: ImageStyle = {
tintColor: this.getLabelColor()
};
const marginSide = [Button.sizes.large, Button.sizes.medium].includes(size) ? 8 : 4;
const marginSide = [Button.sizes.large, Button.sizes.medium].includes(size)
? ICON_SOURCE_MARGIN.LARGE : ICON_SOURCE_MARGIN.SMALL;

if (!this.isIconButton) {
if (iconOnRight) {
Expand Down
62 changes: 37 additions & 25 deletions src/components/svgImage/index.web.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,53 @@
import React from 'react';
import {isSvg, isSvgUri} from '../../utils/imageUtils';
// import {SvgPackage} from '../../optionalDependencies';

// const SvgXml = SvgPackage?.SvgXml;
// const SvgCssUri = SvgPackage?.SvgCssUri;
// const SvgProps = SvgPackage?.SvgProps; TODO: not sure how (or if) we can use their props

import {isSvg, isSvgUri, isBase64ImageContent} from '../../utils/imageUtils';

const asCss = (styleObj: object) => {
return JSON.stringify(styleObj)
.replace(/"/g, '') // remove all quotes
.replace(/,/g, ';') // replace commas to semicolon
.replace(/\}/g, ';}') // replace closing bracket
.replace(/marginRight/g, 'margin-right')
.replace(/marginLeft/g, 'margin-left')
.replace(/marginTop/g, 'margin-top')
.replace(/marginBottom/g, 'margin-bottom')
.replace(/tintColor/g, 'fill');

};
export interface SvgImageProps {
/**
* the asset tint
*/
tintColor?: string | null;
data: any; // TODO: I thought this should be string | React.ReactNode but it doesn't work properly
style?: object[];
}

function SvgImage(props: SvgImageProps) {
// tintColor crashes Android, so we're removing this until we properly support it.
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
// const {data, tintColor, ...others} = props;
const {data} = props;

// if (!SvgXml) {
// // eslint-disable-next-line max-len
// console.error(`RNUILib Image "svg" prop requires installing "react-native-svg" and "react-native-svg-transformer" dependencies`);
// return null;
// }

const {
data,
style,
...other
} = props;

const styleObj = Object.assign({}, ...(style || []));


if (isSvgUri(data)) {
return <img src={data.uri}/>;
// return <SvgCssUri {...others} uri={data.uri}/>;
// }
// else if (typeof data === 'string') {
// return <SvgXml xml={data} {...others}/>;
return <img {...other} src={data.uri} style={styleObj}/>;
} else if (isBase64ImageContent(data)) {
return <img {...other} src={data} style={styleObj}/>;
} else if (data) {
return <img src={data}/>;
const svgStyle = asCss(styleObj);
const svgStyleTag = `<style> svg ${svgStyle} </style>`;

return (
<div
{...other}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: svgStyleTag + data}}
/>
);
}

return null;
}

Expand Down
7 changes: 7 additions & 0 deletions src/utils/imageUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ export function isSvg(source: ImageProps['source']) {
return typeof source === 'string' || typeof source === 'function' || isSvgUri(source);
}

export function isBase64ImageContent(data: string) {
const base64Content = data.split(',')[1];
const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
return base64regex.test(base64Content);
}

export function getAsset(assetName = '', assetGroup = '') {
return get(Assets, `${assetGroup}.${assetName}`);
}

2 changes: 1 addition & 1 deletion webDemo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"react-native-shimmer-placeholder": "^2.0.8",
"react-native-svg": "^12.1.0",
"react-native-svg-transformer": "^0.14.3",
"react-native-ui-lib": "snapshot",
"react-native-ui-lib": "6.27.3-snapshot.2347",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example does work.
We need to change the version to master or ga.

"react-native-web": "^0.18.6",
"typescript": "^4.4.2"
},
Expand Down
32 changes: 32 additions & 0 deletions webDemo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ interface ItemToRender {
title: string,
FC: React.FC
}
const svgData = `<?xml version="1.0" encoding="UTF-8"?>
<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">
<g>
<defs>
<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">
<stop stop-color="#0296d8" offset="0"/>
<stop stop-color="#8371d9" offset="1"/>
</linearGradient>
<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">
<stop stop-color="#cb55c0" offset="0"/>
<stop stop-color="#f28e0e" offset="1"/>
</linearGradient>
</defs>
<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)"/>
<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)"/>
</g>
</svg>
`;

const itemsToRender: ItemToRender[] = [
{
Expand Down Expand Up @@ -91,6 +109,20 @@ const itemsToRender: ItemToRender[] = [
/>
)
},
{
title: 'Button with Svg as <svg> data tag',
FC: () => (
<Button
label={'Svg tag'}
size={Button.sizes.large}
iconSource={svgData}
iconStyle={{
width: '24px',
height: '24px'
}}
/>
)
},
{
title: 'Link Button',
FC: () => (
Expand Down