import type {
InspectorData,
TouchedViewDataAtPoint,
ViewConfig,
} from './ReactNativeTypes';
import {create, diff} from './ReactNativeAttributePayloadFabric';
import {dispatchEvent} from './ReactFabricEventEmitter';
import {
NoEventPriority,
DefaultEventPriority,
DiscreteEventPriority,
type EventPriority,
} from 'react-reconciler/src/ReactEventPriorities';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import {HostText} from 'react-reconciler/src/ReactWorkTags';
import {
ReactNativeViewConfigRegistry,
deepFreezeAndThrowOnMutationInDev,
createPublicInstance,
createPublicTextInstance,
type PublicInstance as ReactNativePublicInstance,
type PublicTextInstance,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
const {
createNode,
cloneNodeWithNewChildren,
cloneNodeWithNewChildrenAndProps,
cloneNodeWithNewProps,
createChildSet: createChildNodeSet,
appendChild: appendChildNode,
appendChildToSet: appendChildNodeToSet,
completeRoot,
registerEventHandler,
unstable_DefaultEventPriority: FabricDefaultPriority,
unstable_DiscreteEventPriority: FabricDiscretePriority,
unstable_getCurrentEventPriority: fabricGetCurrentEventPriority,
} = nativeFabricUIManager;
import {getClosestInstanceFromNode} from './ReactFabricComponentTree';
import {
getInspectorDataForViewTag,
getInspectorDataForViewAtPoint,
getInspectorDataForInstance,
} from './ReactNativeFiberInspector';
import {
enableFabricCompleteRootInCommitPhase,
passChildrenWhenCloningPersistedNodes,
} from 'shared/ReactFeatureFlags';
import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
import type {ReactContext} from 'shared/ReactTypes';
export {default as rendererVersion} from 'shared/ReactVersion';
export const rendererPackageName = 'react-native-renderer';
export const extraDevToolsConfig = {
getInspectorDataForInstance,
getInspectorDataForViewTag,
getInspectorDataForViewAtPoint,
};
const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
let nextReactTag = 2;
type InternalInstanceHandle = Object;
type Node = Object;
export type Type = string;
export type Props = Object;
export type Instance = {
node: Node,
canonical: {
nativeTag: number,
viewConfig: ViewConfig,
currentProps: Props,
internalInstanceHandle: InternalInstanceHandle,
publicInstance: PublicInstance,
},
};
export type TextInstance = {
node: Node,
publicInstance?: PublicTextInstance,
};
export type HydratableInstance = Instance | TextInstance;
export type PublicInstance = ReactNativePublicInstance;
export type Container = number;
export type ChildSet = Object | Array<Node>;
export type HostContext = $ReadOnly<{
isInAParentText: boolean,
}>;
export type UpdatePayload = Object;
export type TimeoutHandle = TimeoutID;
export type NoTimeout = -1;
export type TransitionStatus = mixed;
export type RendererInspectionConfig = $ReadOnly<{
getInspectorDataForInstance?: (instance: Fiber | null) => InspectorData,
getInspectorDataForViewTag?: (tag: number) => Object,
getInspectorDataForViewAtPoint?: (
inspectedView: Object,
locationX: number,
locationY: number,
callback: (viewData: TouchedViewDataAtPoint) => mixed,
) => void,
}>;
if (registerEventHandler) {
registerEventHandler(dispatchEvent);
}
export * from 'react-reconciler/src/ReactFiberConfigWithNoMutation';
export * from 'react-reconciler/src/ReactFiberConfigWithNoHydration';
export * from 'react-reconciler/src/ReactFiberConfigWithNoScopes';
export * from 'react-reconciler/src/ReactFiberConfigWithNoTestSelectors';
export * from 'react-reconciler/src/ReactFiberConfigWithNoResources';
export * from 'react-reconciler/src/ReactFiberConfigWithNoSingletons';
export function appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
appendChildNode(parentInstance.node, child.node);
}
const PROD_HOST_CONTEXT: HostContext = {isInAParentText: true};
export function createInstance(
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: InternalInstanceHandle,
): 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,
viewConfig.uiViewClassName,
rootContainerInstance,
updatePayload,
internalInstanceHandle,
);
const component = createPublicInstance(
tag,
viewConfig,
internalInstanceHandle,
);
return {
node: node,
canonical: {
nativeTag: tag,
viewConfig,
currentProps: props,
internalInstanceHandle,
publicInstance: component,
},
};
}
export function createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: InternalInstanceHandle,
): TextInstance {
if (__DEV__) {
if (!hostContext.isInAParentText) {
console.error('Text strings must be rendered within a <Text> component.');
}
}
const tag = nextReactTag;
nextReactTag += 2;
const node = createNode(
tag,
'RCTRawText',
rootContainerInstance,
{text: text},
internalInstanceHandle,
);
return {
node: node,
};
}
export function finalizeInitialChildren(
parentInstance: Instance,
type: string,
props: Props,
hostContext: HostContext,
): boolean {
return false;
}
export function getRootHostContext(
rootContainerInstance: Container,
): HostContext {
if (__DEV__) {
return {isInAParentText: false};
}
return PROD_HOST_CONTEXT;
}
export function getChildHostContext(
parentHostContext: HostContext,
type: string,
): HostContext {
if (__DEV__) {
const prevIsInAParentText = parentHostContext.isInAParentText;
const isInAParentText =
type === 'AndroidTextInput' ||
type === 'RCTMultilineTextInputView' ||
type === 'RCTSinglelineTextInputView' ||
type === 'RCTText' ||
type === 'RCTVirtualText';
if (prevIsInAParentText !== isInAParentText) {
return {isInAParentText};
}
}
return parentHostContext;
}
export function getPublicInstance(instance: Instance): null | PublicInstance {
if (instance.canonical != null && instance.canonical.publicInstance != null) {
return instance.canonical.publicInstance;
}
if (instance._nativeTag != null) {
return instance;
}
return null;
}
function getPublicTextInstance(
textInstance: TextInstance,
internalInstanceHandle: InternalInstanceHandle,
): PublicTextInstance {
if (textInstance.publicInstance == null) {
textInstance.publicInstance = createPublicTextInstance(
internalInstanceHandle,
);
}
return textInstance.publicInstance;
}
export function getPublicInstanceFromInternalInstanceHandle(
internalInstanceHandle: InternalInstanceHandle,
): null | PublicInstance | PublicTextInstance {
const instance = internalInstanceHandle.stateNode;
if (instance == null) {
return null;
}
if (internalInstanceHandle.tag === HostText) {
const textInstance: TextInstance = instance;
return getPublicTextInstance(textInstance, internalInstanceHandle);
}
const elementInstance: Instance = internalInstanceHandle.stateNode;
return getPublicInstance(elementInstance);
}
export function prepareForCommit(containerInfo: Container): null | Object {
return null;
}
export function resetAfterCommit(containerInfo: Container): void {
}
export function shouldSetTextContent(type: string, props: Props): boolean {
return false;
}
let currentUpdatePriority: EventPriority = NoEventPriority;
export function setCurrentUpdatePriority(newPriority: EventPriority): void {
currentUpdatePriority = newPriority;
}
export function getCurrentUpdatePriority(): EventPriority {
return currentUpdatePriority;
}
export function resolveUpdatePriority(): EventPriority {
if (currentUpdatePriority !== NoEventPriority) {
return currentUpdatePriority;
}
const currentEventPriority = fabricGetCurrentEventPriority
? fabricGetCurrentEventPriority()
: null;
if (currentEventPriority != null) {
switch (currentEventPriority) {
case FabricDiscretePriority:
return DiscreteEventPriority;
case FabricDefaultPriority:
default:
return DefaultEventPriority;
}
}
return DefaultEventPriority;
}
export function resolveEventType(): null | string {
return null;
}
export function resolveEventTimeStamp(): number {
return -1.1;
}
export function shouldAttemptEagerTransition(): boolean {
return false;
}
export const isPrimaryRenderer = false;
export const warnsIfNotActing = false;
export const scheduleTimeout = setTimeout;
export const cancelTimeout = clearTimeout;
export const noTimeout = -1;
export const supportsPersistence = true;
export function cloneInstance(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props,
keepChildren: boolean,
newChildSet: ?ChildSet,
): Instance {
const viewConfig = instance.canonical.viewConfig;
const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
instance.canonical.currentProps = newProps;
const node = instance.node;
let clone;
if (keepChildren) {
if (updatePayload !== null) {
clone = cloneNodeWithNewProps(node, updatePayload);
} else {
return instance;
}
} else {
if (newChildSet != null) {
if (updatePayload !== null) {
clone = cloneNodeWithNewChildrenAndProps(
node,
newChildSet,
updatePayload,
);
} else {
clone = cloneNodeWithNewChildren(node, newChildSet);
}
} 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,
): 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,
): TextInstance {
throw new Error('Not yet implemented.');
}
export function createContainerChildSet(): ChildSet {
if (passChildrenWhenCloningPersistedNodes) {
return [];
} else {
return createChildNodeSet();
}
}
export function appendChildToContainerChildSet(
childSet: ChildSet,
child: Instance | TextInstance,
): void {
if (passChildrenWhenCloningPersistedNodes) {
childSet.push(child.node);
} else {
appendChildNodeToSet(childSet, child.node);
}
}
export function finalizeContainerChildren(
container: Container,
newChildren: ChildSet,
): void {
if (!enableFabricCompleteRootInCommitPhase) {
completeRoot(container, newChildren);
}
}
export function replaceContainerChildren(
container: Container,
newChildren: ChildSet,
): void {
if (enableFabricCompleteRootInCommitPhase) {
completeRoot(container, newChildren);
}
}
export {getClosestInstanceFromNode as getInstanceFromNode};
export function beforeActiveInstanceBlur(
internalInstanceHandle: InternalInstanceHandle,
) {
}
export function afterActiveInstanceBlur() {
}
export function preparePortalMount(portalInstance: Instance): void {
}
export function detachDeletedInstance(node: Instance): void {
}
export function requestPostPaintCallback(callback: (time: number) => void) {
}
export function maySuspendCommit(type: Type, props: Props): boolean {
return false;
}
export function preloadInstance(type: Type, props: Props): boolean {
return true;
}
export function startSuspendingCommit(): void {}
export function suspendInstance(type: Type, props: Props): void {}
export function waitForCommitToBeReady(): null {
return null;
}
export const NotPendingTransition: TransitionStatus = null;
export const HostTransitionContext: ReactContext<TransitionStatus> = {
$$typeof: REACT_CONTEXT_TYPE,
Provider: (null: any),
Consumer: (null: any),
_currentValue: NotPendingTransition,
_currentValue2: NotPendingTransition,
_threadCount: 0,
};
export type FormInstance = Instance;
export function resetFormInstance(form: Instance): void {}
export const supportsMicrotasks: boolean =
typeof RN$enableMicrotasksInReact !== 'undefined' &&
!!RN$enableMicrotasksInReact;
export const scheduleMicrotask: any =
typeof queueMicrotask === 'function' ? queueMicrotask : scheduleTimeout;