react-native 0.72.0-rc.1 → 0.72.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/Libraries/Components/View/ReactNativeStyleAttributes.js +0 -7
  2. package/Libraries/Core/ReactNativeVersion.js +1 -1
  3. package/Libraries/NativeComponent/BaseViewConfig.android.js +0 -8
  4. package/Libraries/NativeComponent/BaseViewConfig.ios.js +0 -8
  5. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +0 -7
  6. package/Libraries/StyleSheet/StyleSheetTypes.js +0 -74
  7. package/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m +3 -3
  8. package/React/Base/RCTVersion.m +1 -1
  9. package/React/CoreModules/RCTDevMenu.mm +3 -3
  10. package/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +12 -1
  11. package/React/Fabric/RCTSurfacePresenter.mm +4 -0
  12. package/ReactAndroid/gradle.properties +1 -1
  13. package/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +10 -0
  14. package/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +29 -0
  15. package/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java +25 -2
  16. package/ReactAndroid/src/main/java/com/facebook/react/bridge/interop/InteropModuleRegistry.java +56 -0
  17. package/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +8 -0
  18. package/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt +1 -0
  19. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java +26 -8
  20. package/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +21 -0
  21. package/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEvent.java +41 -0
  22. package/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEventEmitter.java +65 -0
  23. package/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java +9 -0
  24. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
  25. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java +1 -0
  26. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +32 -0
  27. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java +19 -0
  28. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  29. package/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +0 -21
  30. package/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp +0 -49
  31. package/ReactCommon/react/renderer/components/view/YogaStylableProps.h +0 -9
  32. package/ReactCommon/react/renderer/core/CoreFeatures.cpp +1 -0
  33. package/ReactCommon/react/renderer/core/CoreFeatures.h +4 -0
  34. package/ReactCommon/react/renderer/imagemanager/ImageRequest.h +7 -3
  35. package/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp +0 -11
  36. package/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp +4 -14
  37. package/package.json +9 -9
  38. package/scripts/cocoapods/__tests__/flipper-test.rb +9 -1
  39. package/scripts/cocoapods/__tests__/jsengine-test.rb +6 -2
  40. package/scripts/cocoapods/__tests__/test_utils/podSpy.rb +2 -1
  41. package/scripts/cocoapods/__tests__/utils-test.rb +0 -68
  42. package/scripts/cocoapods/flipper.rb +2 -2
  43. package/scripts/cocoapods/jsengine.rb +6 -1
  44. package/scripts/cocoapods/utils.rb +0 -7
  45. package/scripts/react_native_pods.rb +3 -6
  46. package/sdks/hermesc/linux64-bin/hermesc +0 -0
  47. package/sdks/hermesc/osx-bin/hermesc +0 -0
  48. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  49. package/template/android/app/build.gradle +7 -2
  50. package/template/package.json +5 -5
  51. package/types/index.d.ts +4 -0
@@ -46,13 +46,6 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
46
46
  flexWrap: true,
47
47
  gap: true,
48
48
  height: true,
49
- inset: true,
50
- insetBlock: true,
51
- insetBlockEnd: true,
52
- insetBlockStart: true,
53
- insetInline: true,
54
- insetInlineEnd: true,
55
- insetInlineStart: true,
56
49
  justifyContent: true,
57
50
  left: true,
58
51
  margin: true,
@@ -13,5 +13,5 @@ exports.version = {
13
13
  major: 0,
14
14
  minor: 72,
15
15
  patch: 0,
16
- prerelease: 'rc.1',
16
+ prerelease: 'rc.3',
17
17
  };
@@ -258,14 +258,6 @@ const validAttributesForNonEventProps = {
258
258
  top: true,
259
259
  bottom: true,
260
260
 
261
- inset: true,
262
- insetBlock: true,
263
- insetBlockEnd: true,
264
- insetBlockStart: true,
265
- insetInline: true,
266
- insetInlineEnd: true,
267
- insetInlineStart: true,
268
-
269
261
  position: true,
270
262
 
271
263
  style: ReactNativeStyleAttributes,
@@ -236,14 +236,6 @@ const validAttributesForNonEventProps = {
236
236
  bottom: true,
237
237
  left: true,
238
238
 
239
- inset: true,
240
- insetBlock: true,
241
- insetBlockEnd: true,
242
- insetBlockStart: true,
243
- insetInline: true,
244
- insetInlineEnd: true,
245
- insetInlineStart: true,
246
-
247
239
  width: true,
248
240
  height: true,
249
241
 
@@ -69,13 +69,6 @@ export interface FlexStyle {
69
69
  flexShrink?: number | undefined;
70
70
  flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse' | undefined;
71
71
  height?: DimensionValue | undefined;
72
- inset?: DimensionValue | undefined;
73
- insetBlock?: DimensionValue | undefined;
74
- insetBlockEnd?: DimensionValue | undefined;
75
- insetBlockStart?: DimensionValue | undefined;
76
- insetInline?: DimensionValue | undefined;
77
- insetInlineEnd?: DimensionValue | undefined;
78
- insetInlineStart?: DimensionValue | undefined;
79
72
  justifyContent?:
80
73
  | 'flex-start'
81
74
  | 'flex-end'
@@ -134,80 +134,6 @@ type ____LayoutStyle_Internal = $ReadOnly<{
134
134
  */
135
135
  top?: DimensionValue,
136
136
 
137
- /** `inset` is a shorthand that corresponds to the top, right, bottom, and/or left properties.
138
- *
139
- * It works similarly to `inset` in CSS, but in React Native you
140
- * must use points or percentages. Ems and other units are not supported.
141
- *
142
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset
143
- * for more details of how `inset` affects layout.
144
- */
145
- inset?: DimensionValue,
146
-
147
- /** `insetBlock` is a shorthand that corresponds to the `insetBlockStart` and `insetBlockEnd` properties.
148
- *
149
- * It works similarly to `inset-block` in CSS, but in React Native you
150
- * must use points or percentages. Ems and other units are not supported.
151
- *
152
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset-block
153
- * for more details of how `inset-block` affects layout.
154
- */
155
- insetBlock?: DimensionValue,
156
-
157
- /** `insetBlockEnd` is a logical property that sets the length that an
158
- * element is offset in the block direction from its ending edge.
159
- *
160
- * It works similarly to `inset-block-end` in CSS, but in React Native you
161
- * must use points or percentages. Ems and other units are not supported.
162
- *
163
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset-block-end
164
- * for more details of how `inset-block-end` affects layout.
165
- */
166
- insetBlockEnd?: DimensionValue,
167
-
168
- /** `insetBlockStart` is a logical property that sets the length that an
169
- * element is offset in the block direction from its starting edge.
170
- *
171
- * It works similarly to `inset-block-start` in CSS, but in React Native you
172
- * must use points or percentages. Ems and other units are not supported.
173
- *
174
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset-block-start
175
- * for more details of how `inset-block-start` affects layout.
176
- */
177
- insetBlockStart?: DimensionValue,
178
-
179
- /** `insetInline` is a shorthand that corresponds to the `insetInlineStart` and `insetInlineEnd` properties.
180
- *
181
- * It works similarly to `inset-inline` in CSS, but in React Native you
182
- * must use points or percentages. Ems and other units are not supported.
183
- *
184
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline
185
- * for more details of how `inset-inline` affects layout.
186
- */
187
- insetInline?: DimensionValue,
188
-
189
- /** `insetInlineEnd` is a logical property that sets the length that an
190
- * element is offset in the starting inline direction.
191
- *
192
- * It works similarly to `inset-inline-end` in CSS, but in React Native you
193
- * must use points or percentages. Ems and other units are not supported.
194
- *
195
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-end
196
- * for more details of how `inset-inline-end` affects layout.
197
- */
198
- insetInlineEnd?: DimensionValue,
199
-
200
- /** `insetInlineStart` is a logical property that sets the length that an
201
- * element is offset in the starting inline direction.
202
- *
203
- * It works similarly to `inset-inline-start` in CSS, but in React Native you
204
- * must use points or percentages. Ems and other units are not supported.
205
- *
206
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-start
207
- * for more details of how `inset-inline-start` affects layout.
208
- */
209
- insetInlineStart?: DimensionValue,
210
-
211
137
  /** `minWidth` is the minimum width for this component, in logical pixels.
212
138
  *
213
139
  * It works similarly to `min-width` in CSS, but in React Native you
@@ -256,21 +256,21 @@ static void *TextFieldSelectionObservingContext = &TextFieldSelectionObservingCo
256
256
 
257
257
  - (void)textViewDidChange:(__unused UITextView *)textView
258
258
  {
259
- if (_ignoreNextTextInputCall && [_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
259
+ if (_ignoreNextTextInputCall) {
260
260
  _ignoreNextTextInputCall = NO;
261
261
  return;
262
262
  }
263
- _lastStringStateWasUpdatedWith = _backedTextInputView.attributedText;
264
263
  _textDidChangeIsComing = NO;
265
264
  [_backedTextInputView.textInputDelegate textInputDidChange];
266
265
  }
267
266
 
268
267
  - (void)textViewDidChangeSelection:(__unused UITextView *)textView
269
268
  {
270
- if (![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
269
+ if (_lastStringStateWasUpdatedWith && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
271
270
  [self textViewDidChange:_backedTextInputView];
272
271
  _ignoreNextTextInputCall = YES;
273
272
  }
273
+ _lastStringStateWasUpdatedWith = _backedTextInputView.attributedText;
274
274
  [self textViewProbablyDidChangeSelection];
275
275
  }
276
276
 
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(72),
26
26
  RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"rc.1",
27
+ RCTVersionPrerelease: @"rc.3",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -428,10 +428,10 @@ RCT_EXPORT_METHOD(show)
428
428
  ? UIAlertControllerStyleActionSheet
429
429
  : UIAlertControllerStyleAlert;
430
430
 
431
- NSString *debugMenuType = self.bridge ? @"Bridge" : @"Bridgeless";
432
- NSString *debugMenuTitle = [NSString stringWithFormat:@"React Native Debug Menu (%@)", debugMenuType];
431
+ NSString *devMenuType = self.bridge ? @"Bridge" : @"Bridgeless";
432
+ NSString *devMenuTitle = [NSString stringWithFormat:@"React Native Dev Menu (%@)", devMenuType];
433
433
 
434
- _actionSheet = [UIAlertController alertControllerWithTitle:debugMenuTitle message:description preferredStyle:style];
434
+ _actionSheet = [UIAlertController alertControllerWithTitle:devMenuTitle message:description preferredStyle:style];
435
435
 
436
436
  NSArray<RCTDevMenuItem *> *items = [self _menuItemsToPresent];
437
437
  for (RCTDevMenuItem *item in items) {
@@ -14,6 +14,7 @@
14
14
  #import <react/renderer/components/image/ImageComponentDescriptor.h>
15
15
  #import <react/renderer/components/image/ImageEventEmitter.h>
16
16
  #import <react/renderer/components/image/ImageProps.h>
17
+ #import <react/renderer/core/CoreFeatures.h>
17
18
  #import <react/renderer/imagemanager/ImageRequest.h>
18
19
  #import <react/renderer/imagemanager/RCTImagePrimitivesConversions.h>
19
20
 
@@ -97,8 +98,18 @@ using namespace facebook::react;
97
98
  - (void)_setStateAndResubscribeImageResponseObserver:(ImageShadowNode::ConcreteState::Shared const &)state
98
99
  {
99
100
  if (_state) {
100
- auto &observerCoordinator = _state->getData().getImageRequest().getObserverCoordinator();
101
+ auto const &imageRequest = _state->getData().getImageRequest();
102
+ auto &observerCoordinator = imageRequest.getObserverCoordinator();
101
103
  observerCoordinator.removeObserver(_imageResponseObserverProxy);
104
+ if (CoreFeatures::cancelImageDownloadsOnRecycle) {
105
+ // Cancelling image request because we are no longer observing it.
106
+ // This is not 100% correct place to do this because we may want to
107
+ // re-create RCTImageComponentView with the same image and if it
108
+ // was cancelled before downloaded, download is not resumed.
109
+ // This will only become issue if we decouple life cycle of a
110
+ // ShadowNode from ComponentView, which is not something we do now.
111
+ imageRequest.cancel();
112
+ }
102
113
  }
103
114
 
104
115
  _state = state;
@@ -285,6 +285,10 @@ static BackgroundExecutor RCTGetBackgroundExecutor()
285
285
  CoreFeatures::cacheNSTextStorage = true;
286
286
  }
287
287
 
288
+ if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:cancel_image_downloads_on_recycle")) {
289
+ CoreFeatures::cancelImageDownloadsOnRecycle = true;
290
+ }
291
+
288
292
  auto componentRegistryFactory =
289
293
  [factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
290
294
  EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.72.0-rc.1
1
+ VERSION_NAME=0.72.0-rc.3
2
2
  GROUP=com.facebook.react
3
3
 
4
4
  # JVM Versions
@@ -295,6 +295,16 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
295
295
  mCurrentFrameNumber++;
296
296
  }
297
297
 
298
+ @Override
299
+ public void willMountItems(UIManager uiManager) {
300
+ // noop
301
+ }
302
+
303
+ @Override
304
+ public void didMountItems(UIManager uiManager) {
305
+ // noop
306
+ }
307
+
298
308
  // For FabricUIManager only
299
309
  @Override
300
310
  @UiThread
@@ -21,6 +21,7 @@ import com.facebook.common.logging.FLog;
21
21
  import com.facebook.infer.annotation.Assertions;
22
22
  import com.facebook.infer.annotation.ThreadConfined;
23
23
  import com.facebook.proguard.annotations.DoNotStrip;
24
+ import com.facebook.react.bridge.interop.InteropModuleRegistry;
24
25
  import com.facebook.react.bridge.queue.MessageQueueThread;
25
26
  import com.facebook.react.bridge.queue.ReactQueueConfiguration;
26
27
  import com.facebook.react.common.LifecycleState;
@@ -69,6 +70,8 @@ public class ReactContext extends ContextWrapper {
69
70
  private @Nullable JSExceptionHandler mJSExceptionHandler;
70
71
  private @Nullable JSExceptionHandler mExceptionHandlerWrapper;
71
72
  private @Nullable WeakReference<Activity> mCurrentActivity;
73
+
74
+ private @Nullable InteropModuleRegistry mInteropModuleRegistry;
72
75
  private boolean mIsInitialized = false;
73
76
 
74
77
  public ReactContext(Context base) {
@@ -93,6 +96,7 @@ public class ReactContext extends ContextWrapper {
93
96
 
94
97
  ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
95
98
  initializeMessageQueueThreads(queueConfig);
99
+ initializeInteropModules();
96
100
  }
97
101
 
98
102
  /** Initialize message queue threads using a ReactQueueConfiguration. */
@@ -120,6 +124,14 @@ public class ReactContext extends ContextWrapper {
120
124
  mIsInitialized = true;
121
125
  }
122
126
 
127
+ protected void initializeInteropModules() {
128
+ mInteropModuleRegistry = new InteropModuleRegistry();
129
+ }
130
+
131
+ protected void initializeInteropModules(ReactContext reactContext) {
132
+ mInteropModuleRegistry = reactContext.mInteropModuleRegistry;
133
+ }
134
+
123
135
  public void resetPerfStats() {
124
136
  if (mNativeModulesMessageQueueThread != null) {
125
137
  mNativeModulesMessageQueueThread.resetPerfStats();
@@ -163,6 +175,10 @@ public class ReactContext extends ContextWrapper {
163
175
  }
164
176
  throw new IllegalStateException(EARLY_JS_ACCESS_EXCEPTION_MESSAGE);
165
177
  }
178
+ if (mInteropModuleRegistry != null
179
+ && mInteropModuleRegistry.shouldReturnInteropModule(jsInterface)) {
180
+ return mInteropModuleRegistry.getInteropModule(jsInterface);
181
+ }
166
182
  return mCatalystInstance.getJSModule(jsInterface);
167
183
  }
168
184
 
@@ -546,4 +562,17 @@ public class ReactContext extends ContextWrapper {
546
562
  Assertions.assertNotNull(mCatalystInstance).registerSegment(segmentId, path);
547
563
  Assertions.assertNotNull(callback).invoke();
548
564
  }
565
+
566
+ /**
567
+ * Register a {@link JavaScriptModule} within the Interop Layer so that can be consumed whenever
568
+ * getJSModule is invoked.
569
+ *
570
+ * <p>This method is internal to React Native and should not be used externally.
571
+ */
572
+ public <T extends JavaScriptModule> void internal_registerInteropModule(
573
+ Class<T> interopModuleInterface, Object interopModule) {
574
+ if (mInteropModuleRegistry != null) {
575
+ mInteropModuleRegistry.registerInteropModule(interopModuleInterface, interopModule);
576
+ }
577
+ }
549
578
  }
@@ -12,10 +12,33 @@ public interface UIManagerListener {
12
12
  /**
13
13
  * Called right before view updates are dispatched at the end of a batch. This is useful if a
14
14
  * module needs to add UIBlocks to the queue before it is flushed.
15
+ *
16
+ * <p>This is called by Paper only.
15
17
  */
16
18
  void willDispatchViewUpdates(UIManager uiManager);
17
- /* Called right after view updates are dispatched for a frame. */
19
+ /**
20
+ * Called on UIThread right before view updates are executed.
21
+ *
22
+ * <p>This is called by Fabric only.
23
+ */
24
+ void willMountItems(UIManager uiManager);
25
+ /**
26
+ * Called on UIThread right after view updates are executed.
27
+ *
28
+ * <p>This is called by Fabric only.
29
+ */
30
+ void didMountItems(UIManager uiManager);
31
+ /**
32
+ * Called on UIThread right after view updates are dispatched for a frame. Note that this will be
33
+ * called for every frame even if there are no updates.
34
+ *
35
+ * <p>This is called by Fabric only.
36
+ */
18
37
  void didDispatchMountItems(UIManager uiManager);
19
- /* Called right after scheduleMountItems is called in Fabric, after a new tree is committed. */
38
+ /**
39
+ * Called right after scheduleMountItems is called in Fabric, after a new tree is committed.
40
+ *
41
+ * <p>This is called by Fabric only.
42
+ */
20
43
  void didScheduleMountItems(UIManager uiManager);
21
44
  }
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.bridge.interop;
9
+
10
+ import androidx.annotation.Nullable;
11
+ import com.facebook.react.bridge.JavaScriptModule;
12
+ import com.facebook.react.config.ReactFeatureFlags;
13
+ import java.util.HashMap;
14
+
15
+ /**
16
+ * A utility class that takes care of returning {@link JavaScriptModule} which are used for the
17
+ * Fabric Interop Layer. This allows us to override the returned classes once the user is invoking
18
+ * `ReactContext.getJsModule()`.
19
+ *
20
+ * <p>Currently we only support a `RCTEventEmitter` re-implementation, being `InteropEventEmitter`
21
+ * but this class can support other re-implementation in the future.
22
+ */
23
+ public class InteropModuleRegistry {
24
+
25
+ @SuppressWarnings("rawtypes")
26
+ private final HashMap<Class, Object> supportedModules;
27
+
28
+ public InteropModuleRegistry() {
29
+ this.supportedModules = new HashMap<>();
30
+ }
31
+
32
+ public <T extends JavaScriptModule> boolean shouldReturnInteropModule(Class<T> requestedModule) {
33
+ return checkReactFeatureFlagsConditions() && supportedModules.containsKey(requestedModule);
34
+ }
35
+
36
+ @Nullable
37
+ public <T extends JavaScriptModule> T getInteropModule(Class<T> requestedModule) {
38
+ if (checkReactFeatureFlagsConditions()) {
39
+ //noinspection unchecked
40
+ return (T) supportedModules.get(requestedModule);
41
+ } else {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ public <T extends JavaScriptModule> void registerInteropModule(
47
+ Class<T> interopModuleInterface, Object interopModule) {
48
+ if (checkReactFeatureFlagsConditions()) {
49
+ supportedModules.put(interopModuleInterface, interopModule);
50
+ }
51
+ }
52
+
53
+ private boolean checkReactFeatureFlagsConditions() {
54
+ return ReactFeatureFlags.enableFabricRenderer && ReactFeatureFlags.unstable_useFabricInterop;
55
+ }
56
+ }
@@ -34,6 +34,14 @@ public class ReactFeatureFlags {
34
34
  */
35
35
  public static volatile boolean enableFabricRenderer = false;
36
36
 
37
+ /**
38
+ * Should this application enable the Fabric Interop Layer for Android? If yes, the application
39
+ * will behave so that it can accept non-Fabric components and render them on Fabric. This toggle
40
+ * is controlling extra logic such as custom event dispatching that are needed for the Fabric
41
+ * Interop Layer to work correctly.
42
+ */
43
+ public static volatile boolean unstable_useFabricInterop = false;
44
+
37
45
  /**
38
46
  * Feature flag to enable the new bridgeless architecture. Note: Enabling this will force enable
39
47
  * the following flags: `useTurboModules` & `enableFabricRenderer`.
@@ -31,6 +31,7 @@ object DefaultNewArchitectureEntryPoint {
31
31
  ) {
32
32
  ReactFeatureFlags.useTurboModules = turboModulesEnabled
33
33
  ReactFeatureFlags.enableFabricRenderer = fabricEnabled
34
+ ReactFeatureFlags.unstable_useFabricInterop = fabricEnabled
34
35
 
35
36
  this.privateFabricEnabled = fabricEnabled
36
37
  this.privateTurboModulesEnabled = turboModulesEnabled
@@ -24,6 +24,7 @@ import android.util.Pair;
24
24
  import android.view.Gravity;
25
25
  import android.view.View;
26
26
  import android.widget.EditText;
27
+ import android.widget.LinearLayout;
27
28
  import android.widget.TextView;
28
29
  import android.widget.Toast;
29
30
  import androidx.annotation.Nullable;
@@ -553,17 +554,30 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
553
554
  return;
554
555
  }
555
556
 
556
- final TextView textView = new TextView(getApplicationContext());
557
- textView.setText("React Native DevMenu (" + getUniqueTag() + ")");
558
- textView.setPadding(0, 50, 0, 0);
559
- textView.setGravity(Gravity.CENTER);
560
- textView.setTextColor(Color.BLACK);
561
- textView.setTextSize(17);
562
- textView.setTypeface(textView.getTypeface(), Typeface.BOLD);
557
+ final LinearLayout header = new LinearLayout(getApplicationContext());
558
+ header.setOrientation(LinearLayout.VERTICAL);
559
+
560
+ final TextView title = new TextView(getApplicationContext());
561
+ title.setText("React Native Dev Menu (" + getUniqueTag() + ")");
562
+ title.setPadding(0, 50, 0, 0);
563
+ title.setGravity(Gravity.CENTER);
564
+ title.setTextColor(Color.DKGRAY);
565
+ title.setTextSize(16);
566
+ title.setTypeface(title.getTypeface(), Typeface.BOLD);
567
+
568
+ final TextView jsExecutorLabel = new TextView(getApplicationContext());
569
+ jsExecutorLabel.setText(getJSExecutorDescription());
570
+ jsExecutorLabel.setPadding(0, 20, 0, 0);
571
+ jsExecutorLabel.setGravity(Gravity.CENTER);
572
+ jsExecutorLabel.setTextColor(Color.GRAY);
573
+ jsExecutorLabel.setTextSize(14);
574
+
575
+ header.addView(title);
576
+ header.addView(jsExecutorLabel);
563
577
 
564
578
  mDevOptionsDialog =
565
579
  new AlertDialog.Builder(context)
566
- .setCustomTitle(textView)
580
+ .setCustomTitle(header)
567
581
  .setItems(
568
582
  options.keySet().toArray(new String[0]),
569
583
  new DialogInterface.OnClickListener() {
@@ -587,6 +601,10 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
587
601
  }
588
602
  }
589
603
 
604
+ private String getJSExecutorDescription() {
605
+ return "Running " + getReactInstanceDevHelper().getJavaScriptExecutorFactory().toString();
606
+ }
607
+
590
608
  /**
591
609
  * {@link ReactInstanceDevCommandsHandler} is responsible for enabling/disabling dev support when
592
610
  * a React view is attached/detached or when application state changes (e.g. the application is
@@ -56,6 +56,7 @@ import com.facebook.react.config.ReactFeatureFlags;
56
56
  import com.facebook.react.fabric.events.EventBeatManager;
57
57
  import com.facebook.react.fabric.events.EventEmitterWrapper;
58
58
  import com.facebook.react.fabric.events.FabricEventEmitter;
59
+ import com.facebook.react.fabric.interop.InteropEventEmitter;
59
60
  import com.facebook.react.fabric.mounting.MountItemDispatcher;
60
61
  import com.facebook.react.fabric.mounting.MountingManager;
61
62
  import com.facebook.react.fabric.mounting.SurfaceMountingManager;
@@ -81,6 +82,7 @@ import com.facebook.react.uimanager.ViewManagerRegistry;
81
82
  import com.facebook.react.uimanager.events.EventCategoryDef;
82
83
  import com.facebook.react.uimanager.events.EventDispatcher;
83
84
  import com.facebook.react.uimanager.events.EventDispatcherImpl;
85
+ import com.facebook.react.uimanager.events.RCTEventEmitter;
84
86
  import com.facebook.react.views.text.TextLayoutManager;
85
87
  import com.facebook.react.views.text.TextLayoutManagerMapBuffer;
86
88
  import java.util.HashMap;
@@ -390,6 +392,11 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
390
392
 
391
393
  ReactMarker.addFabricListener(mDevToolsReactPerfLogger);
392
394
  }
395
+ if (ReactFeatureFlags.unstable_useFabricInterop) {
396
+ InteropEventEmitter interopEventEmitter = new InteropEventEmitter(mReactApplicationContext);
397
+ mReactApplicationContext.internal_registerInteropModule(
398
+ RCTEventEmitter.class, interopEventEmitter);
399
+ }
393
400
  }
394
401
 
395
402
  // This is called on the JS thread (see CatalystInstanceImpl).
@@ -1171,6 +1178,20 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
1171
1178
  }
1172
1179
 
1173
1180
  private class MountItemDispatchListener implements MountItemDispatcher.ItemDispatchListener {
1181
+ @Override
1182
+ public void willMountItems() {
1183
+ for (UIManagerListener listener : mListeners) {
1184
+ listener.willMountItems(FabricUIManager.this);
1185
+ }
1186
+ }
1187
+
1188
+ @Override
1189
+ public void didMountItems() {
1190
+ for (UIManagerListener listener : mListeners) {
1191
+ listener.didMountItems(FabricUIManager.this);
1192
+ }
1193
+ }
1194
+
1174
1195
  @Override
1175
1196
  public void didDispatchMountItems() {
1176
1197
  for (UIManagerListener listener : mListeners) {
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.fabric.interop;
9
+
10
+ import androidx.annotation.Nullable;
11
+ import com.facebook.react.bridge.WritableMap;
12
+ import com.facebook.react.common.annotations.VisibleForTesting;
13
+ import com.facebook.react.uimanager.events.Event;
14
+
15
+ /**
16
+ * An {@link Event} class used by the {@link InteropEventEmitter}. This class is just holding the
17
+ * event name and the data which is received by the `receiveEvent` method and will be passed over
18
+ * the the {@link com.facebook.react.uimanager.events.EventDispatcher}
19
+ */
20
+ class InteropEvent extends Event<InteropEvent> {
21
+
22
+ private final String mName;
23
+ private final WritableMap mEventData;
24
+
25
+ InteropEvent(String name, @Nullable WritableMap eventData, int surfaceId, int viewTag) {
26
+ super(surfaceId, viewTag);
27
+ mName = name;
28
+ mEventData = eventData;
29
+ }
30
+
31
+ @Override
32
+ public String getEventName() {
33
+ return mName;
34
+ }
35
+
36
+ @Override
37
+ @VisibleForTesting
38
+ public WritableMap getEventData() {
39
+ return mEventData;
40
+ }
41
+ }
@@ -0,0 +1,65 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.fabric.interop;
9
+
10
+ import androidx.annotation.Nullable;
11
+ import com.facebook.react.bridge.ReactContext;
12
+ import com.facebook.react.bridge.WritableArray;
13
+ import com.facebook.react.bridge.WritableMap;
14
+ import com.facebook.react.common.annotations.VisibleForTesting;
15
+ import com.facebook.react.uimanager.UIManagerHelper;
16
+ import com.facebook.react.uimanager.events.EventDispatcher;
17
+ import com.facebook.react.uimanager.events.RCTEventEmitter;
18
+
19
+ /**
20
+ * A reimplementation of {@link RCTEventEmitter} which is using a {@link EventDispatcher} under the
21
+ * hood.
22
+ *
23
+ * <p>On Fabric, you're supposed to use {@link EventDispatcher} to dispatch events. However, we
24
+ * provide an interop layer for non-Fabric migrated components.
25
+ *
26
+ * <p>This instance will be returned if the user is invoking `context.getJsModule(RCTEventEmitter)
27
+ * and is providing support for the `receiveEvent` method, so that non-Fabric ViewManagers can
28
+ * continue to deliver events also when Fabric is turned on.
29
+ */
30
+ public class InteropEventEmitter implements RCTEventEmitter {
31
+
32
+ private final ReactContext mReactContext;
33
+
34
+ private @Nullable EventDispatcher mEventDispatcherOverride;
35
+
36
+ public InteropEventEmitter(ReactContext reactContext) {
37
+ mReactContext = reactContext;
38
+ }
39
+
40
+ @Override
41
+ public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap eventData) {
42
+ EventDispatcher dispatcher;
43
+ if (mEventDispatcherOverride != null) {
44
+ dispatcher = mEventDispatcherOverride;
45
+ } else {
46
+ dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, targetReactTag);
47
+ }
48
+ int surfaceId = UIManagerHelper.getSurfaceId(mReactContext);
49
+ if (dispatcher != null) {
50
+ dispatcher.dispatchEvent(new InteropEvent(eventName, eventData, surfaceId, targetReactTag));
51
+ }
52
+ }
53
+
54
+ @Override
55
+ public void receiveTouches(
56
+ String eventName, WritableArray touches, WritableArray changedIndices) {
57
+ throw new UnsupportedOperationException(
58
+ "EventEmitter#receiveTouches is not supported by the Fabric Interop Layer");
59
+ }
60
+
61
+ @VisibleForTesting
62
+ void overrideEventDispatcher(EventDispatcher eventDispatcherOverride) {
63
+ mEventDispatcherOverride = eventDispatcherOverride;
64
+ }
65
+ }