Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
Expand Down
1 change: 0 additions & 1 deletion packages/react-devtools-core/webpack.backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}"`,
Expand Down
1 change: 0 additions & 1 deletion packages/react-devtools-core/webpack.standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 0 additions & 6 deletions packages/react-devtools-extensions/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'}`;
Expand All @@ -48,9 +46,6 @@ if (IS_FIREFOX) {
if (IS_EDGE) {
statsFileName += `.edge`;
}
if (IS_INTERNAL_MCP_BUILD) {
statsFileName += `.mcp`;
}
statsFileName += '.json';

const babelOptions = {
Expand Down Expand Up @@ -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}"`,
Expand Down
1 change: 0 additions & 1 deletion packages/react-devtools-fusebox/webpack.config.frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion packages/react-devtools-inline/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
81 changes: 0 additions & 81 deletions packages/react-devtools-shared/src/backend/fiber/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<DevToolsInstance> = [];
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,
Expand Down Expand Up @@ -8994,6 +8914,5 @@ export function attach(
supportsTogglingSuspense,
updateComponentFilters,
getEnvironmentNames,
...internalMcpFunctions,
};
}
94 changes: 60 additions & 34 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -3154,18 +3157,34 @@ function collectChildren(child: Fiber, collection: Array<Fiber>): 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<Instance>(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<Instance>(child);
const ownerDocument = instance.ownerDocument;
if (instance === ownerDocument.activeElement) {
if (instance === activeElement) {
// $FlowFixMe[prop-missing]
instance.blur();
return true;
Expand Down Expand Up @@ -3312,46 +3331,45 @@ FragmentInstance.prototype.compareDocumentPosition = function (
);
}

const firstElement = getInstanceFromHostFiber<Instance>(children[0]);
const lastElement = getInstanceFromHostFiber<Instance>(
const firstNode = getInstanceFromHostFiber<Instance>(children[0]);
const lastNode = getInstanceFromHostFiber<Instance>(
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<Instance>(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;

Expand Down Expand Up @@ -3544,40 +3562,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);
}
}
}
Expand Down
23 changes: 18 additions & 5 deletions packages/react-native-renderer/src/ReactFiberConfigFabric.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.');
Expand All @@ -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) {
Expand Down
Loading
Loading