From dbdd4da14f9baf5f533e1e0ae9b98fa0c644ec14 Mon Sep 17 00:00:00 2001 From: Andrew Coates <30809111+acoates-ms@users.noreply.github.com> Date: Fri, 7 Jun 2024 03:19:43 -0700 Subject: [PATCH] Add ability to override the ViewStyle of the root View component (#44665) Summary: In order to host a ReactNative surface whose size is controlled by the RN content rather than the size of the surface, we need the ability to remove the flex:1 style on the root View component. `SurfaceHandler` has layout functions which take a `LayoutConstraint` (so min/max size). The root View component in `AppContainer` has a hardcoded `flex:1` style. This view is above the `WrapperComponent`, which we can currently override. But I dont see anyway to avoid the root View having that flex style. This flex style means that the rootview will always be the maxheight passed into the layout functions on `SurfaceHandler`. Which prevents allowing RN surfaces that can size themselves based on their content. This change adds a `setRootViewStyleProvider` method to `AppRegistry`, which works similar to `setWrapperComponentProvider` but allows apps to override the style property on the root View component. In particular, this allows apps to remove the flex:1 style, which is required to enable react surfaces which are sized based on their contents. ## Changelog: Pick one each for the category and type tags: [GENERAL] [ADDED] - Added AppRegistry.setRootViewStyleProvider Pull Request resolved: https://github.com/facebook/react-native/pull/44665 Test Plan: Will be including this change into react-native-windows to enable scenarios with content sized surfaces within Microsoft Office to work with the new architecture. Would like signoff on this direction before I go and integrate it there. Reviewed By: javache Differential Revision: D58138443 Pulled By: hoxyq fbshipit-source-id: 95ab4842aa7f827867788d8787527f9675cf4fcc --- .../Libraries/ReactNative/AppContainer-dev.js | 5 +++-- .../Libraries/ReactNative/AppContainer-prod.js | 3 ++- .../react-native/Libraries/ReactNative/AppContainer.js | 2 ++ .../react-native/Libraries/ReactNative/AppRegistry.d.ts | 7 +++++++ .../react-native/Libraries/ReactNative/AppRegistry.js | 8 ++++++++ .../Libraries/ReactNative/renderApplication.js | 3 +++ .../__tests__/__snapshots__/public-api-test.js.snap | 4 ++++ 7 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/react-native/Libraries/ReactNative/AppContainer-dev.js b/packages/react-native/Libraries/ReactNative/AppContainer-dev.js index cba0ccb2395dce..fe71b3c04d3dca 100644 --- a/packages/react-native/Libraries/ReactNative/AppContainer-dev.js +++ b/packages/react-native/Libraries/ReactNative/AppContainer-dev.js @@ -92,6 +92,7 @@ const AppContainer = ({ rootTag, showArchitectureIndicator, WrapperComponent, + rootViewStyle, }: Props): React.Node => { const appContainerRootViewRef: AppContainerRootViewRef = React.useRef(null); const innerViewRef: InspectedViewRef = React.useRef(null); @@ -141,7 +142,7 @@ const AppContainer = ({ collapsable={reactDevToolsAgent == null && !shouldRenderInspector} pointerEvents="box-none" key={key} - style={styles.container} + style={rootViewStyle || styles.container} ref={innerViewRef}> {children} @@ -167,7 +168,7 @@ const AppContainer = ({ {innerView} diff --git a/packages/react-native/Libraries/ReactNative/AppContainer-prod.js b/packages/react-native/Libraries/ReactNative/AppContainer-prod.js index 201d54562b91a8..0f091d5669c922 100644 --- a/packages/react-native/Libraries/ReactNative/AppContainer-prod.js +++ b/packages/react-native/Libraries/ReactNative/AppContainer-prod.js @@ -23,6 +23,7 @@ const AppContainer = ({ rootTag, showArchitectureIndicator, WrapperComponent, + rootViewStyle, }: Props): React.Node => { let innerView = children; @@ -39,7 +40,7 @@ const AppContainer = ({ return ( - + {innerView} diff --git a/packages/react-native/Libraries/ReactNative/AppContainer.js b/packages/react-native/Libraries/ReactNative/AppContainer.js index b27db96888b5b8..3463d14dcf2f6d 100644 --- a/packages/react-native/Libraries/ReactNative/AppContainer.js +++ b/packages/react-native/Libraries/ReactNative/AppContainer.js @@ -8,6 +8,7 @@ * @flow */ +import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type {RootTag} from './RootTag'; import * as React from 'react'; @@ -19,6 +20,7 @@ export type Props = $ReadOnly<{| initialProps?: {...}, showArchitectureIndicator?: boolean, WrapperComponent?: ?React.ComponentType, + rootViewStyle?: ?ViewStyleProp, internal_excludeLogBox?: boolean, internal_excludeInspector?: boolean, |}>; diff --git a/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts b/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts index b75715c6abc8ea..f345ee7dd9f7d7 100644 --- a/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts +++ b/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts @@ -9,6 +9,7 @@ import type * as React from 'react'; import type {IPerformanceLogger} from '../Utilities/IPerformanceLogger'; +import type {ViewStyle} from '../StyleSheet/StyleSheetTypes'; type Task = (taskData: any) => Promise; type TaskProvider = () => Task; @@ -34,6 +35,8 @@ export type WrapperComponentProvider = ( appParameters: any, ) => React.ComponentType; +export type RootViewStyleProvider = (appParameters: any) => ViewStyle; + /** * `AppRegistry` is the JS entry point to running all React Native apps. App * root components should register themselves with @@ -54,6 +57,10 @@ export namespace AppRegistry { provider: WrapperComponentProvider, ): void; + export function setRootViewStyleProvider( + provider: RootViewStyleProvider, + ): void; + export function registerConfig(config: AppConfig[]): void; export function registerComponent( diff --git a/packages/react-native/Libraries/ReactNative/AppRegistry.js b/packages/react-native/Libraries/ReactNative/AppRegistry.js index a4b5b732f5f121..68bd3895571778 100644 --- a/packages/react-native/Libraries/ReactNative/AppRegistry.js +++ b/packages/react-native/Libraries/ReactNative/AppRegistry.js @@ -8,6 +8,7 @@ * @format */ +import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type {RootTag} from '../Types/RootTagTypes'; import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; import type {DisplayModeType} from './DisplayMode'; @@ -60,6 +61,7 @@ export type Registry = { export type WrapperComponentProvider = ( appParameters: Object, ) => React$ComponentType; +export type RootViewStyleProvider = (appParameters: Object) => ViewStyleProp; const runnables: Runnables = {}; let runCount = 1; @@ -70,6 +72,7 @@ let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook = (component: ComponentProvider) => component(); let wrapperComponentProvider: ?WrapperComponentProvider; +let rootViewStyleProvider: ?RootViewStyleProvider; let showArchitectureIndicator = false; /** @@ -82,6 +85,10 @@ const AppRegistry = { wrapperComponentProvider = provider; }, + setRootViewStyleProvider(provider: RootViewStyleProvider) { + rootViewStyleProvider = provider; + }, + enableArchitectureIndicator(enabled: boolean): void { showArchitectureIndicator = enabled; }, @@ -130,6 +137,7 @@ const AppRegistry = { appParameters.initialProps, appParameters.rootTag, wrapperComponentProvider && wrapperComponentProvider(appParameters), + rootViewStyleProvider && rootViewStyleProvider(appParameters), appParameters.fabric, showArchitectureIndicator, scopedPerformanceLogger, diff --git a/packages/react-native/Libraries/ReactNative/renderApplication.js b/packages/react-native/Libraries/ReactNative/renderApplication.js index c6ca67f40144b9..701db565ffe80c 100644 --- a/packages/react-native/Libraries/ReactNative/renderApplication.js +++ b/packages/react-native/Libraries/ReactNative/renderApplication.js @@ -8,6 +8,7 @@ * @flow */ +import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; import GlobalPerformanceLogger from '../Utilities/GlobalPerformanceLogger'; @@ -32,6 +33,7 @@ export default function renderApplication( initialProps: Props, rootTag: any, WrapperComponent?: ?React.ComponentType, + rootViewStyle?: ?ViewStyleProp, fabric?: boolean, showArchitectureIndicator?: boolean, scopedPerformanceLogger?: IPerformanceLogger, @@ -52,6 +54,7 @@ export default function renderApplication( fabric={fabric} showArchitectureIndicator={showArchitectureIndicator} WrapperComponent={WrapperComponent} + rootViewStyle={rootViewStyle} initialProps={initialProps ?? Object.freeze({})} internal_excludeLogBox={isLogBox}> diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index d6222d194daa63..e083609f06e083 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -6508,6 +6508,7 @@ exports[`public API should not change unintentionally Libraries/ReactNative/AppC initialProps?: { ... }, showArchitectureIndicator?: boolean, WrapperComponent?: ?React.ComponentType, + rootViewStyle?: ?ViewStyleProp, internal_excludeLogBox?: boolean, internal_excludeInspector?: boolean, |}>; @@ -6573,8 +6574,10 @@ export type Registry = { export type WrapperComponentProvider = ( appParameters: Object ) => React$ComponentType; +export type RootViewStyleProvider = (appParameters: Object) => ViewStyleProp; declare const AppRegistry: { setWrapperComponentProvider(provider: WrapperComponentProvider): void, + setRootViewStyleProvider(provider: RootViewStyleProvider): void, enableArchitectureIndicator(enabled: boolean): void, registerConfig(config: Array): void, registerComponent( @@ -6913,6 +6916,7 @@ exports[`public API should not change unintentionally Libraries/ReactNative/rend initialProps: Props, rootTag: any, WrapperComponent?: ?React.ComponentType, + rootViewStyle?: ?ViewStyleProp, fabric?: boolean, showArchitectureIndicator?: boolean, scopedPerformanceLogger?: IPerformanceLogger,