From 03430ca660eb48239795f7812d20cfa84c1fd572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 13 Apr 2023 09:19:00 -0700 Subject: [PATCH] Implement node.isConnected Summary: This implements the `isConnected` method as defined in https://github.com/react-native-community/discussions-and-proposals/pull/607. This requires a new method in Fabric because we can't derive that from the existing methods. Changelog: [internal] bypass-github-export-checks Reviewed By: sammy-SC Differential Revision: D44346661 fbshipit-source-id: 1eefa589f2937d1dac2461350ddc8df006f0e873 --- .../Libraries/DOM/Nodes/ReadOnlyNode.js | 8 +++++- .../Libraries/ReactNative/FabricUIManager.js | 1 + .../ReactNative/__mocks__/FabricUIManager.js | 3 +++ .../renderer/uimanager/UIManagerBinding.cpp | 26 +++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) 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(); }