diff --git a/packages/react-native/Libraries/DOM/Nodes/ReadOnlyNode.js b/packages/react-native/Libraries/DOM/Nodes/ReadOnlyNode.js index 40cc988b2a2..e7e0192c83a 100644 --- a/packages/react-native/Libraries/DOM/Nodes/ReadOnlyNode.js +++ b/packages/react-native/Libraries/DOM/Nodes/ReadOnlyNode.js @@ -47,7 +47,13 @@ export default class ReadOnlyNode { } get isConnected(): boolean { - throw new TypeError('Unimplemented'); + const shadowNode = getShadowNode(this); + + if (shadowNode == null) { + return false; + } + + return nullthrows(getFabricUIManager()).isConnected(shadowNode); } get lastChild(): ReadOnlyNode | null { diff --git a/packages/react-native/Libraries/ReactNative/FabricUIManager.js b/packages/react-native/Libraries/ReactNative/FabricUIManager.js index ac1d9c98648..23ae2a53d7c 100644 --- a/packages/react-native/Libraries/ReactNative/FabricUIManager.js +++ b/packages/react-native/Libraries/ReactNative/FabricUIManager.js @@ -72,6 +72,7 @@ export type Spec = {| ) => void, +getParentNode: (node: Node) => ?InternalInstanceHandle, +getChildNodes: (node: Node) => $ReadOnlyArray, + +isConnected: (node: Node) => boolean, |}; // This is exposed as a getter because apps using the legacy renderer AND diff --git a/packages/react-native/Libraries/ReactNative/__mocks__/FabricUIManager.js b/packages/react-native/Libraries/ReactNative/__mocks__/FabricUIManager.js index bf722637a8f..5e75910d060 100644 --- a/packages/react-native/Libraries/ReactNative/__mocks__/FabricUIManager.js +++ b/packages/react-native/Libraries/ReactNative/__mocks__/FabricUIManager.js @@ -285,6 +285,9 @@ const FabricUIManagerMock: FabricUIManager = { ); }, ), + isConnected: jest.fn((node: Node): boolean => { + return getNodeInCurrentTree(node) != null; + }), }; global.nativeFabricUIManager = FabricUIManagerMock; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index aefe552fb20..b328b8fa20c 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -836,6 +836,32 @@ jsi::Value UIManagerBinding::get( }); } + if (methodName == "isConnected") { + // This is a React Native implementation of `Node.prototype.isConnected` + // (see https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected). + + // Indicates whether a version of the given shadow node is present in + // the current revision of an active shadow tree. + + // isConnected(shadowNode: ShadowNode): boolean + return jsi::Function::createFromHostFunction( + runtime, + name, + 1, + [uiManager]( + jsi::Runtime &runtime, + jsi::Value const & /*thisValue*/, + jsi::Value const *arguments, + size_t /*count*/) noexcept -> jsi::Value { + auto shadowNode = shadowNodeFromValue(runtime, arguments[0]); + + auto newestCloneOfShadowNode = + uiManager->getNewestCloneOfShadowNode(*shadowNode); + + return jsi::Value(newestCloneOfShadowNode != nullptr); + }); + } + return jsi::Value::undefined(); }