Skip to content

Commit

Permalink
Bring ReactFabricHostComponent back to react-native
Browse files Browse the repository at this point in the history
Summary:
I'm doing some preparations to implement this proposal to bring some DOM APIs to React Native refs: react-native-community/discussions-and-proposals#607

To make it easier to iterate on the proposal, and to improve the separation of concerns between React and React Native, I'm moving the definition of `ReactFabricHostComponent` (the public instance provided by React when using refs on host conmponents) to the `react-native` package.

I already did some steps in the React repository to simplify this:
* Removing unused imperative events that caused increased coupling: facebook/react#26282
* Extracting the definition of the public instance to a separate module: facebook/react#26291

In this case, in order to be able to move the definition from React to React Native, we need to:
1. Create the definition in React Native and export it through `ReactNativePrivateInterface`.
2. Update React to use that definition instead of the one in its own module.

This diff implements the first step.

`ReactNativeAttributePayload` is required by this definition and by the one for Paper that still exists in React. I moved it here so we only define it where we use it when we remove Paper. Paper will access it through `ReactNativePrivateInterface` as well. That will also allow us to remove a few other fields in that interface.

Changelog: [Internal]

Reviewed By: yungsters

Differential Revision: D43772356

fbshipit-source-id: 0540fb9c665a9daa4d978926e0d01081f8541ffe
  • Loading branch information
rubennorte authored and facebook-github-bot committed Mar 22, 2023
1 parent 7410746 commit 826d0f8
Show file tree
Hide file tree
Showing 7 changed files with 1,127 additions and 8 deletions.
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ module.exports = {
testPathIgnorePatterns: [
'/node_modules/',
'<rootDir>/packages/react-native/template',
'<rootDir>/packages/react-native/Libraries/Renderer',
'<rootDir>/packages/react-native/Libraries/Renderer/implementations',
'<rootDir>/packages/react-native/Libraries/Renderer/shims',
'<rootDir>/packages/rn-tester/e2e',
],
transformIgnorePatterns: ['node_modules/(?!@react-native/)'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ import type {
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
Node,
} from '../Renderer/shims/ReactNativeTypes';
import type {RootTag} from '../Types/RootTagTypes';

// TODO: type these properly.
export opaque type Node = {...};
type NodeSet = Array<Node>;
type NodeProps = {...};
type InstanceHandle = {...};
export type NodeSet = Array<Node>;
export type NodeProps = {...};
export type InstanceHandle = {...};
export type Spec = {|
+createNode: (
reactTag: number,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/

import type {
LayoutAnimationConfig,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
Node,
} from '../../Renderer/shims/ReactNativeTypes';
import type {RootTag} from '../../Types/RootTagTypes';
import type {
InstanceHandle,
NodeProps,
NodeSet,
Spec as FabricUIManager,
} from '../FabricUIManager';

type NodeMock = {
reactTag: number,
rootTag: RootTag,
props: NodeProps,
instanceHandle: InstanceHandle,
children: NodeSet,
};

function fromNode(node: Node): NodeMock {
// $FlowExpectedError[incompatible-return]
return node;
}

function toNode(node: NodeMock): Node {
// $FlowExpectedError[incompatible-return]
return node;
}

const FabricUIManagerMock: FabricUIManager = {
createNode: jest.fn(
(
reactTag: number,
viewName: string,
rootTag: RootTag,
props: NodeProps,
instanceHandle: InstanceHandle,
): Node => {
return toNode({
reactTag,
rootTag,
props,
instanceHandle,
children: [],
});
},
),
cloneNode: jest.fn((node: Node): Node => {
return toNode({...fromNode(node)});
}),
cloneNodeWithNewChildren: jest.fn((node: Node): Node => {
return toNode({...fromNode(node), children: []});
}),
cloneNodeWithNewProps: jest.fn((node: Node, newProps: NodeProps): Node => {
return toNode({...fromNode(node), props: newProps});
}),
cloneNodeWithNewChildrenAndProps: jest.fn(
(node: Node, newProps: NodeProps): Node => {
return toNode({...fromNode(node), children: [], props: newProps});
},
),
createChildSet: jest.fn((rootTag: RootTag): NodeSet => {
return [];
}),
appendChild: jest.fn((parentNode: Node, child: Node): Node => {
return toNode({
...fromNode(parentNode),
children: fromNode(parentNode).children.concat(child),
});
}),
appendChildToSet: jest.fn((childSet: NodeSet, child: Node): void => {
childSet.push(child);
}),
completeRoot: jest.fn((rootTag: RootTag, childSet: NodeSet): void => {}),
measure: jest.fn((node: Node, callback: MeasureOnSuccessCallback): void => {
callback(10, 10, 100, 100, 0, 0);
}),
measureInWindow: jest.fn(
(node: Node, callback: MeasureInWindowOnSuccessCallback): void => {
callback(10, 10, 100, 100);
},
),
measureLayout: jest.fn(
(
node: Node,
relativeNode: Node,
onFail: () => void,
onSuccess: MeasureLayoutOnSuccessCallback,
): void => {
onSuccess(1, 1, 100, 100);
},
),
configureNextLayoutAnimation: jest.fn(
(
config: LayoutAnimationConfig,
callback: () => void, // check what is returned here
errorCallback: () => void,
): void => {},
),
sendAccessibilityEvent: jest.fn((node: Node, eventType: string): void => {}),
findShadowNodeByTag_DEPRECATED: jest.fn((reactTag: number): ?Node => {}),
getBoundingClientRect: jest.fn(
(
node: Node,
): [
/* x:*/ number,
/* y:*/ number,
/* width:*/ number,
/* height:*/ number,
] => {
return [1, 1, 100, 100];
},
),
setNativeProps: jest.fn((node: Node, newProps: NodeProps): void => {}),
dispatchCommand: jest.fn(
(node: Node, commandName: string, args: Array<mixed>): void => {},
),
};

global.nativeFabricUIManager = FabricUIManagerMock;

export function getFabricUIManager(): ?FabricUIManager {
return FabricUIManagerMock;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@ import typeof ReactFiberErrorDialog from '../Core/ReactFiberErrorDialog';
import typeof RCTEventEmitter from '../EventEmitter/RCTEventEmitter';
import typeof CustomEvent from '../Events/CustomEvent';
import typeof UIManager from '../ReactNative/UIManager';
import typeof {
createPublicInstance,
getNativeTagFromPublicInstance,
getNodeFromPublicInstance,
} from '../Renderer/public/ReactFabricPublicInstance';
import typeof {
create as createAttributePayload,
diff as diffAttributePayloads,
} from '../Renderer/public/ReactNativeAttributePayload';
import typeof ReactNativeViewConfigRegistry from '../Renderer/shims/ReactNativeViewConfigRegistry';
import typeof flattenStyle from '../StyleSheet/flattenStyle';
import type {DangerouslyImpreciseStyleProp} from '../StyleSheet/StyleSheet';
import typeof deepFreezeAndThrowOnMutationInDev from '../Utilities/deepFreezeAndThrowOnMutationInDev';
import typeof deepDiffer from '../Utilities/differ/deepDiffer';
import typeof Platform from '../Utilities/Platform';

import {type DangerouslyImpreciseStyleProp} from '../StyleSheet/StyleSheet';

// flowlint unsafe-getters-setters:off
module.exports = {
get BatchedBridge(): BatchedBridge {
Expand All @@ -48,6 +56,7 @@ module.exports = {
get UIManager(): UIManager {
return require('../ReactNative/UIManager');
},
// TODO: Remove when React has migrated to `createAttributePayload` and `diffAttributePayloads`
get deepDiffer(): deepDiffer {
return require('../Utilities/differ/deepDiffer');
},
Expand All @@ -56,6 +65,7 @@ module.exports = {
> {
return require('../Utilities/deepFreezeAndThrowOnMutationInDev');
},
// TODO: Remove when React has migrated to `createAttributePayload` and `diffAttributePayloads`
get flattenStyle(): flattenStyle<DangerouslyImpreciseStyleProp> {
// $FlowFixMe[underconstrained-implicit-instantiation]
return require('../StyleSheet/flattenStyle');
Expand All @@ -72,4 +82,22 @@ module.exports = {
get CustomEvent(): CustomEvent {
return require('../Events/CustomEvent').default;
},
get createAttributePayload(): createAttributePayload {
return require('../Renderer/public/ReactNativeAttributePayload').create;
},
get diffAttributePayloads(): diffAttributePayloads {
return require('../Renderer/public/ReactNativeAttributePayload').diff;
},
get createPublicInstance(): createPublicInstance {
return require('../Renderer/public/ReactFabricPublicInstance')
.createPublicInstance;
},
get getNativeTagFromPublicInstance(): getNativeTagFromPublicInstance {
return require('../Renderer/public/ReactFabricPublicInstance')
.getNativeTagFromPublicInstance;
},
get getNodeFromPublicInstance(): getNodeFromPublicInstance {
return require('../Renderer/public/ReactFabricPublicInstance')
.getNodeFromPublicInstance;
},
};
Loading

0 comments on commit 826d0f8

Please sign in to comment.