From 444c11f032ae46c94442270ce0238aba23c67235 Mon Sep 17 00:00:00 2001 From: jhnstn Date: Wed, 5 Apr 2023 13:25:22 -0400 Subject: [PATCH 1/5] Add ref forwarding --- .../components/src/sandbox/index.native.js | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/components/src/sandbox/index.native.js b/packages/components/src/sandbox/index.native.js index 12125c31edf67b..f4518319777e2f 100644 --- a/packages/components/src/sandbox/index.native.js +++ b/packages/components/src/sandbox/index.native.js @@ -14,6 +14,7 @@ import { useRef, useState, useEffect, + forwardRef, } from '@wordpress/element'; import { usePreferredColorScheme } from '@wordpress/compose'; @@ -171,20 +172,22 @@ const style = ` const EMPTY_ARRAY = []; -function Sandbox( { - containerStyle, - customJS, - html = '', - lang = 'en', - providerUrl = '', - scripts = EMPTY_ARRAY, - styles = EMPTY_ARRAY, - title = '', - type, - url, -} ) { +const Sandbox = forwardRef( function Sandbox( + { + containerStyle, + customJS, + html = '', + lang = 'en', + providerUrl = '', + scripts = EMPTY_ARRAY, + styles = EMPTY_ARRAY, + title = '', + type, + url, + }, + ref +) { const colorScheme = usePreferredColorScheme(); - const ref = useRef(); const [ height, setHeight ] = useState( 0 ); const [ contentHtml, setContentHtml ] = useState( getHtmlDoc() ); @@ -333,7 +336,7 @@ function Sandbox( { showsVerticalScrollIndicator={ false } /> ); -} +} ); const workaroundStyles = StyleSheet.create( { webView: { From 5b99cbfb511e08b9ced6dd190f9ed8d6e04a1522 Mon Sep 17 00:00:00 2001 From: jhnstn Date: Wed, 5 Apr 2023 17:53:06 -0400 Subject: [PATCH 2/5] Fix typo --- packages/components/src/sandbox/index.native.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/sandbox/index.native.js b/packages/components/src/sandbox/index.native.js index f4518319777e2f..6ec04daa73e332 100644 --- a/packages/components/src/sandbox/index.native.js +++ b/packages/components/src/sandbox/index.native.js @@ -99,7 +99,6 @@ const observeAndResizeJS = ` // get an DOM mutations for that, so do the resize when the window is resized, too. window.addEventListener( 'resize', sendResize, true ); window.addEventListener( 'orientationchange', sendResize, true ); - widow.addEventListener( 'click', sendResize, true ); })(); `; From 13b2621a107a5ba259c975ffa4afb98482ce5b92 Mon Sep 17 00:00:00 2001 From: jhnstn Date: Thu, 6 Apr 2023 17:34:42 -0400 Subject: [PATCH 3/5] Enable non touch play events --- packages/components/src/sandbox/index.native.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/sandbox/index.native.js b/packages/components/src/sandbox/index.native.js index 6ec04daa73e332..e6ce87c44b4e76 100644 --- a/packages/components/src/sandbox/index.native.js +++ b/packages/components/src/sandbox/index.native.js @@ -333,6 +333,7 @@ const Sandbox = forwardRef( function Sandbox( setBuiltInZoomControls={ false } showsHorizontalScrollIndicator={ false } showsVerticalScrollIndicator={ false } + mediaPlaybackRequiresUserAction={ false } /> ); } ); From 9b389dbd4b9dc2c35dfc2cc9988bd24d66aeab3f Mon Sep 17 00:00:00 2001 From: jhnstn Date: Thu, 6 Apr 2023 17:38:59 -0400 Subject: [PATCH 4/5] Allow parent to register window event listeners --- .../components/src/sandbox/index.native.js | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/packages/components/src/sandbox/index.native.js b/packages/components/src/sandbox/index.native.js index e6ce87c44b4e76..9338cc096fba17 100644 --- a/packages/components/src/sandbox/index.native.js +++ b/packages/components/src/sandbox/index.native.js @@ -15,6 +15,7 @@ import { useState, useEffect, forwardRef, + useCallback, } from '@wordpress/element'; import { usePreferredColorScheme } from '@wordpress/compose'; @@ -183,6 +184,7 @@ const Sandbox = forwardRef( function Sandbox( title = '', type, url, + onWindowEvents = {}, }, ref ) { @@ -241,6 +243,21 @@ const Sandbox = forwardRef( function Sandbox( return '' + renderToString( htmlDoc ); } + const getInjectedJavaScript = useCallback( () => { + // Allow parent to override the resize observers with prop.customJS (legacy support) + let injectedJS = customJS || observeAndResizeJS; + + // Add any event listeners that were passed in. + Object.keys( onWindowEvents ).forEach( ( eventType ) => { + injectedJS += ` + window.addEventListener( '${ eventType }', function( event ) { + window.ReactNativeWebView.postMessage( JSON.stringify( { type: '${ eventType }', ...event.data } ) ); + });`; + } ); + + return injectedJS; + }, [ customJS, onWindowEvents ] ); + function updateContentHtml( forceRerender = false ) { const newContentHtml = getHtmlDoc(); @@ -255,25 +272,6 @@ const Sandbox = forwardRef( function Sandbox( } } - function checkMessageForResize( event ) { - // Attempt to parse the message data as JSON if passed as string. - let data = event.nativeEvent.data || {}; - - if ( 'string' === typeof data ) { - try { - data = JSON.parse( data ); - } catch ( e ) {} - } - - // Update the state only if the message is formatted as we expect, - // i.e. as an object with a 'resize' action. - if ( 'resize' !== data.action ) { - return; - } - - setHeight( data.height ); - } - function getSizeStyle() { const contentHeight = Math.ceil( height ); @@ -284,6 +282,31 @@ const Sandbox = forwardRef( function Sandbox( setIsLandscape( dimensions.window.width >= dimensions.window.height ); } + const onMessage = useCallback( + ( message ) => { + let data = message?.nativeEvent?.data; + + try { + data = JSON.parse( data ); + } catch ( e ) { + return; + } + + // check for resize event + if ( 'resize' === data?.action ) { + setHeight( data.height ); + } + + // Forward the event to parent event listeners + Object.keys( onWindowEvents ).forEach( ( eventType ) => { + if ( data?.type === eventType ) { + onWindowEvents[ eventType ]( data ); + } + } ); + }, + [ onWindowEvents ] + ); + useEffect( () => { const dimensionsChangeSubscription = Dimensions.addEventListener( 'change', @@ -316,7 +339,7 @@ const Sandbox = forwardRef( function Sandbox( sandboxStyles[ 'sandbox-webview__container' ], containerStyle, ] } - injectedJavaScript={ customJS || observeAndResizeJS } + injectedJavaScript={ getInjectedJavaScript() } key={ key } ref={ ref } source={ { baseUrl: providerUrl, html: contentHtml } } @@ -328,7 +351,7 @@ const Sandbox = forwardRef( function Sandbox( getSizeStyle(), Platform.isAndroid && workaroundStyles.webView, ] } - onMessage={ checkMessageForResize } + onMessage={ onMessage } scrollEnabled={ false } setBuiltInZoomControls={ false } showsHorizontalScrollIndicator={ false } From 43ef2da9cc7bbfbc73bdaa96bcf368e7769e9c91 Mon Sep 17 00:00:00 2001 From: jhnstn Date: Fri, 7 Apr 2023 12:28:12 -0400 Subject: [PATCH 5/5] Catch calling non-functions --- packages/components/src/sandbox/index.native.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/components/src/sandbox/index.native.js b/packages/components/src/sandbox/index.native.js index 9338cc096fba17..f374e07dec4e33 100644 --- a/packages/components/src/sandbox/index.native.js +++ b/packages/components/src/sandbox/index.native.js @@ -300,7 +300,15 @@ const Sandbox = forwardRef( function Sandbox( // Forward the event to parent event listeners Object.keys( onWindowEvents ).forEach( ( eventType ) => { if ( data?.type === eventType ) { - onWindowEvents[ eventType ]( data ); + try { + onWindowEvents[ eventType ]( data ); + } catch ( e ) { + // eslint-disable-next-line no-console + console.warn( + `Error handling event ${ eventType }`, + e + ); + } } } ); },