mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Extract ReactFabricHostComponent into a separate module
Summary: Small refactor in preparation for adding `ReactNativeElement` as an alternative implementation for `ReactFabricHostComponent`. Changelog: [internal] bypass-github-export-checks Reviewed By: yungsters Differential Revision: D44299619 fbshipit-source-id: b1bc43f6a6ae5b75dca43d7e08cd15acdc49bb79
This commit is contained in:
committed by
Facebook GitHub Bot
parent
4bff977869
commit
1476d99048
Vendored
+171
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import type {
|
||||
AttributeConfiguration,
|
||||
HostComponent,
|
||||
INativeMethods,
|
||||
MeasureInWindowOnSuccessCallback,
|
||||
MeasureLayoutOnSuccessCallback,
|
||||
MeasureOnSuccessCallback,
|
||||
ViewConfig,
|
||||
} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {ElementRef} from 'react';
|
||||
|
||||
import TextInputState from '../../Components/TextInput/TextInputState';
|
||||
import {getNodeFromInternalInstanceHandle} from '../../Renderer/shims/ReactFabric';
|
||||
import {getFabricUIManager} from '../FabricUIManager';
|
||||
import {create} from './ReactNativeAttributePayload';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
const {
|
||||
measure: fabricMeasure,
|
||||
measureInWindow: fabricMeasureInWindow,
|
||||
measureLayout: fabricMeasureLayout,
|
||||
getBoundingClientRect: fabricGetBoundingClientRect,
|
||||
setNativeProps,
|
||||
} = nullthrows(getFabricUIManager());
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
/**
|
||||
* This is used for refs on host components.
|
||||
*/
|
||||
export default class ReactFabricHostComponent implements INativeMethods {
|
||||
// These need to be accessible from `ReactFabricPublicInstanceUtils`.
|
||||
__nativeTag: number;
|
||||
__internalInstanceHandle: mixed;
|
||||
|
||||
_viewConfig: ViewConfig;
|
||||
|
||||
constructor(
|
||||
tag: number,
|
||||
viewConfig: ViewConfig,
|
||||
internalInstanceHandle: mixed,
|
||||
) {
|
||||
this.__nativeTag = tag;
|
||||
this._viewConfig = viewConfig;
|
||||
this.__internalInstanceHandle = internalInstanceHandle;
|
||||
}
|
||||
|
||||
blur() {
|
||||
// $FlowFixMe[incompatible-exact] Migrate all usages of `NativeMethods` to an interface to fix this.
|
||||
TextInputState.blurTextInput(this);
|
||||
}
|
||||
|
||||
focus() {
|
||||
// $FlowFixMe[incompatible-exact] Migrate all usages of `NativeMethods` to an interface to fix this.
|
||||
TextInputState.focusTextInput(this);
|
||||
}
|
||||
|
||||
measure(callback: MeasureOnSuccessCallback) {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
fabricMeasure(node, callback);
|
||||
}
|
||||
}
|
||||
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
fabricMeasureInWindow(node, callback);
|
||||
}
|
||||
}
|
||||
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void /* currently unused */,
|
||||
) {
|
||||
if (
|
||||
typeof relativeToNativeNode === 'number' ||
|
||||
!(relativeToNativeNode instanceof ReactFabricHostComponent)
|
||||
) {
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
'Warning: ref.measureLayout must be called with a ref to a native component.',
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const toStateNode = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
const fromStateNode = getNodeFromInternalInstanceHandle(
|
||||
relativeToNativeNode.__internalInstanceHandle,
|
||||
);
|
||||
|
||||
if (toStateNode != null && fromStateNode != null) {
|
||||
fabricMeasureLayout(
|
||||
toStateNode,
|
||||
fromStateNode,
|
||||
onFail != null ? onFail : noop,
|
||||
onSuccess != null ? onSuccess : noop,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unstable_getBoundingClientRect(): DOMRect {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
const rect = fabricGetBoundingClientRect(node);
|
||||
|
||||
if (rect) {
|
||||
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty rect if any of the above failed
|
||||
return new DOMRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
setNativeProps(nativeProps: {...}): void {
|
||||
if (__DEV__) {
|
||||
warnForStyleProps(nativeProps, this._viewConfig.validAttributes);
|
||||
}
|
||||
const updatePayload = create(nativeProps, this._viewConfig.validAttributes);
|
||||
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null && updatePayload != null) {
|
||||
setNativeProps(node, updatePayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function warnForStyleProps(
|
||||
props: {...},
|
||||
validAttributes: AttributeConfiguration,
|
||||
): void {
|
||||
if (__DEV__) {
|
||||
for (const key in validAttributes.style) {
|
||||
if (!(validAttributes[key] || props[key] === undefined)) {
|
||||
console.error(
|
||||
'You are setting the style `{ %s' +
|
||||
': ... }` as a prop. You ' +
|
||||
'should nest it in a style object. ' +
|
||||
'E.g. `{ style: { %s' +
|
||||
': ... } }`',
|
||||
key,
|
||||
key,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+23
-164
@@ -8,173 +8,23 @@
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import type {
|
||||
AttributeConfiguration,
|
||||
HostComponent,
|
||||
INativeMethods,
|
||||
MeasureInWindowOnSuccessCallback,
|
||||
MeasureLayoutOnSuccessCallback,
|
||||
MeasureOnSuccessCallback,
|
||||
ViewConfig,
|
||||
} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {ElementRef} from 'react';
|
||||
import typeof ReactFabricType from '../../Renderer/shims/ReactFabric';
|
||||
import type {ViewConfig} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type ReactFabricHostComponentType from './ReactFabricHostComponent';
|
||||
|
||||
import TextInputState from '../../Components/TextInput/TextInputState';
|
||||
import {getNodeFromInternalInstanceHandle} from '../../Renderer/shims/ReactFabric';
|
||||
import {getFabricUIManager} from '../FabricUIManager';
|
||||
import {create} from './ReactNativeAttributePayload';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
const {
|
||||
measure: fabricMeasure,
|
||||
measureInWindow: fabricMeasureInWindow,
|
||||
measureLayout: fabricMeasureLayout,
|
||||
getBoundingClientRect: fabricGetBoundingClientRect,
|
||||
setNativeProps,
|
||||
} = nullthrows(getFabricUIManager());
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
/**
|
||||
* This is used for refs on host components.
|
||||
*/
|
||||
export class ReactFabricHostComponent implements INativeMethods {
|
||||
// These need to be accessible from `ReactFabricPublicInstanceUtils`.
|
||||
__nativeTag: number;
|
||||
__internalInstanceHandle: mixed;
|
||||
|
||||
_viewConfig: ViewConfig;
|
||||
|
||||
constructor(
|
||||
tag: number,
|
||||
viewConfig: ViewConfig,
|
||||
internalInstanceHandle: mixed,
|
||||
) {
|
||||
this.__nativeTag = tag;
|
||||
this._viewConfig = viewConfig;
|
||||
this.__internalInstanceHandle = internalInstanceHandle;
|
||||
}
|
||||
|
||||
blur() {
|
||||
// $FlowFixMe[incompatible-exact] Migrate all usages of `NativeMethods` to an interface to fix this.
|
||||
TextInputState.blurTextInput(this);
|
||||
}
|
||||
|
||||
focus() {
|
||||
// $FlowFixMe[incompatible-exact] Migrate all usages of `NativeMethods` to an interface to fix this.
|
||||
TextInputState.focusTextInput(this);
|
||||
}
|
||||
|
||||
measure(callback: MeasureOnSuccessCallback) {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
fabricMeasure(node, callback);
|
||||
}
|
||||
}
|
||||
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
fabricMeasureInWindow(node, callback);
|
||||
}
|
||||
}
|
||||
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void /* currently unused */,
|
||||
) {
|
||||
if (
|
||||
typeof relativeToNativeNode === 'number' ||
|
||||
!(relativeToNativeNode instanceof ReactFabricHostComponent)
|
||||
) {
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
'Warning: ref.measureLayout must be called with a ref to a native component.',
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const toStateNode = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
const fromStateNode = getNodeFromInternalInstanceHandle(
|
||||
relativeToNativeNode.__internalInstanceHandle,
|
||||
);
|
||||
|
||||
if (toStateNode != null && fromStateNode != null) {
|
||||
fabricMeasureLayout(
|
||||
toStateNode,
|
||||
fromStateNode,
|
||||
onFail != null ? onFail : noop,
|
||||
onSuccess != null ? onSuccess : noop,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unstable_getBoundingClientRect(): DOMRect {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
const rect = fabricGetBoundingClientRect(node);
|
||||
|
||||
if (rect) {
|
||||
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty rect if any of the above failed
|
||||
return new DOMRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
setNativeProps(nativeProps: {...}): void {
|
||||
if (__DEV__) {
|
||||
warnForStyleProps(nativeProps, this._viewConfig.validAttributes);
|
||||
}
|
||||
const updatePayload = create(nativeProps, this._viewConfig.validAttributes);
|
||||
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null && updatePayload != null) {
|
||||
setNativeProps(node, updatePayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function warnForStyleProps(
|
||||
props: {...},
|
||||
validAttributes: AttributeConfiguration,
|
||||
): void {
|
||||
if (__DEV__) {
|
||||
for (const key in validAttributes.style) {
|
||||
if (!(validAttributes[key] || props[key] === undefined)) {
|
||||
console.error(
|
||||
'You are setting the style `{ %s' +
|
||||
': ... }` as a prop. You ' +
|
||||
'should nest it in a style object. ' +
|
||||
'E.g. `{ style: { %s' +
|
||||
': ... } }`',
|
||||
key,
|
||||
key,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Lazy loaded to avoid evaluating the module when using the legacy renderer.
|
||||
let ReactFabricHostComponent: Class<ReactFabricHostComponentType>;
|
||||
// Lazy loaded to avoid evaluating the module when using the legacy renderer.
|
||||
let ReactFabric: ReactFabricType;
|
||||
|
||||
export function createPublicInstance(
|
||||
tag: number,
|
||||
viewConfig: ViewConfig,
|
||||
internalInstanceHandle: mixed,
|
||||
): ReactFabricHostComponent {
|
||||
): ReactFabricHostComponentType {
|
||||
if (ReactFabricHostComponent == null) {
|
||||
ReactFabricHostComponent = require('./ReactFabricHostComponent').default;
|
||||
}
|
||||
return new ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle);
|
||||
}
|
||||
|
||||
@@ -186,15 +36,24 @@ export function createPublicTextInstance(internalInstanceHandle: mixed): {} {
|
||||
}
|
||||
|
||||
export function getNativeTagFromPublicInstance(
|
||||
publicInstance: ReactFabricHostComponent,
|
||||
publicInstance: ReactFabricHostComponentType,
|
||||
): number {
|
||||
return publicInstance.__nativeTag;
|
||||
}
|
||||
|
||||
export function getNodeFromPublicInstance(
|
||||
publicInstance: ReactFabricHostComponent,
|
||||
publicInstance: ReactFabricHostComponentType,
|
||||
): mixed {
|
||||
return getNodeFromInternalInstanceHandle(
|
||||
// Avoid loading ReactFabric if using an instance from the legacy renderer.
|
||||
if (publicInstance.__internalInstanceHandle == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ReactFabric == null) {
|
||||
ReactFabric = require('../../Renderer/shims/ReactFabric');
|
||||
}
|
||||
|
||||
return ReactFabric.getNodeFromInternalInstanceHandle(
|
||||
publicInstance.__internalInstanceHandle,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user