/** * 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 { HostInstance, INativeMethods, InternalInstanceHandle, MeasureInWindowOnSuccessCallback, MeasureLayoutOnSuccessCallback, MeasureOnSuccessCallback, ViewConfig, } from '../../Renderer/shims/ReactNativeTypes'; import TextInputState from '../../Components/TextInput/TextInputState'; import {getNodeFromInternalInstanceHandle} from '../../ReactNative/RendererProxy'; import {getFabricUIManager} from '../FabricUIManager'; import {create} from './ReactNativeAttributePayload'; import warnForStyleProps from './warnForStyleProps'; 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: InternalInstanceHandle; _viewConfig: ViewConfig; constructor( tag: number, viewConfig: ViewConfig, internalInstanceHandle: InternalInstanceHandle, ) { 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 | HostInstance, 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, true); 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); } } }