/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
status
packages/react-native-renderer/src/ReactFabricHostConfig.js
497 строк
13 KB
Dominic Gannaway
[react-interactions] Adds more experimental Scope API methods (#17042)
08 окт 2019, 20:32
Не верифицирован
08 окт 2019, 20:32
b71ab61
Код
Авторство
О чём код?
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import type { MeasureInWindowOnSuccessCallback, MeasureLayoutOnSuccessCallback, MeasureOnSuccessCallback, NativeMethods, ReactNativeBaseComponentViewConfig, ReactNativeResponderEvent, ReactNativeResponderContext, } from './ReactNativeTypes'; import type { ReactEventResponder, ReactEventResponderInstance, } from 'shared/ReactTypes'; import {mountSafeCallback_NOT_REALLY_SAFE} from './NativeMethodsMixinUtils'; import {create, diff} from './ReactNativeAttributePayload'; import invariant from 'shared/invariant'; import warningWithoutStack from 'shared/warningWithoutStack'; import {dispatchEvent} from './ReactFabricEventEmitter'; import { addRootEventTypesForResponderInstance, mountEventResponder, unmountEventResponder, } from './ReactFabricEventResponderSystem'; import {enableFlareAPI} from 'shared/ReactFeatureFlags'; // Modules provided by RN: import { ReactNativeViewConfigRegistry, TextInputState, deepFreezeAndThrowOnMutationInDev, } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; const { createNode, cloneNode, cloneNodeWithNewChildren, cloneNodeWithNewChildrenAndProps, cloneNodeWithNewProps, createChildSet: createChildNodeSet, appendChild: appendChildNode, appendChildToSet: appendChildNodeToSet, completeRoot, registerEventHandler, measure: fabricMeasure, measureInWindow: fabricMeasureInWindow, measureLayout: fabricMeasureLayout, } = nativeFabricUIManager; const {get: getViewConfigForType} = ReactNativeViewConfigRegistry; // Counter for uniquely identifying views. // % 10 === 1 means it is a rootTag. // % 2 === 0 means it is a Fabric tag. // This means that they never overlap. let nextReactTag = 2; type ReactNativeEventResponderInstance = ReactEventResponderInstance< ReactNativeResponderEvent, ReactNativeResponderContext, >; type ReactNativeEventResponder = ReactEventResponder< ReactNativeResponderEvent, ReactNativeResponderContext, >; type Node = Object; export type Type = string; export type Props = Object; export type Instance = { node: Node, canonical: ReactFabricHostComponent, }; export type TextInstance = { node: Node, }; export type HydratableInstance = Instance | TextInstance; export type PublicInstance = ReactFabricHostComponent; export type Container = number; export type ChildSet = Object; export type HostContext = $ReadOnly<{| isInAParentText: boolean, |}>; export type UpdatePayload = Object; export type TimeoutHandle = TimeoutID; export type NoTimeout = -1; // TODO: Remove this conditional once all changes have propagated. if (registerEventHandler) { /** * Register the event emitter with the native bridge */ registerEventHandler(dispatchEvent); } /** * This is used for refs on host components. */ class ReactFabricHostComponent { _nativeTag: number; viewConfig: ReactNativeBaseComponentViewConfig<>; currentProps: Props; _internalInstanceHandle: Object; constructor( tag: number, viewConfig: ReactNativeBaseComponentViewConfig<>, props: Props, internalInstanceHandle: Object, ) { this._nativeTag = tag; this.viewConfig = viewConfig; this.currentProps = props; this._internalInstanceHandle = internalInstanceHandle; } blur() { TextInputState.blurTextInput(this._nativeTag); } focus() { TextInputState.focusTextInput(this._nativeTag); } measure(callback: MeasureOnSuccessCallback) { fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback), ); } measureInWindow(callback: MeasureInWindowOnSuccessCallback) { fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback), ); } measureLayout( relativeToNativeNode: number | ReactFabricHostComponent, onSuccess: MeasureLayoutOnSuccessCallback, onFail?: () => void /* currently unused */, ) { if ( typeof relativeToNativeNode === 'number' || !(relativeToNativeNode instanceof ReactFabricHostComponent) ) { warningWithoutStack( false, 'Warning: ref.measureLayout must be called with a ref to a native component.', ); return; } fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess), ); } setNativeProps(nativeProps: Object) { warningWithoutStack( false, 'Warning: setNativeProps is not currently supported in Fabric', ); return; } } // eslint-disable-next-line no-unused-expressions (ReactFabricHostComponent.prototype: NativeMethods); export * from 'shared/HostConfigWithNoMutation'; export * from 'shared/HostConfigWithNoHydration'; export function appendInitialChild( parentInstance: Instance, child: Instance | TextInstance, ): void { appendChildNode(parentInstance.node, child.node); } export function createInstance( type: string, props: Props, rootContainerInstance: Container, hostContext: HostContext, internalInstanceHandle: Object, ): Instance { const tag = nextReactTag; nextReactTag += 2; const viewConfig = getViewConfigForType(type); if (__DEV__) { for (const key in viewConfig.validAttributes) { if (props.hasOwnProperty(key)) { deepFreezeAndThrowOnMutationInDev(props[key]); } } } const updatePayload = create(props, viewConfig.validAttributes); const node = createNode( tag, // reactTag viewConfig.uiViewClassName, // viewName rootContainerInstance, // rootTag updatePayload, // props internalInstanceHandle, // internalInstanceHandle ); const component = new ReactFabricHostComponent( tag, viewConfig, props, internalInstanceHandle, ); return { node: node, canonical: component, }; } export function createTextInstance( text: string, rootContainerInstance: Container, hostContext: HostContext, internalInstanceHandle: Object, ): TextInstance { invariant( hostContext.isInAParentText, 'Text strings must be rendered within a <Text> component.', ); const tag = nextReactTag; nextReactTag += 2; const node = createNode( tag, // reactTag 'RCTRawText', // viewName rootContainerInstance, // rootTag {text: text}, // props internalInstanceHandle, // instance handle ); return { node: node, }; } export function finalizeInitialChildren( parentInstance: Instance, type: string, props: Props, rootContainerInstance: Container, hostContext: HostContext, ): boolean { return false; } export function getRootHostContext( rootContainerInstance: Container, ): HostContext { return {isInAParentText: false}; } export function getChildHostContext( parentHostContext: HostContext, type: string, rootContainerInstance: Container, ): HostContext { const prevIsInAParentText = parentHostContext.isInAParentText; const isInAParentText = type === 'AndroidTextInput' || // Android type === 'RCTMultilineTextInputView' || // iOS type === 'RCTSinglelineTextInputView' || // iOS type === 'RCTText' || type === 'RCTVirtualText'; if (prevIsInAParentText !== isInAParentText) { return {isInAParentText}; } else { return parentHostContext; } } export function getPublicInstance(instance: Instance): * { return instance.canonical; } export function prepareForCommit(containerInfo: Container): void { // Noop } export function prepareUpdate( instance: Instance, type: string, oldProps: Props, newProps: Props, rootContainerInstance: Container, hostContext: HostContext, ): null | Object { const viewConfig = instance.canonical.viewConfig; const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); // TODO: If the event handlers have changed, we need to update the current props // in the commit phase but there is no host config hook to do it yet. // So instead we hack it by updating it in the render phase. instance.canonical.currentProps = newProps; return updatePayload; } export function resetAfterCommit(containerInfo: Container): void { // Noop } export function shouldDeprioritizeSubtree(type: string, props: Props): boolean { return false; } export function shouldSetTextContent(type: string, props: Props): boolean { // TODO (bvaughn) Revisit this decision. // Always returning false simplifies the createInstance() implementation, // But creates an additional child Fiber for raw text children. // No additional native views are created though. // It's not clear to me which is better so I'm deferring for now. // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 return false; } // The Fabric renderer is secondary to the existing React Native renderer. export const isPrimaryRenderer = false; // The Fabric renderer shouldn't trigger missing act() warnings export const warnsIfNotActing = false; export const scheduleTimeout = setTimeout; export const cancelTimeout = clearTimeout; export const noTimeout = -1; // ------------------- // Persistence // ------------------- export const supportsPersistence = true; export function cloneInstance( instance: Instance, updatePayload: null | Object, type: string, oldProps: Props, newProps: Props, internalInstanceHandle: Object, keepChildren: boolean, recyclableInstance: null | Instance, ): Instance { const node = instance.node; let clone; if (keepChildren) { if (updatePayload !== null) { clone = cloneNodeWithNewProps(node, updatePayload); } else { clone = cloneNode(node); } } else { if (updatePayload !== null) { clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); } else { clone = cloneNodeWithNewChildren(node); } } return { node: clone, canonical: instance.canonical, }; } export function cloneHiddenInstance( instance: Instance, type: string, props: Props, internalInstanceHandle: Object, ): Instance { const viewConfig = instance.canonical.viewConfig; const node = instance.node; const updatePayload = create( {style: {display: 'none'}}, viewConfig.validAttributes, ); return { node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical, }; } export function cloneHiddenTextInstance( instance: Instance, text: string, internalInstanceHandle: Object, ): TextInstance { throw new Error('Not yet implemented.'); } export function createContainerChildSet(container: Container): ChildSet { return createChildNodeSet(container); } export function appendChildToContainerChildSet( childSet: ChildSet, child: Instance | TextInstance, ): void { appendChildNodeToSet(childSet, child.node); } export function finalizeContainerChildren( container: Container, newChildren: ChildSet, ): void { completeRoot(container, newChildren); } export function replaceContainerChildren( container: Container, newChildren: ChildSet, ): void {} export function mountResponderInstance( responder: ReactNativeEventResponder, responderInstance: ReactNativeEventResponderInstance, props: Object, state: Object, instance: Instance, ) { if (enableFlareAPI) { const {rootEventTypes} = responder; if (rootEventTypes !== null) { addRootEventTypesForResponderInstance(responderInstance, rootEventTypes); } mountEventResponder(responder, responderInstance, props, state); } } export function unmountResponderInstance( responderInstance: ReactNativeEventResponderInstance, ): void { if (enableFlareAPI) { // TODO stop listening to targetEventTypes unmountEventResponder(responderInstance); } } export function getFundamentalComponentInstance(fundamentalInstance) { throw new Error('Not yet implemented.'); } export function mountFundamentalComponent(fundamentalInstance) { throw new Error('Not yet implemented.'); } export function shouldUpdateFundamentalComponent(fundamentalInstance) { throw new Error('Not yet implemented.'); } export function updateFundamentalComponent(fundamentalInstance) { throw new Error('Not yet implemented.'); } export function unmountFundamentalComponent(fundamentalInstance) { throw new Error('Not yet implemented.'); } export function cloneFundamentalInstance(fundamentalInstance) { throw new Error('Not yet implemented.'); } export function getInstanceFromNode(node) { throw new Error('Not yet implemented.'); }