From bda409cf272cc2c34d4af98ed8ba94617e3bf748 Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Sun, 28 Apr 2024 04:54:38 -0500 Subject: [PATCH 1/3] fix(types): add shell types for react-reconciler changes --- packages/fiber/src/core/reconciler.tsx | 109 +++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/packages/fiber/src/core/reconciler.tsx b/packages/fiber/src/core/reconciler.tsx index 2afd8b898d..b7c18a9906 100644 --- a/packages/fiber/src/core/reconciler.tsx +++ b/packages/fiber/src/core/reconciler.tsx @@ -2,7 +2,6 @@ import * as THREE from 'three' import * as React from 'react' import Reconciler from 'react-reconciler' import { - // @ts-expect-error NoEventPriority, ContinuousEventPriority, DiscreteEventPriority, @@ -23,6 +22,98 @@ import type { RootStore } from './store' import { removeInteractivity, type EventHandlers } from './events' import type { ThreeElement } from '../three-types' +// TODO: upstream to DefinitelyTyped for React 19 +type EventPriority = number + +const createReconciler = Reconciler as unknown as < + Type, + Props, + Container, + Instance, + TextInstance, + SuspenseInstance, + HydratableInstance, + FormInstance, + PublicInstance, + HostContext, + ChildSet, + TimeoutHandle, + NoTimeout, + TransitionStatus, +>( + config: Omit< + Reconciler.HostConfig< + Type, + Props, + Container, + Instance, + TextInstance, + SuspenseInstance, + HydratableInstance, + PublicInstance, + HostContext, + null, // updatePayload + ChildSet, + TimeoutHandle, + NoTimeout + >, + 'getCurrentEventPriority' | 'prepareUpdate' | 'commitUpdate' + > & { + // Changed + /** + * This method should mutate the `instance` and perform prop diffing if needed. + * + * The `internalHandle` data structure is meant to be opaque. If you bend the rules and rely on its internal fields, be aware that it may change significantly between versions. You're taking on additional maintenance risk by reading from it, and giving up all guarantees if you write something to it. + */ + commitUpdate?( + instance: Instance, + type: Type, + prevProps: Props, + nextProps: Props, + internalHandle: Reconciler.OpaqueHandle, + ): void + + // Undocumented + NotPendingTransition: TransitionStatus | null + setCurrentUpdatePriority(newPriority: EventPriority): void + getCurrentUpdatePriority(): EventPriority + resolveUpdatePriority(): EventPriority + resetFormInstance(form: FormInstance): void + requestPostPaintCallback(callback: (time: number) => void): void + shouldAttemptEagerTransition(): boolean + + /** + * This method is called during render to determine if the Host Component type and props require some kind of loading process to complete before committing an update. + */ + maySuspendCommit(type: Type, props: Props): boolean + /** + * This method may be called during render if the Host Component type and props might suspend a commit. It can be used to initiate any work that might shorten the duration of a suspended commit. + */ + preloadInstance(type: Type, props: Props): boolean + /** + * This method is called just before the commit phase. Use it to set up any necessary state while any Host Components that might suspend this commit are evaluated to determine if the commit must be suspended. + */ + startSuspendingCommit(): void + /** + * This method is called after `startSuspendingCommit` for each Host Component that indicated it might suspend a commit. + */ + suspendInstance(type: Type, props: Props): void + /** + * This method is called after all `suspendInstance` calls are complete. + * + * Return `null` if the commit can happen immediately. + * + * Return `(initiateCommit: Function) => Function` if the commit must be suspended. The argument to this callback will initiate the commit when called. The return value is a cancellation function that the Reconciler can use to abort the commit. + * + */ + waitForCommitToBeReady(): ((initiateCommit: Function) => Function) | null + }, +) => Reconciler.Reconciler + +declare module 'react-reconciler/constants' { + const NoEventPriority = 0 +} + export interface Root { fiber: Reconciler.FiberRoot store: RootStore @@ -76,12 +167,13 @@ interface HostConfig { textInstance: void suspenseInstance: Instance hydratableInstance: never + formInstance: never publicInstance: Instance['object'] hostContext: {} - updatePayload: null | [true] | [false, Instance['props']] // NOTE: removed with React 19 childSet: never timeoutHandle: number | undefined noTimeout: -1 + TransitionStatus: null } export const catalogue: Catalogue = {} @@ -324,7 +416,7 @@ const NO_CONTEXT: HostConfig['hostContext'] = {} let currentUpdatePriority: number = NoEventPriority -export const reconciler = Reconciler< +export const reconciler = createReconciler< HostConfig['type'], HostConfig['props'], HostConfig['container'], @@ -332,12 +424,13 @@ export const reconciler = Reconciler< HostConfig['textInstance'], HostConfig['suspenseInstance'], HostConfig['hydratableInstance'], + HostConfig['formInstance'], HostConfig['publicInstance'], HostConfig['hostContext'], - HostConfig['updatePayload'], HostConfig['childSet'], HostConfig['timeoutHandle'], - HostConfig['noTimeout'] + HostConfig['noTimeout'], + HostConfig['TransitionStatus'] >({ isPrimaryRenderer: false, warnsIfNotActing: false, @@ -369,7 +462,6 @@ export const reconciler = Reconciler< }, getRootHostContext: () => NO_CONTEXT, getChildHostContext: () => NO_CONTEXT, - // @ts-expect-error prepareUpdate and updatePayload removed with React 19 commitUpdate( instance: HostConfig['instance'], type: HostConfig['type'], @@ -418,8 +510,8 @@ export const reconciler = Reconciler< beforeActiveInstanceBlur() {}, afterActiveInstanceBlur() {}, detachDeletedInstance() {}, - // TODO: add shell types for these and upstream to DefinitelyTyped - // https://github.com/facebook/react/blob/main/packages/react-art/src/ReactFiberConfigART.js + prepareScopeUpdate() {}, + getInstanceFromScope: () => null, shouldAttemptEagerTransition() { return false }, @@ -464,4 +556,5 @@ export const reconciler = Reconciler< return DefaultEventPriority } }, + resetFormInstance(): void {}, }) From 47bb62867543da3a3f9f2cb40bb6b84ca08ccd78 Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Sun, 28 Apr 2024 05:06:32 -0500 Subject: [PATCH 2/3] chore(types): cleanup --- packages/fiber/src/core/reconciler.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/fiber/src/core/reconciler.tsx b/packages/fiber/src/core/reconciler.tsx index b7c18a9906..10b4ca693f 100644 --- a/packages/fiber/src/core/reconciler.tsx +++ b/packages/fiber/src/core/reconciler.tsx @@ -59,7 +59,6 @@ const createReconciler = Reconciler as unknown as < >, 'getCurrentEventPriority' | 'prepareUpdate' | 'commitUpdate' > & { - // Changed /** * This method should mutate the `instance` and perform prop diffing if needed. * @@ -74,12 +73,17 @@ const createReconciler = Reconciler as unknown as < ): void // Undocumented + // https://github.com/facebook/react/pull/26722 NotPendingTransition: TransitionStatus | null + // https://github.com/facebook/react/pull/28751 setCurrentUpdatePriority(newPriority: EventPriority): void getCurrentUpdatePriority(): EventPriority resolveUpdatePriority(): EventPriority + // https://github.com/facebook/react/pull/28804 resetFormInstance(form: FormInstance): void + // https://github.com/facebook/react/pull/25105 requestPostPaintCallback(callback: (time: number) => void): void + // https://github.com/facebook/react/pull/26025 shouldAttemptEagerTransition(): boolean /** @@ -556,5 +560,5 @@ export const reconciler = createReconciler< return DefaultEventPriority } }, - resetFormInstance(): void {}, + resetFormInstance() {}, }) From aaadee9d5e84b2fe47d669c32504c1742025fbf4 Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Wed, 15 May 2024 14:31:39 -0500 Subject: [PATCH 3/3] chore: add backlink --- packages/fiber/src/core/reconciler.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/fiber/src/core/reconciler.tsx b/packages/fiber/src/core/reconciler.tsx index 10b4ca693f..bbb1f4e164 100644 --- a/packages/fiber/src/core/reconciler.tsx +++ b/packages/fiber/src/core/reconciler.tsx @@ -23,6 +23,7 @@ import { removeInteractivity, type EventHandlers } from './events' import type { ThreeElement } from '../three-types' // TODO: upstream to DefinitelyTyped for React 19 +// https://github.com/facebook/react/issues/28956 type EventPriority = number const createReconciler = Reconciler as unknown as <