mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-05 22:56:11 +00:00
# Summary Due to the large number of example apps in the repository, I decided to change the structure and move all applications into an "apps" folder to maintain a clear structure.
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
|
import {Platform, Text, View} from 'react-native';
|
|
import * as RNSVG from 'react-native-svg';
|
|
import ViewShot from 'react-native-view-shot';
|
|
|
|
const address = ['ios', 'web'].includes(Platform.OS) ? 'localhost' : '10.0.2.2';
|
|
const wsUri = `ws://${address}:7123`;
|
|
|
|
export const TestingView = () => {
|
|
const wrapperRef = useRef<ViewShot>(null);
|
|
const [wsClient, setWsClient] = useState<WebSocket | null>(null);
|
|
const [renderedContent, setRenderedContent] =
|
|
useState<React.ReactElement | null>();
|
|
const [readyToSnapshot, setReadyToSnapshot] = useState(false);
|
|
const [resolution, setResolution] = useState([0, 0]); // placeholder value, later updated by incoming render requests
|
|
const [message, setMessage] = useState('⏳ Connecting to Jest server...');
|
|
|
|
const connect = useCallback(() => {
|
|
const client = new WebSocket(wsUri);
|
|
setWsClient(client);
|
|
setMessage('⏳ Connecting to Jest server...');
|
|
client.onopen = () => {
|
|
client.send(
|
|
JSON.stringify({
|
|
os: Platform.OS,
|
|
version: Platform.Version,
|
|
arch: isFabric() ? 'fabric' : 'paper',
|
|
connectionTime: new Date(),
|
|
}),
|
|
);
|
|
setMessage('✅ Connected to Jest server. Waiting for render requests.');
|
|
};
|
|
client.onerror = (err: any) => {
|
|
if (!err.message) {
|
|
return;
|
|
}
|
|
console.error(
|
|
`Error while connecting to E2E WebSocket server at ${wsUri}: ${err.message}. Will retry in 3 seconds.`,
|
|
);
|
|
setMessage(
|
|
`🚨 Failed to connect to Jest server at ${wsUri}: ${err.message}! Will retry in 3 seconds.`,
|
|
);
|
|
setTimeout(() => {
|
|
connect();
|
|
}, 3000);
|
|
};
|
|
client.onmessage = ({data: rawMessage}) => {
|
|
const message = JSON.parse(rawMessage);
|
|
if (message.type == 'renderRequest') {
|
|
setMessage(`✅ Rendering tests, please don't close this tab.`);
|
|
setResolution([message.width, message.height]);
|
|
setRenderedContent(
|
|
createElementFromObject(
|
|
message.data.type || 'SvgFromXml',
|
|
message.data.props,
|
|
),
|
|
);
|
|
setReadyToSnapshot(true);
|
|
}
|
|
};
|
|
client.onclose = event => {
|
|
if (event.code == 1006 && event.reason) {
|
|
// this is an error, let error handler take care of it
|
|
return;
|
|
}
|
|
setMessage(
|
|
`✅ Connection to Jest server has been closed. You can close this tab safely. (${event.code})`,
|
|
);
|
|
};
|
|
}, [wsClient]);
|
|
|
|
// Create initial connection when rendering the view
|
|
useEffect(connect, []);
|
|
|
|
// Whenever new content is rendered, send renderResponse with snapshot view
|
|
useEffect(() => {
|
|
if (!readyToSnapshot || !wrapperRef.current) {
|
|
return;
|
|
}
|
|
wrapperRef.current.capture?.().then((value: string) => {
|
|
wsClient?.send(
|
|
JSON.stringify({
|
|
type: 'renderResponse',
|
|
data: value,
|
|
}),
|
|
);
|
|
setReadyToSnapshot(false);
|
|
});
|
|
}, [wrapperRef, readyToSnapshot]);
|
|
|
|
return (
|
|
<View>
|
|
<Text style={{marginLeft: 'auto', marginRight: 'auto'}}>{message}</Text>
|
|
<ViewShot
|
|
ref={wrapperRef}
|
|
style={{width: resolution[0], height: resolution[1]}}
|
|
options={{result: 'base64'}}>
|
|
{renderedContent}
|
|
</ViewShot>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
function isFabric(): boolean {
|
|
// @ts-expect-error nativeFabricUIManager is not yet included in the RN types
|
|
return !!global?.nativeFabricUIManager;
|
|
}
|
|
|
|
const createElementFromObject = (
|
|
element: keyof typeof RNSVG,
|
|
props: any,
|
|
): React.ReactElement => {
|
|
const children: any[] = [];
|
|
if (props.children) {
|
|
if (Array.isArray(props.children)) {
|
|
props?.children.forEach((child: {type: any; props: any}) =>
|
|
children.push(createElementFromObject(child.type, child?.props)),
|
|
);
|
|
} else if (typeof props.children === 'object') {
|
|
children.push(
|
|
createElementFromObject(props.children.type, props.children?.props),
|
|
);
|
|
} else {
|
|
children.push(props.children);
|
|
}
|
|
}
|
|
return React.createElement(RNSVG[element] as any, {...props, children});
|
|
};
|