Skip to content

Commit 447d80e

Browse files
rubennortefacebook-github-bot
authored andcommitted
Implement tagName property in ReadOnlyElement (#39278)
Summary: Pull Request resolved: #39278 Implements tagName as the name of the component prefixed with `RN:`. Changelog: [internal] Reviewed By: NickGerleman Differential Revision: D48951824 fbshipit-source-id: 4a8387adff8ed504423d7ead7b95943bfd77ae8c
1 parent cbf3b7d commit 447d80e

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

packages/react-native/Libraries/DOM/Nodes/ReadOnlyElement.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,13 @@ export default class ReadOnlyElement extends ReadOnlyNode {
137137
}
138138

139139
get tagName(): string {
140-
throw new TypeError('Unimplemented');
140+
const node = getShadowNode(this);
141+
142+
if (node != null) {
143+
return nullthrows(getFabricUIManager()).getTagName(node);
144+
}
145+
146+
return '';
141147
}
142148

143149
get textContent(): string | null {

packages/react-native/Libraries/ReactNative/FabricUIManager.js

+5
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export interface Spec {
9191
+getScrollPosition: (
9292
node: Node,
9393
) => ?[/* scrollLeft: */ number, /* scrollTop: */ number];
94+
+getTagName: (node: Node) => string;
9495

9596
/**
9697
* Support methods for the Pointer Capture APIs.
@@ -131,6 +132,10 @@ const CACHED_PROPERTIES = [
131132
'getBoundingClientRect',
132133
'getOffset',
133134
'getScrollPosition',
135+
'getTagName',
136+
'hasPointerCapture',
137+
'setPointerCapture',
138+
'releasePointerCapture',
134139
];
135140

136141
// This is exposed as a getter because apps using the legacy renderer AND

packages/react-native/Libraries/ReactNative/__mocks__/FabricUIManager.js

+5
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,11 @@ const FabricUIManagerMock: IFabricUIManagerMock = {
497497
},
498498
),
499499

500+
getTagName: jest.fn((node: Node): string => {
501+
ensureHostNode(node);
502+
return 'RN:' + fromNode(node).viewName;
503+
}),
504+
500505
__getInstanceHandleFromNode(node: Node): InternalInstanceHandle {
501506
return fromNode(node).instanceHandle;
502507
},

packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,43 @@ jsi::Value UIManagerBinding::get(
12071207
});
12081208
}
12091209

1210+
if (methodName == "getTagName") {
1211+
// This is a method to access the normalized tag name of a shadow node, to
1212+
// implement `Element.prototype.tagName` (see
1213+
// https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName).
1214+
1215+
// getTagName(shadowNode: ShadowNode): string
1216+
auto paramCount = 1;
1217+
return jsi::Function::createFromHostFunction(
1218+
runtime,
1219+
name,
1220+
paramCount,
1221+
[methodName, paramCount](
1222+
jsi::Runtime& runtime,
1223+
const jsi::Value& /*thisValue*/,
1224+
const jsi::Value* arguments,
1225+
size_t count) -> jsi::Value {
1226+
validateArgumentCount(runtime, methodName, paramCount, count);
1227+
1228+
auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
1229+
1230+
std::string canonicalComponentName = shadowNode->getComponentName();
1231+
1232+
// FIXME(T162807327): Remove Android-specific prefixes and unify
1233+
// shadow node implementations
1234+
if (canonicalComponentName == "AndroidTextInput") {
1235+
canonicalComponentName = "TextInput";
1236+
} else if (canonicalComponentName == "AndroidSwitch") {
1237+
canonicalComponentName = "Switch";
1238+
}
1239+
1240+
// Prefix with RN:
1241+
canonicalComponentName.insert(0, "RN:");
1242+
1243+
return jsi::String::createFromUtf8(runtime, canonicalComponentName);
1244+
});
1245+
}
1246+
12101247
/**
12111248
* Pointer Capture APIs
12121249
*/

0 commit comments

Comments
 (0)