import type {Fiber} from './ReactInternalTypes';
import type {StackCursor} from './ReactFiberStack';
import type {Container, HostContext} from './ReactFiberConfig';
import type {Hook} from './ReactFiberHooks';
import {
getChildHostContext,
getRootHostContext,
HostTransitionContext,
NotPendingTransition,
isPrimaryRenderer,
} from './ReactFiberConfig';
import {createCursor, push, pop} from './ReactFiberStack';
import {enableAsyncActions} from 'shared/ReactFeatureFlags';
const contextStackCursor: StackCursor<HostContext | null> = createCursor(null);
const contextFiberStackCursor: StackCursor<Fiber | null> = createCursor(null);
const rootInstanceStackCursor: StackCursor<Container | null> =
createCursor(null);
const hostTransitionProviderCursor: StackCursor<Fiber | null> =
createCursor(null);
function requiredContext<Value>(c: Value | null): Value {
if (__DEV__) {
if (c === null) {
console.error(
'Expected host context to exist. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
}
}
return (c: any);
}
function getCurrentRootHostContainer(): null | Container {
return rootInstanceStackCursor.current;
}
function getRootHostContainer(): Container {
const rootInstance = requiredContext(rootInstanceStackCursor.current);
return rootInstance;
}
export function getHostTransitionProvider(): Fiber | null {
return hostTransitionProviderCursor.current;
}
function pushHostContainer(fiber: Fiber, nextRootInstance: Container): void {
push(rootInstanceStackCursor, nextRootInstance, fiber);
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, null, fiber);
const nextRootContext = getRootHostContext(nextRootInstance);
pop(contextStackCursor, fiber);
push(contextStackCursor, nextRootContext, fiber);
}
function popHostContainer(fiber: Fiber) {
pop(contextStackCursor, fiber);
pop(contextFiberStackCursor, fiber);
pop(rootInstanceStackCursor, fiber);
}
function getHostContext(): HostContext {
const context = requiredContext(contextStackCursor.current);
return context;
}
function pushHostContext(fiber: Fiber): void {
if (enableAsyncActions) {
const stateHook: Hook | null = fiber.memoizedState;
if (stateHook !== null) {
push(hostTransitionProviderCursor, fiber, fiber);
}
}
const context: HostContext = requiredContext(contextStackCursor.current);
const nextContext = getChildHostContext(context, fiber.type);
if (context !== nextContext) {
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, nextContext, fiber);
}
}
function popHostContext(fiber: Fiber): void {
if (contextFiberStackCursor.current === fiber) {
pop(contextStackCursor, fiber);
pop(contextFiberStackCursor, fiber);
}
if (enableAsyncActions) {
if (hostTransitionProviderCursor.current === fiber) {
pop(hostTransitionProviderCursor, fiber);
if (isPrimaryRenderer) {
HostTransitionContext._currentValue = NotPendingTransition;
} else {
HostTransitionContext._currentValue2 = NotPendingTransition;
}
}
}
}
export {
getHostContext,
getCurrentRootHostContainer,
getRootHostContainer,
popHostContainer,
popHostContext,
pushHostContainer,
pushHostContext,
};