import React, { cloneElement, FC, useEffect, useRef } from 'react'; import { View } from 'react-native'; import Logger from '../core/logging/logger'; import CSQMethodFilter from '../csq/CSQMethodFilter'; import { CSWebViewProps } from '../types/types'; import { hasOnlyOneChild, mergeCallbacks } from '../utils/utils'; import { registerWebView, unregisterWebView } from './csqWebViewMethods'; /** * CSQWebView is a wrapper around the React Native WebView component. * * @param children - The child webview component to render. */ export const CSQWebView: FC = ({ children }) => { const nativeTag = useRef(undefined); const injectedWebViewTag = useRef(undefined); const hasOneChild = hasOnlyOneChild(children); useEffect(() => { CSQMethodFilter.warnIfDisabled('CSQ', 'CSQWebView'); return () => { if (injectedWebViewTag.current != null) { unregisterWebView(injectedWebViewTag.current); } }; }, []); useEffect(() => { if (children && !hasOneChild) { Logger.error( 'CSQWebView component expects exactly 1 child, but received multiple. Ensure that only a single child element is passed' ); } }, [children]); // We need to clone React Native WebView so we can inject the webview onLoadEnd const renderChildWebView = () => { if (children && hasOneChild) { const userOnLoadEnd = (children as React.ReactElement).props .onLoadEnd; const originalApplicationNameForUserAgent = (children as React.ReactElement).props.applicationNameForUserAgent; const webViewApplicationNameForUserAgent = originalApplicationNameForUserAgent ? `${originalApplicationNameForUserAgent} CS_WebView` : `CS_WebView`; // We need to be sure to call our internal onLoadEnd method which is the responsible of starting // the injection process but also we need to keep React Native WebView onLoadEnd prop that could // have been defined by the user const mergeOnLoadEnd = mergeCallbacks(inject, userOnLoadEnd); return cloneElement(children, { ...(children as React.ReactElement).props, onLoadEnd: mergeOnLoadEnd, applicationNameForUserAgent: webViewApplicationNameForUserAgent, }); } }; const inject = (event: any) => { nativeTag.current = event.nativeEvent.target; if (nativeTag.current && nativeTag.current !== injectedWebViewTag.current) { registerWebView(nativeTag.current); injectedWebViewTag.current = nativeTag.current; } }; return {renderChildWebView()}; };