diff --git a/packages/react-native-sandbox/android/src/main/java/io/callstack/rnsandbox/SandboxReactNativeView.kt b/packages/react-native-sandbox/android/src/main/java/io/callstack/rnsandbox/SandboxReactNativeView.kt index 3729790..22fb640 100644 --- a/packages/react-native-sandbox/android/src/main/java/io/callstack/rnsandbox/SandboxReactNativeView.kt +++ b/packages/react-native-sandbox/android/src/main/java/io/callstack/rnsandbox/SandboxReactNativeView.kt @@ -78,7 +78,21 @@ class SandboxReactNativeView( val w = right - left val h = bottom - top for (i in 0 until childCount) { - getChildAt(i).layout(0, 0, w, h) + val child = getChildAt(i) + // The child is a ReactSurfaceView from a SEPARATE ReactHost. Fabric + // lays our view out by calling layout() directly, without a measure + // pass, so the child never receives onMeasure(). But ReactSurfaceView + // only pushes layout constraints to its surface from onMeasure() (and + // its onLayout() is a no-op until wasMeasured is true). Without an + // explicit measure the nested surface keeps its initial constructor + // constraints and renders blank (regression surfaced on RN 0.85). + // Measure with EXACTLY specs so updateLayoutSpecs() runs with our real + // size, then lay the child out to fill us. + child.measure( + MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY), + ) + child.layout(0, 0, w, h) } } diff --git a/packages/react-native-sandbox/src/index.tsx b/packages/react-native-sandbox/src/index.tsx index c01386e..c3760b4 100644 --- a/packages/react-native-sandbox/src/index.tsx +++ b/packages/react-native-sandbox/src/index.tsx @@ -7,7 +7,7 @@ import { useRef, } from 'react' import type {NativeSyntheticEvent} from 'react-native' -import {StyleProp, StyleSheet, View, ViewProps, ViewStyle} from 'react-native' +import {StyleProp, View, ViewProps, ViewStyle} from 'react-native' import type {NativeSandboxReactNativeViewComponentType} from '../specs/NativeSandboxReactNativeView' import NativeSandboxReactNativeView, { @@ -305,9 +305,14 @@ const SandboxReactNativeView = forwardRef< return null }, []) + // The native sandbox view fills the user-styled wrapper as an in-flow + // flex child. It used to be position:absolute (StyleSheet.absoluteFillObject), + // but on RN 0.85 an absolutely-positioned child with all-zero insets no longer + // stretches to a flex-sized parent — it collapses to height 0 and the embedded + // surface renders blank. flex:1 makes it claim the wrapper's space reliably. const _style: StyleProp = useMemo( () => ({ - ...StyleSheet.absoluteFillObject, + flex: 1, }), [] )