Skip to content

Commit 45ba042

Browse files
dmytrorykunlunaleaps
authored andcommitted
Event name normalization (#42586)
Summary: Pull Request resolved: #42586 Every event name must be normalized. The normalization strategy is: 1. If it starts with `top` -> do nothing. 2. If it starts with `on` -> replace `on` with `top`. 3. Else -> capitalize the first character and prepend `top`. We have it for the old renderer on iOS [here](https://github.com/facebook/react-native/blob/a7586947d719a9cd2344ad346d271e7ca900de87/packages/react-native/React/Base/RCTEventDispatcher.m#L12-L21). This one is also used by the interop layer. Static ViewConfigs being a part of the new renderer [replicate](https://github.com/facebook/react-native/blob/a7586947d719a9cd2344ad346d271e7ca900de87/packages/react-native-codegen/src/generators/components/GenerateViewConfigJs.js#L164-L172) this behavior to match the old rendered. The Android that we have is incomplete, it is missing the [*2. If it starts with `on` -> replace `on` with `top`*]. This means that some events names that worked with the old renderer would not be compatible with the new renderer + Static ViewConfigs. Specifically every event names that start with `on`. This diff implements event name normalization on Android. Changelog: [Internal] - Update event normalization algorithm to match SVCs. Reviewed By: cortinico Differential Revision: D50604571 fbshipit-source-id: cef34d8baa2cf31f641be423a16bca7ea9fa20c4
1 parent 0d2c505 commit 45ba042

File tree

6 files changed

+35
-19
lines changed

6 files changed

+35
-19
lines changed

packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GenerateViewConfigJs-test.js.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export const __INTERNAL_VIEW_CONFIG = {
294294
uiViewClassName: 'EventPropsNativeComponentView',
295295
296296
bubblingEventTypes: {
297-
paperDirectName: {
297+
topPaperDirectName: {
298298
phasedRegistrationNames: {
299299
captured: 'onChangeCapture',
300300
bubbled: 'onChange',
@@ -308,7 +308,7 @@ export const __INTERNAL_VIEW_CONFIG = {
308308
},
309309
},
310310
311-
paperBubblingName: {
311+
topPaperBubblingName: {
312312
phasedRegistrationNames: {
313313
captured: 'onEventBubblingWithPaperNameCapture',
314314
bubbled: 'onEventBubblingWithPaperName',
@@ -321,11 +321,11 @@ export const __INTERNAL_VIEW_CONFIG = {
321321
registrationName: 'onEventDirect',
322322
},
323323
324-
paperDirectName: {
324+
topPaperDirectName: {
325325
registrationName: 'onEventDirectWithPaperName',
326326
},
327327
328-
paperBubblingName: {
328+
topPaperBubblingName: {
329329
registrationName: 'onOrientationChange',
330330
},
331331
},

packages/react-native-codegen/src/generators/components/GenerateViewConfigJs.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ function generateBubblingEventInfo(
197197
) {
198198
return j.property(
199199
'init',
200-
j.identifier(nameOveride || normalizeInputEventName(event.name)),
200+
j.identifier(normalizeInputEventName(nameOveride || event.name)),
201201
j.objectExpression([
202202
j.property(
203203
'init',
@@ -221,7 +221,7 @@ function generateDirectEventInfo(
221221
) {
222222
return j.property(
223223
'init',
224-
j.identifier(nameOveride || normalizeInputEventName(event.name)),
224+
j.identifier(normalizeInputEventName(nameOveride || event.name)),
225225
j.objectExpression([
226226
j.property(
227227
'init',

packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ export const __INTERNAL_VIEW_CONFIG = {
468468
uiViewClassName: 'RCTInterfaceOnlyComponent',
469469
470470
bubblingEventTypes: {
471-
paperChange: {
471+
topPaperChange: {
472472
phasedRegistrationNames: {
473473
captured: 'onChangeCapture',
474474
bubbled: 'onChange',
@@ -477,7 +477,7 @@ export const __INTERNAL_VIEW_CONFIG = {
477477
},
478478
479479
directEventTypes: {
480-
paperDirectChange: {
480+
topPaperDirectChange: {
481481
registrationName: 'onDirectChange',
482482
},
483483
},

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,15 @@ private static void validateDirectEventNames(
206206
}
207207
for (String oldKey : keysToNormalize) {
208208
Object value = events.get(oldKey);
209-
String newKey = "top" + oldKey.substring(0, 1).toUpperCase() + oldKey.substring(1);
209+
String baseKey = "";
210+
if (oldKey.startsWith("on")) {
211+
// Drop "on" prefix.
212+
baseKey = oldKey.substring(2);
213+
} else {
214+
// Capitalize first letter.
215+
baseKey = oldKey.substring(0, 1).toUpperCase() + oldKey.substring(1);
216+
}
217+
String newKey = "top" + baseKey;
210218
events.put(newKey, value);
211219
}
212220
}

packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelperTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class UIManagerModuleConstantsHelperTest {
3232
val onClickMap: Map<String, String> =
3333
MapBuilder.builder<String, String>().put("onClick", "¯\\_(ツ)_/¯").build()
3434
UIManagerModuleConstantsHelper.normalizeEventTypes(onClickMap)
35-
assertTrue(onClickMap.containsKey("topOnClick"))
35+
assertTrue(onClickMap.containsKey("topClick"))
3636
assertTrue(onClickMap.containsKey("onClick"))
3737
}
3838

@@ -58,16 +58,16 @@ class UIManagerModuleConstantsHelperTest {
5858
"bubbled", "onColorChanged", "captured", "onColorChangedCapture")))
5959
.build()
6060
UIManagerModuleConstantsHelper.normalizeEventTypes(nestedObjects)
61-
assertTrue(nestedObjects.containsKey("topOnColorChanged"))
62-
var innerMap = nestedObjects["topOnColorChanged"] as? Map<String, Any?>
61+
assertTrue(nestedObjects.containsKey("topColorChanged"))
62+
var innerMap = nestedObjects["topColorChanged"] as? Map<String, Any?>
6363
assertNotNull(innerMap)
6464
assertTrue(innerMap!!.containsKey("phasedRegistrationNames"))
6565
var innerInnerMap = innerMap.get("phasedRegistrationNames") as? Map<String, Any?>
6666
assertNotNull(innerInnerMap)
6767
assertEquals("onColorChanged", innerInnerMap!!.get("bubbled"))
6868
assertEquals("onColorChangedCapture", innerInnerMap.get("captured"))
6969
assertTrue(nestedObjects.containsKey("onColorChanged"))
70-
innerMap = nestedObjects.get("topOnColorChanged") as? Map<String, Any?>
70+
innerMap = nestedObjects.get("topColorChanged") as? Map<String, Any?>
7171
assertNotNull(innerMap)
7272
assertTrue(innerMap!!.containsKey("phasedRegistrationNames"))
7373
innerInnerMap = innerMap.get("phasedRegistrationNames") as? Map<String, Any?>

packages/react-native/ReactCommon/react/renderer/core/EventEmitter.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,26 @@
1616

1717
namespace facebook::react {
1818

19+
static bool hasPrefix(const std::string& str, const std::string& prefix) {
20+
return str.compare(0, prefix.length(), prefix) == 0;
21+
}
22+
1923
// TODO(T29874519): Get rid of "top" prefix once and for all.
2024
/*
21-
* Capitalizes the first letter of the event type and adds "top" prefix if
22-
* necessary (e.g. "layout" becames "topLayout").
25+
* Replaces "on" with "top" if present. Or capitalizes the first letter and adds
26+
* "top" prefix. E.g. "eventName" becomes "topEventName", "onEventName" also
27+
* becomes "topEventName".
2328
*/
2429
static std::string normalizeEventType(std::string type) {
2530
auto prefixedType = std::move(type);
26-
if (prefixedType.find("top", 0) != 0) {
27-
prefixedType.insert(0, "top");
28-
prefixedType[3] = static_cast<char>(toupper(prefixedType[3]));
31+
if (facebook::react::hasPrefix(prefixedType, "top")) {
32+
return prefixedType;
33+
}
34+
if (facebook::react::hasPrefix(prefixedType, "on")) {
35+
return "top" + prefixedType.substr(2);
2936
}
30-
return prefixedType;
37+
prefixedType[0] = static_cast<char>(toupper(prefixedType[0]));
38+
return "top" + prefixedType;
3139
}
3240

3341
std::mutex& EventEmitter::DispatchMutex() {

0 commit comments

Comments
 (0)