From 78f5c504b732aec0eb12514bc2cf3f27a8143dd2 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 11 Feb 2026 09:26:22 -0500 Subject: [PATCH 1/4] Notify FragmentInstance of added/removed text (#35637) Follow up to https://github.com/facebook/react/pull/35630 We don't currently have any operations that depend on the updating of text nodes added or removed after Fragment mount. But for the sake of completeness and extending the ability to any other host configs, this change calls `commitNewChildToFragmentInstance` and `deleteChildFromFragmentInstance` on HostText fibers. Both DOM and Fabric configs early return because we cannot attach event listeners or observers to text. In the future, there could be some stateful Fragment feature that uses text that could extend this. --- .../src/client/ReactFiberConfigDOM.js | 24 ++++++++++++------- .../src/ReactFiberConfigFabric.js | 23 ++++++++++++++---- .../src/ReactFiberCommitHostEffects.js | 8 +++++-- .../src/ReactFiberCommitWork.js | 13 ++++++++-- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index a03ccc161ad1..5b2d1e09fc09 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3544,40 +3544,48 @@ export function updateFragmentInstanceFiber( } export function commitNewChildToFragmentInstance( - childInstance: InstanceWithFragmentHandles, + childInstance: InstanceWithFragmentHandles | Text, fragmentInstance: FragmentInstanceType, ): void { + if (childInstance.nodeType === TEXT_NODE) { + return; + } + const instance: InstanceWithFragmentHandles = (childInstance: any); const eventListeners = fragmentInstance._eventListeners; if (eventListeners !== null) { for (let i = 0; i < eventListeners.length; i++) { const {type, listener, optionsOrUseCapture} = eventListeners[i]; - childInstance.addEventListener(type, listener, optionsOrUseCapture); + instance.addEventListener(type, listener, optionsOrUseCapture); } } if (fragmentInstance._observers !== null) { fragmentInstance._observers.forEach(observer => { - observer.observe(childInstance); + observer.observe(instance); }); } if (enableFragmentRefsInstanceHandles) { - addFragmentHandleToInstance(childInstance, fragmentInstance); + addFragmentHandleToInstance(instance, fragmentInstance); } } export function deleteChildFromFragmentInstance( - childInstance: InstanceWithFragmentHandles, + childInstance: InstanceWithFragmentHandles | Text, fragmentInstance: FragmentInstanceType, ): void { + if (childInstance.nodeType === TEXT_NODE) { + return; + } + const instance: InstanceWithFragmentHandles = (childInstance: any); const eventListeners = fragmentInstance._eventListeners; if (eventListeners !== null) { for (let i = 0; i < eventListeners.length; i++) { const {type, listener, optionsOrUseCapture} = eventListeners[i]; - childInstance.removeEventListener(type, listener, optionsOrUseCapture); + instance.removeEventListener(type, listener, optionsOrUseCapture); } } if (enableFragmentRefsInstanceHandles) { - if (childInstance.unstable_reactFragments != null) { - childInstance.unstable_reactFragments.delete(fragmentInstance); + if (instance.unstable_reactFragments != null) { + instance.unstable_reactFragments.delete(fragmentInstance); } } } diff --git a/packages/react-native-renderer/src/ReactFiberConfigFabric.js b/packages/react-native-renderer/src/ReactFiberConfigFabric.js index f5a4361fd41d..cc7f0d0c36a2 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigFabric.js +++ b/packages/react-native-renderer/src/ReactFiberConfigFabric.js @@ -40,7 +40,10 @@ import { type PublicTextInstance, type PublicRootInstance, } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; -import {enableFragmentRefsInstanceHandles} from 'shared/ReactFeatureFlags'; +import { + enableFragmentRefsInstanceHandles, + enableFragmentRefsTextNodes, +} from 'shared/ReactFeatureFlags'; const { createNode, @@ -847,10 +850,15 @@ export function updateFragmentInstanceFiber( } export function commitNewChildToFragmentInstance( - childInstance: Instance, + childInstance: Instance | TextInstance, fragmentInstance: FragmentInstanceType, ): void { - const publicInstance = getPublicInstance(childInstance); + // Text nodes are not observable + if (enableFragmentRefsTextNodes && childInstance.canonical == null) { + return; + } + const instance: Instance = (childInstance: any); + const publicInstance = getPublicInstance(instance); if (fragmentInstance._observers !== null) { if (publicInstance == null) { throw new Error('Expected to find a host node. This is a bug in React.'); @@ -869,11 +877,16 @@ export function commitNewChildToFragmentInstance( } export function deleteChildFromFragmentInstance( - childInstance: Instance, + childInstance: Instance | TextInstance, fragmentInstance: FragmentInstanceType, ): void { + // Text nodes are not observable + if (enableFragmentRefsTextNodes && childInstance.canonical == null) { + return; + } + const instance: Instance = (childInstance: any); const publicInstance = ((getPublicInstance( - childInstance, + instance, ): any): PublicInstanceWithFragmentHandles); if (enableFragmentRefsInstanceHandles) { if (publicInstance.unstable_reactFragments != null) { diff --git a/packages/react-reconciler/src/ReactFiberCommitHostEffects.js b/packages/react-reconciler/src/ReactFiberCommitHostEffects.js index 5c7ccf398787..3626561e1b49 100644 --- a/packages/react-reconciler/src/ReactFiberCommitHostEffects.js +++ b/packages/react-reconciler/src/ReactFiberCommitHostEffects.js @@ -64,7 +64,10 @@ import {captureCommitPhaseError} from './ReactFiberWorkLoop'; import {trackHostMutation} from './ReactFiberMutationTracking'; import {runWithFiberInDEV} from './ReactCurrentFiber'; -import {enableFragmentRefs} from 'shared/ReactFeatureFlags'; +import { + enableFragmentRefs, + enableFragmentRefsTextNodes, +} from 'shared/ReactFeatureFlags'; export function commitHostMount(finishedWork: Fiber) { const type = finishedWork.type; @@ -258,7 +261,8 @@ export function commitNewChildToFragmentInstances( parentFragmentInstances: null | Array, ): void { if ( - fiber.tag !== HostComponent || + (fiber.tag !== HostComponent && + !(enableFragmentRefsTextNodes && fiber.tag === HostText)) || // Only run fragment insertion effects for initial insertions fiber.alternate !== null || parentFragmentInstances === null diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 08882a04766c..199a4a873127 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -62,6 +62,7 @@ import { enableFragmentRefs, enableEagerAlternateStateNodeCleanup, enableDefaultTransitionIndicator, + enableFragmentRefsTextNodes, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -1533,7 +1534,11 @@ function commitDeletionEffectsOnFiber( if (!offscreenSubtreeWasHidden) { safelyDetachRef(deletedFiber, nearestMountedAncestor); } - if (enableFragmentRefs && deletedFiber.tag === HostComponent) { + if ( + enableFragmentRefs && + (deletedFiber.tag === HostComponent || + (enableFragmentRefsTextNodes && deletedFiber.tag === HostText)) + ) { commitFragmentInstanceDeletionEffects(deletedFiber); } // Intentional fallthrough to next branch @@ -3028,7 +3033,11 @@ export function disappearLayoutEffects(finishedWork: Fiber) { // TODO (Offscreen) Check: flags & RefStatic safelyDetachRef(finishedWork, finishedWork.return); - if (enableFragmentRefs && finishedWork.tag === HostComponent) { + if ( + enableFragmentRefs && + (finishedWork.tag === HostComponent || + (enableFragmentRefsTextNodes && finishedWork.tag === HostText)) + ) { commitFragmentInstanceDeletionEffects(finishedWork); } From cd515d7e22636238adef912356f522168946313d Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 11 Feb 2026 10:03:36 -0500 Subject: [PATCH 2/4] Minor DOM FragmentInstance refactors (#35641) Handles TODOs, small follow up refactors --- .../src/client/ReactFiberConfigDOM.js | 70 ++++++++++++------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 5b2d1e09fc09..94d37cfc902d 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3056,13 +3056,16 @@ function indexOfEventListener( listener: EventListener, optionsOrUseCapture: void | EventListenerOptionsOrUseCapture, ): number { + if (eventListeners.length === 0) { + return -1; + } + const normalizedOptions = normalizeListenerOptions(optionsOrUseCapture); for (let i = 0; i < eventListeners.length; i++) { const item = eventListeners[i]; if ( item.type === type && item.listener === listener && - normalizeListenerOptions(item.optionsOrUseCapture) === - normalizeListenerOptions(optionsOrUseCapture) + normalizeListenerOptions(item.optionsOrUseCapture) === normalizedOptions ) { return i; } @@ -3154,18 +3157,34 @@ function collectChildren(child: Fiber, collection: Array): boolean { } // $FlowFixMe[prop-missing] FragmentInstance.prototype.blur = function (this: FragmentInstanceType): void { - // TODO: When we have a parent element reference, we can skip traversal if the fragment's parent - // does not contain document.activeElement + // Early exit if activeElement is not within the fragment's parent + const parentHostFiber = getFragmentParentHostFiber(this._fragmentFiber); + if (parentHostFiber === null) { + return; + } + const parentHostInstance = + getInstanceFromHostFiber(parentHostFiber); + const activeElement = parentHostInstance.ownerDocument.activeElement; + if (activeElement === null || !parentHostInstance.contains(activeElement)) { + return; + } + traverseFragmentInstance( this._fragmentFiber, blurActiveElementWithinFragment, + activeElement, ); }; -function blurActiveElementWithinFragment(child: Fiber): boolean { - // TODO: We can get the activeElement from the parent outside of the loop when we have a reference. +function blurActiveElementWithinFragment( + child: Fiber, + activeElement: Element, +): boolean { + // Skip text nodes - they can't be focused + if (enableFragmentRefsTextNodes && child.tag === HostText) { + return false; + } const instance = getInstanceFromHostFiber(child); - const ownerDocument = instance.ownerDocument; - if (instance === ownerDocument.activeElement) { + if (instance === activeElement) { // $FlowFixMe[prop-missing] instance.blur(); return true; @@ -3312,46 +3331,45 @@ FragmentInstance.prototype.compareDocumentPosition = function ( ); } - const firstElement = getInstanceFromHostFiber(children[0]); - const lastElement = getInstanceFromHostFiber( + const firstNode = getInstanceFromHostFiber(children[0]); + const lastNode = getInstanceFromHostFiber( children[children.length - 1], ); // If the fragment has been portaled into another host instance, we need to // our best guess is to use the parent of the child instance, rather than // the fiber tree host parent. - const firstInstance = getInstanceFromHostFiber(children[0]); const parentHostInstanceFromDOM = fiberIsPortaledIntoHost(this._fragmentFiber) - ? (firstInstance.parentElement: ?Instance) + ? (firstNode.parentElement: ?Instance) : parentHostInstance; if (parentHostInstanceFromDOM == null) { return Node.DOCUMENT_POSITION_DISCONNECTED; } - // Check if first and last element are actually in the expected document position - // before relying on them as source of truth for other contained elements - const firstElementIsContained = - parentHostInstanceFromDOM.compareDocumentPosition(firstElement) & + // Check if first and last node are actually in the expected document position + // before relying on them as source of truth for other contained nodes + const firstNodeIsContained = + parentHostInstanceFromDOM.compareDocumentPosition(firstNode) & Node.DOCUMENT_POSITION_CONTAINED_BY; - const lastElementIsContained = - parentHostInstanceFromDOM.compareDocumentPosition(lastElement) & + const lastNodeIsContained = + parentHostInstanceFromDOM.compareDocumentPosition(lastNode) & Node.DOCUMENT_POSITION_CONTAINED_BY; - const firstResult = firstElement.compareDocumentPosition(otherNode); - const lastResult = lastElement.compareDocumentPosition(otherNode); + const firstResult = firstNode.compareDocumentPosition(otherNode); + const lastResult = lastNode.compareDocumentPosition(otherNode); const otherNodeIsFirstOrLastChild = - (firstElementIsContained && firstElement === otherNode) || - (lastElementIsContained && lastElement === otherNode); + (firstNodeIsContained && firstNode === otherNode) || + (lastNodeIsContained && lastNode === otherNode); const otherNodeIsFirstOrLastChildDisconnected = - (!firstElementIsContained && firstElement === otherNode) || - (!lastElementIsContained && lastElement === otherNode); + (!firstNodeIsContained && firstNode === otherNode) || + (!lastNodeIsContained && lastNode === otherNode); const otherNodeIsWithinFirstOrLastChild = firstResult & Node.DOCUMENT_POSITION_CONTAINED_BY || lastResult & Node.DOCUMENT_POSITION_CONTAINED_BY; const otherNodeIsBetweenFirstAndLastChildren = - firstElementIsContained && - lastElementIsContained && + firstNodeIsContained && + lastNodeIsContained && firstResult & Node.DOCUMENT_POSITION_FOLLOWING && lastResult & Node.DOCUMENT_POSITION_PRECEDING; From 892c68605c46af0558cdd546782f23ad120ad0d4 Mon Sep 17 00:00:00 2001 From: Ricky Date: Wed, 11 Feb 2026 11:20:51 -0500 Subject: [PATCH 3/4] [fiber] bugfix - don't show in error message. (#35763) ## Overview While building the RSC sandboxes I notice error messages like: > An error occurred in the `` component This is an internal component so it should show either: > An error occurred in the `` component. > An error occurred in the `` component. It should only happen when there's a lazy in the direct child position of a `` or `` component. --- .../ReactIncrementalErrorLogging-test.js | 61 +++++++++++++++++++ .../src/getComponentNameFromFiber.js | 5 +- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js index 3dde9c75bf03..f759fc60ef35 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js @@ -213,6 +213,67 @@ describe('ReactIncrementalErrorLogging', () => { }).toThrow('logCapturedError error'); }); + it('does not report internal Offscreen component for errors thrown during reconciliation inside Suspense', async () => { + // When a child of Suspense throws during reconciliation (not render), + // a Throw fiber is created whose .return is the internal Offscreen fiber. + // We should skip Offscreen since it's an internal + // implementation detail and walk up to Suspense instead. + const lazyChild = React.lazy(() => { + throw new Error('lazy init error'); + }); + + await fakeAct(() => { + ReactNoop.render( + }>{lazyChild}, + ); + }); + expect(uncaughtExceptionMock).toHaveBeenCalledTimes(1); + expect(uncaughtExceptionMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: 'lazy init error', + }), + ); + if (__DEV__) { + expect(console.warn).toHaveBeenCalledTimes(1); + expect(console.warn.mock.calls[0]).toEqual([ + '%s\n\n%s\n', + 'An error occurred in the component.', + 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.', + ]); + } + }); + + it('does not report internal Offscreen component for errors thrown during reconciliation inside Activity', async () => { + // Same as the Suspense test above — Activity also wraps its children in + // an internal Offscreen fiber. The error message should show Activity, + // not Offscreen. + const lazyChild = React.lazy(() => { + throw new Error('lazy init error'); + }); + + await fakeAct(() => { + ReactNoop.render( + {lazyChild}, + ); + }); + expect(uncaughtExceptionMock).toHaveBeenCalledTimes(1); + expect(uncaughtExceptionMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: 'lazy init error', + }), + ); + if (__DEV__) { + expect(console.warn).toHaveBeenCalledTimes(1); + expect(console.warn.mock.calls[0]).toEqual([ + '%s\n\n%s\n', + 'An error occurred in the component.', + 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.', + ]); + } + }); + it('resets instance variables before unmounting failed node', async () => { class ErrorBoundary extends React.Component { state = {error: null}; diff --git a/packages/react-reconciler/src/getComponentNameFromFiber.js b/packages/react-reconciler/src/getComponentNameFromFiber.js index 97124bbf5ba5..8719539cfc08 100644 --- a/packages/react-reconciler/src/getComponentNameFromFiber.js +++ b/packages/react-reconciler/src/getComponentNameFromFiber.js @@ -122,7 +122,10 @@ export default function getComponentNameFromFiber(fiber: Fiber): string | null { } return 'Mode'; case OffscreenComponent: - return 'Offscreen'; + if (fiber.return !== null) { + return getComponentNameFromFiber(fiber.return); + } + return null; case Profiler: return 'Profiler'; case ScopeComponent: From 8374c2abf13fa803233025192b8d7e87de70b087 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin <28902667+hoxyq@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:59:43 +0000 Subject: [PATCH 4/4] [DevTools] Remove experimental __IS_INTERNAL_MCP_BUILD__ flag and related code (#35755) This is unused. --- .eslintrc.js | 1 - .../react-devtools-core/webpack.backend.js | 1 - .../react-devtools-core/webpack.standalone.js | 1 - .../webpack.config.js | 6 -- .../webpack.config.frontend.js | 1 - .../react-devtools-inline/webpack.config.js | 1 - .../src/backend/fiber/renderer.js | 81 ------------------- scripts/flow/react-devtools.js | 1 - scripts/jest/devtools/setupEnv.js | 1 - 9 files changed, 94 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 952149f30ca7..2cebe8698c7c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -507,7 +507,6 @@ module.exports = { __IS_FIREFOX__: 'readonly', __IS_EDGE__: 'readonly', __IS_NATIVE__: 'readonly', - __IS_INTERNAL_MCP_BUILD__: 'readonly', __IS_INTERNAL_VERSION__: 'readonly', chrome: 'readonly', }, diff --git a/packages/react-devtools-core/webpack.backend.js b/packages/react-devtools-core/webpack.backend.js index c1312fc6d8ec..32d4fadcb588 100644 --- a/packages/react-devtools-core/webpack.backend.js +++ b/packages/react-devtools-core/webpack.backend.js @@ -72,7 +72,6 @@ module.exports = { __IS_CHROME__: false, __IS_EDGE__: false, __IS_NATIVE__: true, - __IS_INTERNAL_MCP_BUILD__: false, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-core"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, diff --git a/packages/react-devtools-core/webpack.standalone.js b/packages/react-devtools-core/webpack.standalone.js index 6279ba7fb349..01437e7f0fb7 100644 --- a/packages/react-devtools-core/webpack.standalone.js +++ b/packages/react-devtools-core/webpack.standalone.js @@ -91,7 +91,6 @@ module.exports = { __IS_FIREFOX__: false, __IS_CHROME__: false, __IS_EDGE__: false, - __IS_INTERNAL_MCP_BUILD__: false, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-core"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null, diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js index 7b5acca6cc28..129816e90749 100644 --- a/packages/react-devtools-extensions/webpack.config.js +++ b/packages/react-devtools-extensions/webpack.config.js @@ -34,8 +34,6 @@ const IS_FIREFOX = process.env.IS_FIREFOX === 'true'; const IS_EDGE = process.env.IS_EDGE === 'true'; const IS_INTERNAL_VERSION = process.env.FEATURE_FLAG_TARGET === 'extension-fb'; -const IS_INTERNAL_MCP_BUILD = process.env.IS_INTERNAL_MCP_BUILD === 'true'; - const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss'; let statsFileName = `webpack-stats.${featureFlagTarget}.${__DEV__ ? 'development' : 'production'}`; @@ -48,9 +46,6 @@ if (IS_FIREFOX) { if (IS_EDGE) { statsFileName += `.edge`; } -if (IS_INTERNAL_MCP_BUILD) { - statsFileName += `.mcp`; -} statsFileName += '.json'; const babelOptions = { @@ -139,7 +134,6 @@ module.exports = { __IS_FIREFOX__: IS_FIREFOX, __IS_EDGE__: IS_EDGE, __IS_NATIVE__: false, - __IS_INTERNAL_MCP_BUILD__: IS_INTERNAL_MCP_BUILD, __IS_INTERNAL_VERSION__: IS_INTERNAL_VERSION, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-extensions"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, diff --git a/packages/react-devtools-fusebox/webpack.config.frontend.js b/packages/react-devtools-fusebox/webpack.config.frontend.js index 0d56e81a34b6..a2e09f0e0adb 100644 --- a/packages/react-devtools-fusebox/webpack.config.frontend.js +++ b/packages/react-devtools-fusebox/webpack.config.frontend.js @@ -85,7 +85,6 @@ module.exports = { __IS_CHROME__: false, __IS_FIREFOX__: false, __IS_EDGE__: false, - __IS_INTERNAL_MCP_BUILD__: false, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-fusebox"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null, diff --git a/packages/react-devtools-inline/webpack.config.js b/packages/react-devtools-inline/webpack.config.js index a0300069bfa2..f2b5fd8a6f41 100644 --- a/packages/react-devtools-inline/webpack.config.js +++ b/packages/react-devtools-inline/webpack.config.js @@ -77,7 +77,6 @@ module.exports = { __IS_FIREFOX__: false, __IS_EDGE__: false, __IS_NATIVE__: false, - __IS_INTERNAL_MCP_BUILD__: false, 'process.env.DEVTOOLS_PACKAGE': `"react-devtools-inline"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null, diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 7a01d6c5984a..266346a6bbe7 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -8871,86 +8871,6 @@ export function attach( return unresolvedSource; } - type InternalMcpFunctions = { - __internal_only_getComponentTree?: Function, - }; - - const internalMcpFunctions: InternalMcpFunctions = {}; - if (__IS_INTERNAL_MCP_BUILD__) { - // eslint-disable-next-line no-inner-declarations - function __internal_only_getComponentTree(): string { - let treeString = ''; - - function buildTreeString( - instance: DevToolsInstance, - prefix: string = '', - isLastChild: boolean = true, - ): void { - if (!instance) return; - - const name = - (instance.kind !== VIRTUAL_INSTANCE - ? getDisplayNameForFiber(instance.data) - : instance.data.name) || 'Unknown'; - - const id = instance.id !== undefined ? instance.id : 'unknown'; - - if (name !== 'createRoot()') { - treeString += - prefix + - (isLastChild ? '└── ' : '├── ') + - name + - ' (id: ' + - id + - ')\n'; - } - - const childPrefix = prefix + (isLastChild ? ' ' : '│ '); - - let childCount = 0; - let tempChild = instance.firstChild; - while (tempChild !== null) { - childCount++; - tempChild = tempChild.nextSibling; - } - - let child = instance.firstChild; - let currentChildIndex = 0; - - while (child !== null) { - currentChildIndex++; - const isLastSibling = currentChildIndex === childCount; - buildTreeString(child, childPrefix, isLastSibling); - child = child.nextSibling; - } - } - - const rootInstances: Array = []; - idToDevToolsInstanceMap.forEach(instance => { - if (instance.parent === null || instance.parent.parent === null) { - rootInstances.push(instance); - } - }); - - if (rootInstances.length > 0) { - for (let i = 0; i < rootInstances.length; i++) { - const isLast = i === rootInstances.length - 1; - buildTreeString(rootInstances[i], '', isLast); - if (!isLast) { - treeString += '\n'; - } - } - } else { - treeString = 'No component tree found.'; - } - - return treeString; - } - - internalMcpFunctions.__internal_only_getComponentTree = - __internal_only_getComponentTree; - } - return { cleanup, clearErrorsAndWarnings, @@ -8994,6 +8914,5 @@ export function attach( supportsTogglingSuspense, updateComponentFilters, getEnvironmentNames, - ...internalMcpFunctions, }; } diff --git a/scripts/flow/react-devtools.js b/scripts/flow/react-devtools.js index 09a251bbe2f5..4e0f2a915ede 100644 --- a/scripts/flow/react-devtools.js +++ b/scripts/flow/react-devtools.js @@ -16,6 +16,5 @@ declare const __IS_FIREFOX__: boolean; declare const __IS_CHROME__: boolean; declare const __IS_EDGE__: boolean; declare const __IS_NATIVE__: boolean; -declare const __IS_INTERNAL_MCP_BUILD__: boolean; declare const chrome: any; diff --git a/scripts/jest/devtools/setupEnv.js b/scripts/jest/devtools/setupEnv.js index 32bf13e686c7..a797c0951435 100644 --- a/scripts/jest/devtools/setupEnv.js +++ b/scripts/jest/devtools/setupEnv.js @@ -15,7 +15,6 @@ global.__IS_FIREFOX__ = false; global.__IS_CHROME__ = false; global.__IS_EDGE__ = false; global.__IS_NATIVE__ = false; -global.__IS_INTERNAL_MCP_BUILD__ = false; const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion;