import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'; import type { StyleProp, ViewStyle } from 'react-native'; type Props = { source: { uri?: string; html?: string; headers?: Record }; style?: StyleProp; injectedJavaScript?: string; onMessage?: (ev: { nativeEvent: { data: string } }) => void; onLoadStart?: () => void; onLoad?: () => void; onLoadEnd?: () => void; onError?: (syntheticEvent: { nativeEvent: { code: number; description: string }; }) => void; onNavigationStateChange?: (navState: { url: string; loading: boolean; canGoBack: boolean; canGoForward: boolean; }) => void; onShouldStartLoadWithRequest?: (event: { url: string }) => boolean; scrollEnabled?: boolean; bounces?: boolean; }; /** * Web-based implementation of React Native WebView using iframe */ export const WebView = forwardRef((props: Props, ref) => { const iframeRef = useRef(null); const { source, style, injectedJavaScript, onMessage, onLoadStart, onLoad, onLoadEnd, onNavigationStateChange, } = props; useEffect(() => { const handleMessage = (event: MessageEvent) => { onMessage?.({ nativeEvent: { data: event.data } }); }; window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, [onMessage]); // Imperative handle to match RN WebView API useImperativeHandle(ref, () => ({ injectJavaScript: (js: string) => { iframeRef.current?.contentWindow?.postMessage(js, '*'); }, goBack: () => { iframeRef.current?.contentWindow?.history.back(); }, goForward: () => { iframeRef.current?.contentWindow?.history.forward(); }, reload: () => { iframeRef.current?.contentWindow?.location.reload(); }, stopLoading: () => { // Not directly possible with iframe }, })); const src = source.html ? `data:text/html;charset=utf-8,${encodeURIComponent(source.html)}` : source.uri; return (