diff --git a/packages/react-native-renderer/src/NativeMethodsMixinUtils.js b/packages/react-native-renderer/src/NativeMethodsMixinUtils.js index b9dc7d4394..bda6b263e3 100644 --- a/packages/react-native-renderer/src/NativeMethodsMixinUtils.js +++ b/packages/react-native-renderer/src/NativeMethodsMixinUtils.js @@ -45,26 +45,6 @@ export function mountSafeCallback_NOT_REALLY_SAFE( }; } -export function throwOnStylesProp(component: any, props: any) { - if (props.styles !== undefined) { - const owner = component._owner || null; - const name = component.constructor.displayName; - let msg = - '`styles` is not a supported property of `' + - name + - '`, did ' + - 'you mean `style` (singular)?'; - if (owner && owner.constructor && owner.constructor.displayName) { - msg += - '\n\nCheck the `' + - owner.constructor.displayName + - '` parent ' + - ' component.'; - } - throw new Error(msg); - } -} - export function warnForStyleProps(props: any, validAttributes: any) { if (__DEV__) { for (const key in validAttributes.style) { diff --git a/packages/react-native-renderer/src/ReactFabric.js b/packages/react-native-renderer/src/ReactFabric.js index 78c1d75412..84d5651f83 100644 --- a/packages/react-native-renderer/src/ReactFabric.js +++ b/packages/react-native-renderer/src/ReactFabric.js @@ -122,6 +122,7 @@ export { }; injectIntoDevTools({ + // $FlowExpectedError[incompatible-call] The type of `Instance` in `getClosestInstanceFromNode` does not match in Fabric and the legacy renderer, so it fails to typecheck here. findFiberByHostInstance: getClosestInstanceFromNode, bundleType: __DEV__ ? 1 : 0, version: ReactVersion, diff --git a/packages/react-native-renderer/src/ReactFabricComponentTree.js b/packages/react-native-renderer/src/ReactFabricComponentTree.js index 7db7505bee..4cdb1ca815 100644 --- a/packages/react-native-renderer/src/ReactFabricComponentTree.js +++ b/packages/react-native-renderer/src/ReactFabricComponentTree.js @@ -3,28 +3,44 @@ * * 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 */ -function getInstanceFromInstance(instanceHandle) { - return instanceHandle; +import type { + PublicInstance, + Instance, + Props, + TextInstance, +} from './ReactFabricHostConfig'; +import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; +import {getPublicInstance} from './ReactFabricHostConfig'; + +// `node` is typed incorrectly here. The proper type should be `PublicInstance`. +// This is ok in DOM because they types are interchangeable, but in React Native +// they aren't. +function getInstanceFromNode(node: Instance | TextInstance): Fiber | null { + // $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native. + return node; } -function getTagFromInstance(inst) { - const nativeInstance = inst.stateNode.canonical; +function getNodeFromInstance(fiber: Fiber): PublicInstance { + const publicInstance = getPublicInstance(fiber.stateNode); - if (!nativeInstance._nativeTag) { - throw new Error('All native instances should have a tag.'); + if (publicInstance == null) { + throw new Error('Could not find host instance from fiber'); } - return nativeInstance; + return publicInstance; +} + +function getFiberCurrentPropsFromNode(instance: Instance): Props { + return instance.canonical.currentProps; } export { - getInstanceFromInstance as getClosestInstanceFromNode, - getInstanceFromInstance as getInstanceFromNode, - getTagFromInstance as getNodeFromInstance, + getInstanceFromNode, + getInstanceFromNode as getClosestInstanceFromNode, + getNodeFromInstance, + getFiberCurrentPropsFromNode, }; - -export function getFiberCurrentPropsFromNode(inst) { - return inst.canonical.currentProps; -} diff --git a/packages/react-native-renderer/src/ReactFabricEventEmitter.js b/packages/react-native-renderer/src/ReactFabricEventEmitter.js index b4a4694045..b7d545aa11 100644 --- a/packages/react-native-renderer/src/ReactFabricEventEmitter.js +++ b/packages/react-native-renderer/src/ReactFabricEventEmitter.js @@ -29,6 +29,7 @@ import getListener from './ReactNativeGetListener'; import {runEventsInBatch} from './legacy-events/EventBatching'; import {RawEventEmitter} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; +import {getPublicInstance} from './ReactFabricHostConfig'; export {getListener, registrationNameModules as registrationNames}; @@ -92,7 +93,8 @@ export function dispatchEvent( const stateNode = targetFiber.stateNode; // Guard against Fiber being unmounted if (stateNode != null) { - eventTarget = stateNode.canonical; + // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet. + eventTarget = (getPublicInstance(stateNode): EventTarget); } } diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 30982a7ad0..09cb55a572 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -18,10 +18,7 @@ import type { TouchedViewDataAtPoint, } from './ReactNativeTypes'; -import { - mountSafeCallback_NOT_REALLY_SAFE, - warnForStyleProps, -} from './NativeMethodsMixinUtils'; +import {warnForStyleProps} from './NativeMethodsMixinUtils'; import {create, diff} from './ReactNativeAttributePayload'; import {dispatchEvent} from './ReactFabricEventEmitter'; @@ -107,6 +104,8 @@ if (registerEventHandler) { registerEventHandler(dispatchEvent); } +const noop = () => {}; + /** * This is used for refs on host components. */ @@ -137,22 +136,20 @@ class ReactFabricHostComponent implements NativeMethods { } measure(callback: MeasureOnSuccessCallback) { - const {stateNode} = this._internalInstanceHandle; - if (stateNode != null) { - fabricMeasure( - stateNode.node, - mountSafeCallback_NOT_REALLY_SAFE(this, callback), - ); + const node = getShadowNodeFromInternalInstanceHandle( + this._internalInstanceHandle, + ); + if (node != null) { + fabricMeasure(node, callback); } } measureInWindow(callback: MeasureInWindowOnSuccessCallback) { - const {stateNode} = this._internalInstanceHandle; - if (stateNode != null) { - fabricMeasureInWindow( - stateNode.node, - mountSafeCallback_NOT_REALLY_SAFE(this, callback), - ); + const node = getShadowNodeFromInternalInstanceHandle( + this._internalInstanceHandle, + ); + if (node != null) { + fabricMeasureInWindow(node, callback); } } @@ -174,24 +171,29 @@ class ReactFabricHostComponent implements NativeMethods { return; } - const toStateNode = this._internalInstanceHandle.stateNode; - const fromStateNode = - relativeToNativeNode._internalInstanceHandle.stateNode; + const toStateNode = getShadowNodeFromInternalInstanceHandle( + this._internalInstanceHandle, + ); + const fromStateNode = getShadowNodeFromInternalInstanceHandle( + relativeToNativeNode._internalInstanceHandle, + ); if (toStateNode != null && fromStateNode != null) { fabricMeasureLayout( - toStateNode.node, - fromStateNode.node, - mountSafeCallback_NOT_REALLY_SAFE(this, onFail), - mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess), + toStateNode, + fromStateNode, + onFail != null ? onFail : noop, + onSuccess != null ? onSuccess : noop, ); } } unstable_getBoundingClientRect(): DOMRect { - const {stateNode} = this._internalInstanceHandle; - if (stateNode != null) { - const rect = fabricGetBoundingClientRect(stateNode.node); + const node = getShadowNodeFromInternalInstanceHandle( + this._internalInstanceHandle, + ); + if (node != null) { + const rect = fabricGetBoundingClientRect(node); if (rect) { return new DOMRect(rect[0], rect[1], rect[2], rect[3]); @@ -208,13 +210,31 @@ class ReactFabricHostComponent implements NativeMethods { } const updatePayload = create(nativeProps, this.viewConfig.validAttributes); - const {stateNode} = this._internalInstanceHandle; - if (stateNode != null && updatePayload != null) { - setNativeProps(stateNode.node, updatePayload); + const node = getShadowNodeFromInternalInstanceHandle( + this._internalInstanceHandle, + ); + if (node != null && updatePayload != null) { + setNativeProps(node, updatePayload); } } } +type ParamOf = $Call<((arg: T) => mixed) => T, Fn>; +type ShadowNode = ParamOf<(typeof nativeFabricUIManager)['measure']>; + +export function getShadowNodeFromInternalInstanceHandle( + internalInstanceHandle: mixed, +): ?ShadowNode { + return ( + // $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here. + internalInstanceHandle && + // $FlowExpectedError[incompatible-return] + internalInstanceHandle.stateNode && + // $FlowExpectedError[incompatible-use] + internalInstanceHandle.stateNode.node + ); +} + export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation'; export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration'; export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes'; diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index a6dc47b066..db69a469c5 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -218,18 +218,6 @@ export type ReactFabricType = { ... }; -export type ReactNativeEventTarget = { - node: {...}, - canonical: { - _nativeTag: number, - viewConfig: ViewConfig, - currentProps: {...}, - _internalInstanceHandle: {...}, - ... - }, - ... -}; - export type ReactFabricEventTouch = { identifier: number, locationX: number,