import type {InspectorData, TouchedViewDataAtPoint} from './ReactNativeTypes';
import type {TransitionTypes} from 'react/src/ReactTransitionType';
import {
ReactNativeViewConfigRegistry,
UIManager,
deepFreezeAndThrowOnMutationInDev,
type PublicRootInstance,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {create, diff} from './ReactNativeAttributePayload';
import {
precacheFiberNode,
uncacheFiberNode,
updateFiberProps,
getClosestInstanceFromNode,
} from './ReactNativeComponentTree';
import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent';
import {
DefaultEventPriority,
NoEventPriority,
type EventPriority,
} from 'react-reconciler/src/ReactEventPriorities';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
import type {ReactContext} from 'shared/ReactTypes';
import {
getInspectorDataForViewTag,
getInspectorDataForViewAtPoint,
getInspectorDataForInstance,
} from './ReactNativeFiberInspector';
export {default as rendererVersion} from 'shared/ReactVersion';
export const rendererPackageName = 'react-native-renderer';
export const extraDevToolsConfig = {
getInspectorDataForInstance,
getInspectorDataForViewTag,
getInspectorDataForViewAtPoint,
};
const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
export type Type = string;
export type Props = Object;
export type Container = {
containerTag: number,
publicInstance: PublicRootInstance | null,
};
export type Instance = ReactNativeFiberHostComponent;
export type TextInstance = number;
export type HydratableInstance = Instance | TextInstance;
export type PublicInstance = Instance;
export type HostContext = $ReadOnly<{
isInAParentText: boolean,
}>;
export type UpdatePayload = Object;
export type ChildSet = void;
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,
}>;
let nextReactTag = 3;
function allocateTag() {
let tag = nextReactTag;
if (tag % 10 === 1) {
tag += 2;
}
nextReactTag = tag + 2;
return tag;
}
function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
if (typeof node === 'number') {
uncacheFiberNode(node);
} else {
uncacheFiberNode((node: any)._nativeTag);
(node: any)._children.forEach(recursivelyUncacheFiberNode);
}
}
export * from 'react-reconciler/src/ReactFiberConfigWithNoPersistence';
export * from 'react-reconciler/src/ReactFiberConfigWithNoHydration';
export * from 'react-reconciler/src/ReactFiberConfigWithNoScopes';
export * from 'react-reconciler/src/ReactFiberConfigWithNoTestSelectors';
export * from 'react-reconciler/src/ReactFiberConfigWithNoMicrotasks';
export * from 'react-reconciler/src/ReactFiberConfigWithNoResources';
export * from 'react-reconciler/src/ReactFiberConfigWithNoSingletons';
export function appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
parentInstance._children.push(child);
}
export function createInstance(
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: Object,
): Instance {
const tag = allocateTag();
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);
UIManager.createView(
tag,
viewConfig.uiViewClassName,
rootContainerInstance.containerTag,
updatePayload,
);
const component = new ReactNativeFiberHostComponent(
tag,
viewConfig,
internalInstanceHandle,
);
precacheFiberNode(internalInstanceHandle, tag);
updateFiberProps(tag, props);
return ((component: any): Instance);
}
export function cloneMutableInstance(
instance: Instance,
keepChildren: boolean,
): Instance {
throw new Error('Not yet implemented.');
}
export function createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
if (!hostContext.isInAParentText) {
throw new Error('Text strings must be rendered within a <Text> component.');
}
const tag = allocateTag();
UIManager.createView(
tag,
'RCTRawText',
rootContainerInstance.containerTag,
{text: text},
);
precacheFiberNode(internalInstanceHandle, tag);
return tag;
}
export function cloneMutableTextInstance(
textInstance: TextInstance,
): TextInstance {
throw new Error('Not yet implemented.');
}
export type FragmentInstanceType = null;
export function createFragmentInstance(
fragmentFiber: Fiber,
): FragmentInstanceType {
return null;
}
export function updateFragmentInstanceFiber(
fragmentFiber: Fiber,
instance: FragmentInstanceType,
): void {
}
export function commitNewChildToFragmentInstance(
child: PublicInstance,
fragmentInstance: FragmentInstanceType,
): void {
}
export function deleteChildFromFragmentInstance(
child: PublicInstance,
fragmentInstance: FragmentInstanceType,
): void {
}
export function finalizeInitialChildren(
parentInstance: Instance,
type: string,
props: Props,
hostContext: HostContext,
): boolean {
if (parentInstance._children.length === 0) {
return false;
}
const nativeTags = parentInstance._children.map(child =>
typeof child === 'number'
? child
: child._nativeTag,
);
UIManager.setChildren(
parentInstance._nativeTag,
nativeTags,
);
return false;
}
export function getRootHostContext(
rootContainerInstance: Container,
): HostContext {
return {isInAParentText: false};
}
export function getChildHostContext(
parentHostContext: HostContext,
type: string,
): HostContext {
const prevIsInAParentText = parentHostContext.isInAParentText;
const isInAParentText =
type === 'AndroidTextInput' ||
type === 'RCTMultilineTextInputView' ||
type === 'RCTSinglelineTextInputView' ||
type === 'RCTText' ||
type === 'RCTVirtualText';
if (prevIsInAParentText !== isInAParentText) {
return {isInAParentText};
} else {
return parentHostContext;
}
}
export function getPublicInstance(instance: Instance): PublicInstance {
if (instance.canonical != null && instance.canonical.publicInstance != null) {
return instance.canonical.publicInstance;
}
return instance;
}
export function prepareForCommit(containerInfo: Container): null | Object {
return null;
}
export function resetAfterCommit(containerInfo: Container): void {
}
export const isPrimaryRenderer = true;
export const warnsIfNotActing = true;
export const scheduleTimeout = setTimeout;
export const cancelTimeout = clearTimeout;
export const noTimeout = -1;
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;
}
return DefaultEventPriority;
}
export function trackSchedulerEvent(): void {}
export function resolveEventType(): null | string {
return null;
}
export function resolveEventTimeStamp(): number {
return -1.1;
}
export function shouldAttemptEagerTransition(): boolean {
return false;
}
export const supportsMutation = true;
export function appendChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
const childTag = typeof child === 'number' ? child : child._nativeTag;
const children = parentInstance._children;
const index = children.indexOf(child);
if (index >= 0) {
children.splice(index, 1);
children.push(child);
UIManager.manageChildren(
parentInstance._nativeTag,
[index],
[children.length - 1],
[],
[],
[],
);
} else {
children.push(child);
UIManager.manageChildren(
parentInstance._nativeTag,
[],
[],
[childTag],
[children.length - 1],
[],
);
}
}
export function appendChildToContainer(
parentInstance: Container,
child: Instance | TextInstance,
): void {
const childTag = typeof child === 'number' ? child : child._nativeTag;
UIManager.setChildren(
parentInstance.containerTag,
[childTag],
);
}
export function commitTextUpdate(
textInstance: TextInstance,
oldText: string,
newText: string,
): void {
UIManager.updateView(
textInstance,
'RCTRawText',
{text: newText},
);
}
export function commitMount(
instance: Instance,
type: string,
newProps: Props,
internalInstanceHandle: Object,
): void {
}
export function commitUpdate(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props,
internalInstanceHandle: Object,
): void {
const viewConfig = instance.viewConfig;
updateFiberProps(instance._nativeTag, newProps);
const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
if (updatePayload != null) {
UIManager.updateView(
instance._nativeTag,
viewConfig.uiViewClassName,
updatePayload,
);
}
}
export function insertBefore(
parentInstance: Instance,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void {
const children = (parentInstance: any)._children;
const index = children.indexOf(child);
if (index >= 0) {
children.splice(index, 1);
const beforeChildIndex = children.indexOf(beforeChild);
children.splice(beforeChildIndex, 0, child);
UIManager.manageChildren(
(parentInstance: any)._nativeTag,
[index],
[beforeChildIndex],
[],
[],
[],
);
} else {
const beforeChildIndex = children.indexOf(beforeChild);
children.splice(beforeChildIndex, 0, child);
const childTag = typeof child === 'number' ? child : child._nativeTag;
UIManager.manageChildren(
(parentInstance: any)._nativeTag,
[],
[],
[childTag],
[beforeChildIndex],
[],
);
}
}
export function insertInContainerBefore(
parentInstance: Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void {
if (typeof parentInstance === 'number') {
throw new Error('Container does not support insertBefore operation');
}
}
export function removeChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
recursivelyUncacheFiberNode(child);
const children = parentInstance._children;
const index = children.indexOf(child);
children.splice(index, 1);
UIManager.manageChildren(
parentInstance._nativeTag,
[],
[],
[],
[],
[index],
);
}
export function removeChildFromContainer(
parentInstance: Container,
child: Instance | TextInstance,
): void {
recursivelyUncacheFiberNode(child);
UIManager.manageChildren(
parentInstance.containerTag,
[],
[],
[],
[],
[0],
);
}
export function resetTextContent(instance: Instance): void {
}
export function hideInstance(instance: Instance): void {
const viewConfig = instance.viewConfig;
const updatePayload = create(
{style: {display: 'none'}},
viewConfig.validAttributes,
);
UIManager.updateView(
instance._nativeTag,
viewConfig.uiViewClassName,
updatePayload,
);
}
export function hideTextInstance(textInstance: TextInstance): void {
throw new Error('Not yet implemented.');
}
export function unhideInstance(instance: Instance, props: Props): void {
const viewConfig = instance.viewConfig;
const updatePayload = diff(
{...props, style: [props.style, {display: 'none'}]},
props,
viewConfig.validAttributes,
);
UIManager.updateView(
instance._nativeTag,
viewConfig.uiViewClassName,
updatePayload,
);
}
export function applyViewTransitionName(
instance: Instance,
name: string,
className: ?string,
): void {
}
export function restoreViewTransitionName(
instance: Instance,
props: Props,
): void {
}
export function cancelViewTransitionName(
instance: Instance,
name: string,
props: Props,
): void {
}
export function cancelRootViewTransitionName(rootContainer: Container): void {
}
export function restoreRootViewTransitionName(rootContainer: Container): void {
}
export function cloneRootViewTransitionContainer(
rootContainer: Container,
): Instance {
throw new Error('Not implemented.');
}
export function removeRootViewTransitionClone(
rootContainer: Container,
clone: Instance,
): void {
throw new Error('Not implemented.');
}
export type InstanceMeasurement = null;
export function measureInstance(instance: Instance): InstanceMeasurement {
return null;
}
export function measureClonedInstance(instance: Instance): InstanceMeasurement {
return null;
}
export function wasInstanceInViewport(
measurement: InstanceMeasurement,
): boolean {
return true;
}
export function hasInstanceChanged(
oldMeasurement: InstanceMeasurement,
newMeasurement: InstanceMeasurement,
): boolean {
return false;
}
export function hasInstanceAffectedParent(
oldMeasurement: InstanceMeasurement,
newMeasurement: InstanceMeasurement,
): boolean {
return false;
}
export function startViewTransition(
rootContainer: Container,
transitionTypes: null | TransitionTypes,
mutationCallback: () => void,
layoutCallback: () => void,
afterMutationCallback: () => void,
spawnedWorkCallback: () => void,
passiveCallback: () => mixed,
errorCallback: mixed => void,
): null | RunningViewTransition {
mutationCallback();
layoutCallback();
spawnedWorkCallback();
return null;
}
export type RunningViewTransition = null;
export function startGestureTransition(
rootContainer: Container,
timeline: GestureTimeline,
rangeStart: number,
rangeEnd: number,
transitionTypes: null | TransitionTypes,
mutationCallback: () => void,
animateCallback: () => void,
errorCallback: mixed => void,
): null | RunningViewTransition {
mutationCallback();
animateCallback();
return null;
}
export function stopViewTransition(transition: RunningViewTransition) {}
export type ViewTransitionInstance = null | {name: string, ...};
export function createViewTransitionInstance(
name: string,
): ViewTransitionInstance {
return null;
}
export type GestureTimeline = null;
export function getCurrentGestureOffset(provider: GestureTimeline): number {
throw new Error(
'startGestureTransition is not yet supported in React Native.',
);
}
export function clearContainer(container: Container): void {
}
export function unhideTextInstance(
textInstance: TextInstance,
text: string,
): void {
throw new Error('Not yet implemented.');
}
export {getClosestInstanceFromNode as getInstanceFromNode};
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
}
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 maySuspendCommitOnUpdate(
type: Type,
oldProps: Props,
newProps: Props,
): boolean {
return false;
}
export function maySuspendCommitInSyncRender(
type: Type,
props: Props,
): boolean {
return false;
}
export function preloadInstance(
instance: Instance,
type: Type,
props: Props,
): boolean {
return true;
}
export function startSuspendingCommit(): void {}
export function suspendInstance(
instance: Instance,
type: Type,
props: Props,
): void {}
export function suspendOnActiveViewTransition(container: Container): 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 {}