react-native-tvos 0.74.0-0rc3 → 0.74.2-0

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 (74) hide show
  1. package/Libraries/AppDelegate/RCTAppDelegate+Protected.h +16 -0
  2. package/Libraries/AppDelegate/RCTAppDelegate.mm +32 -1
  3. package/Libraries/AppDelegate/React-RCTAppDelegate.podspec +1 -0
  4. package/Libraries/Components/Pressable/Pressable.js +9 -5
  5. package/Libraries/Components/TextInput/TextInput.js +6 -3
  6. package/Libraries/Components/Touchable/TouchableBounce.js +1 -0
  7. package/Libraries/Components/Touchable/TouchableOpacity.js +1 -0
  8. package/Libraries/Core/ReactNativeVersion.js +2 -2
  9. package/Libraries/ReactNative/RendererImplementation.js +2 -0
  10. package/README.md +29 -9
  11. package/React/Base/RCTUtils.m +28 -8
  12. package/React/Base/RCTVersion.m +2 -2
  13. package/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm +2 -4
  14. package/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm +22 -2
  15. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +5 -1
  16. package/React/Fabric/RCTScheduler.h +2 -0
  17. package/React/Fabric/RCTScheduler.mm +6 -0
  18. package/React/Fabric/RCTSurfacePresenter.mm +5 -0
  19. package/React/Modules/RCTUIManager.m +8 -9
  20. package/React/Views/RCTComponentData.m +14 -1
  21. package/React/Views/ScrollView/RCTScrollView.m +30 -14
  22. package/ReactAndroid/api/ReactAndroid.api +1 -2
  23. package/ReactAndroid/gradle.properties +1 -1
  24. package/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +2 -2
  25. package/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java +24 -9
  26. package/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt +15 -0
  27. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +19 -7
  28. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +31 -11
  29. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +7 -3
  30. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +7 -3
  31. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +34 -12
  32. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +7 -3
  33. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
  34. package/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt +11 -18
  35. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java +27 -14
  36. package/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +1 -3
  37. package/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +38 -3
  38. package/ReactAndroid/src/main/jni/react/fabric/Binding.h +8 -0
  39. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +43 -15
  40. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +10 -4
  41. package/ReactCommon/ReactCommon.podspec +1 -0
  42. package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
  43. package/ReactCommon/jsc/JSCRuntime.cpp +2 -0
  44. package/ReactCommon/jsinspector-modern/React-jsinspector.podspec +2 -1
  45. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +13 -5
  46. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +16 -6
  47. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +62 -26
  48. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +8 -4
  49. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +13 -5
  50. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +4 -2
  51. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +16 -6
  52. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +7 -3
  53. package/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp +53 -1
  54. package/ReactCommon/react/renderer/mounting/MountingTransaction.cpp +13 -0
  55. package/ReactCommon/react/renderer/mounting/MountingTransaction.h +9 -0
  56. package/ReactCommon/react/renderer/scheduler/Scheduler.cpp +7 -2
  57. package/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h +11 -0
  58. package/cli.js +11 -3
  59. package/package.json +12 -12
  60. package/scripts/cocoapods/privacy_manifest_utils.rb +173 -0
  61. package/scripts/cocoapods/utils.rb +1 -38
  62. package/scripts/ios-configure-glog.sh +9 -2
  63. package/scripts/react_native_pods.rb +14 -3
  64. package/sdks/.hermesversion +1 -1
  65. package/sdks/hermesc/osx-bin/hermes +0 -0
  66. package/sdks/hermesc/osx-bin/hermesc +0 -0
  67. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  68. package/src/private/featureflags/NativeReactNativeFeatureFlags.js +4 -2
  69. package/src/private/featureflags/ReactNativeFeatureFlags.js +16 -6
  70. package/template/package.json +5 -5
  71. package/third-party-podspecs/RCT-Folly.podspec +1 -0
  72. package/types/public/ReactNativeTVTypes.d.ts +6 -10
  73. package/Libraries/React-Native +0 -214
  74. package/ReactAndroid/src/main/java/com/facebook/react/ReactAndroidHWInputDeviceHelper.java +0 -98
@@ -0,0 +1,16 @@
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
+ #if defined(__cplusplus)
9
+
10
+ #import <ReactCommon/RCTTurboModuleManager.h>
11
+ #import "RCTAppDelegate.h"
12
+
13
+ @interface RCTAppDelegate () <RCTTurboModuleManagerDelegate>
14
+ @end
15
+
16
+ #endif
@@ -11,7 +11,11 @@
11
11
  #import <React/RCTRootView.h>
12
12
  #import <React/RCTSurfacePresenterBridgeAdapter.h>
13
13
  #import <React/RCTUtils.h>
14
- #import <react/renderer/runtimescheduler/RuntimeScheduler.h>
14
+ #import <objc/runtime.h>
15
+ #import <react/featureflags/ReactNativeFeatureFlags.h>
16
+ #import <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
17
+ #import <react/renderer/graphics/ColorComponents.h>
18
+ #import "RCTAppDelegate+Protected.h"
15
19
  #import "RCTAppSetupUtils.h"
16
20
 
17
21
  #if RN_DISABLE_OSS_PLUGIN_HEADER
@@ -46,6 +50,8 @@
46
50
 
47
51
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
48
52
  {
53
+ [self _setUpFeatureFlags];
54
+
49
55
  RCTSetNewArchEnabled([self newArchEnabled]);
50
56
  RCTAppSetupPrepareApp(application, self.turboModuleEnabled);
51
57
 
@@ -268,4 +274,29 @@
268
274
  return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self];
269
275
  }
270
276
 
277
+ #pragma mark - Feature Flags
278
+
279
+ class RCTAppDelegateBridgelessFeatureFlags : public facebook::react::ReactNativeFeatureFlagsDefaults {
280
+ public:
281
+ bool useModernRuntimeScheduler() override
282
+ {
283
+ return true;
284
+ }
285
+ bool enableMicrotasks() override
286
+ {
287
+ return true;
288
+ }
289
+ bool batchRenderingUpdatesInEventLoop() override
290
+ {
291
+ return true;
292
+ }
293
+ };
294
+
295
+ - (void)_setUpFeatureFlags
296
+ {
297
+ if ([self bridgelessEnabled]) {
298
+ facebook::react::ReactNativeFeatureFlags::override(std::make_unique<RCTAppDelegateBridgelessFeatureFlags>());
299
+ }
300
+ }
301
+
271
302
  @end
@@ -89,6 +89,7 @@ Pod::Spec.new do |s|
89
89
  add_dependency(s, "React-utils")
90
90
  add_dependency(s, "React-debug")
91
91
  add_dependency(s, "React-rendererdebug")
92
+ add_dependency(s, "React-featureflags")
92
93
 
93
94
  if use_hermes
94
95
  s.dependency "React-hermes"
@@ -275,6 +275,9 @@ function Pressable(props: Props, forwardedRef): React.Node {
275
275
 
276
276
  const [focused, setFocused] = useState(false);
277
277
 
278
+ const shouldUpdatePressed =
279
+ typeof children === 'function' || typeof style === 'function';
280
+
278
281
  let _accessibilityState = {
279
282
  busy: ariaBusy ?? accessibilityState?.busy,
280
283
  checked: ariaChecked ?? accessibilityState?.checked,
@@ -334,7 +337,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
334
337
  if (android_rippleConfig != null) {
335
338
  android_rippleConfig.onPressIn(event);
336
339
  }
337
- setPressed(true);
340
+ shouldUpdatePressed && setPressed(true);
338
341
  if (onPressIn != null) {
339
342
  onPressIn(event);
340
343
  }
@@ -344,7 +347,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
344
347
  if (android_rippleConfig != null) {
345
348
  android_rippleConfig.onPressOut(event);
346
349
  }
347
- setPressed(false);
350
+ shouldUpdatePressed && setPressed(false);
348
351
  if (onPressOut != null) {
349
352
  onPressOut(event);
350
353
  }
@@ -369,6 +372,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
369
372
  onPressOut,
370
373
  pressRetentionOffset,
371
374
  setPressed,
375
+ shouldUpdatePressed,
372
376
  unstable_pressDelay,
373
377
  ],
374
378
  );
@@ -380,12 +384,12 @@ function Pressable(props: Props, forwardedRef): React.Node {
380
384
  if (isTVSelectable !== false || focusable !== false) {
381
385
  // $FlowFixMe[prop-missing]
382
386
  if (evt?.eventType === 'focus') {
383
- setFocused(true);
387
+ shouldUpdatePressed && setFocused(true);
384
388
  onFocus && onFocus(evt);
385
389
  // $FlowFixMe[prop-missing]
386
390
  } else if (evt.eventType === 'blur') {
387
391
  onBlur && onBlur(evt);
388
- setFocused(false);
392
+ shouldUpdatePressed && setFocused(false);
389
393
  }
390
394
  }
391
395
  // $FlowFixMe[prop-missing]
@@ -399,7 +403,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
399
403
  onLongPress && onLongPress(evt);
400
404
  }
401
405
  },
402
- [focused, onBlur, onFocus, onLongPress, onPress, focusable, isTVSelectable],
406
+ [focused, onBlur, onFocus, onLongPress, onPress, focusable, isTVSelectable, shouldUpdatePressed],
403
407
  );
404
408
 
405
409
  React.useEffect(() => {
@@ -1136,12 +1136,14 @@ function InternalTextInput(props: Props): React.Node {
1136
1136
  };
1137
1137
 
1138
1138
  const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
1139
-
1140
1139
  const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
1141
1140
  const [lastNativeSelectionState, setLastNativeSelection] = useState<{|
1142
- selection: ?Selection,
1141
+ selection: Selection,
1143
1142
  mostRecentEventCount: number,
1144
- |}>({selection, mostRecentEventCount});
1143
+ |}>({
1144
+ selection: {start: -1, end: -1},
1145
+ mostRecentEventCount: mostRecentEventCount,
1146
+ });
1145
1147
 
1146
1148
  const lastNativeSelection = lastNativeSelectionState.selection;
1147
1149
 
@@ -1506,6 +1508,7 @@ function InternalTextInput(props: Props): React.Node {
1506
1508
  onSelectionChange={_onSelectionChange}
1507
1509
  onSelectionChangeShouldSetResponder={emptyFunctionThatReturnsTrue}
1508
1510
  selection={selection}
1511
+ selectionColor={selectionColor}
1509
1512
  style={StyleSheet.compose(
1510
1513
  useMultilineDefaultStyle ? styles.multilineDefault : null,
1511
1514
  style,
@@ -245,6 +245,7 @@ class TouchableBounce extends React.Component<Props, State> {
245
245
  }
246
246
  }
247
247
  this.state.pressability.reset();
248
+ this.state.scale.resetAnimation();
248
249
  }
249
250
  }
250
251
 
@@ -364,6 +364,7 @@ class TouchableOpacity extends React.Component<Props, State> {
364
364
  }
365
365
  }
366
366
  this.state.pressability.reset();
367
+ this.state.anim.resetAnimation();
367
368
  }
368
369
  }
369
370
 
@@ -16,8 +16,8 @@ const version: $ReadOnly<{
16
16
  }> = {
17
17
  major: 0,
18
18
  minor: 74,
19
- patch: 0,
20
- prerelease: '0rc3',
19
+ patch: 2,
20
+ prerelease: '0',
21
21
  };
22
22
 
23
23
  module.exports = {version};
@@ -47,9 +47,11 @@ export function findHostInstance_DEPRECATED<TElementType: ElementType>(
47
47
 
48
48
  export function findNodeHandle<TElementType: ElementType>(
49
49
  componentOrHandle: ?(ElementRef<TElementType> | number),
50
+ suppressWarning: ?Boolean,
50
51
  ): ?number {
51
52
  return require('../Renderer/shims/ReactNative').findNodeHandle(
52
53
  componentOrHandle,
54
+ suppressWarning,
53
55
  );
54
56
  }
55
57
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Apple TV and Android TV support for React Native are maintained here and in the corresponding `react-native-tvos` NPM package, and not in the [core repo](https://github.com/facebook/react-native/). This is a full fork of the main repository, with only the changes needed to support Apple TV and Android TV.
4
4
 
5
- Releases of `react-native-tvos` will be based on a public release of `react-native`; e.g. the 0.72.4-0 release of this package will be derived from the 0.72.4 release of `react-native`. All releases of this repo will follow the 0.xx.x-y format, where x digits are from a specific RN core release, and y represents the additional versioning from this repo.
5
+ Releases of `react-native-tvos` will be based on a public release of `react-native`; e.g. the 0.74.0-0 release of this package will be derived from the 0.74.0 release of `react-native`. All releases of this repo will follow the 0.xx.x-y format, where x digits are from a specific RN core release, and y represents the additional versioning from this repo.
6
6
 
7
7
  Releases will be published on npmjs.org and you may find the latest release version here: https://www.npmjs.com/package/react-native-tvos?activeTab=versions or use the tag `@latest`
8
8
 
@@ -16,6 +16,11 @@ To build your project for Apple TV, you should change your `package.json` import
16
16
 
17
17
  You cannot use this package and the core react-native package simultaneously in a project.
18
18
 
19
+ This README covers only TV-specific features. For more general documentation and for changes between versions, you should also see these resources:
20
+
21
+ - React Native documentation: https://reactnative.dev
22
+ - The React Native changelog: https://github.com/facebook/react-native/blob/main/CHANGELOG.md
23
+
19
24
  ### Hermes JS support
20
25
 
21
26
  As of the 0.71 release, Hermes is fully working on both Apple TV and Android TV, and is enabled by default.
@@ -25,6 +30,17 @@ As of the 0.71 release, Hermes is fully working on both Apple TV and Android TV,
25
30
  - _Apple TV_: Modify your app's Podfile to set the `:fabric_enabled` value to `true` in both iOS and tvOS targets. After that, run `pod install` to pick up the additional pods needed for the new architecture. Some components (TVTextScrollView, TabBarIOS) have not been reimplemented in the new architecture so they will show up as an "unimplemented component".
26
31
  - _Android TV_: To enable Fabric, modify `android/gradle.properties` in your app and set `newArchEnabled=true`, then rebuild your app.
27
32
 
33
+ As of the 0.74 release, bridgeless is the default when Fabric is enabled.
34
+
35
+ Known issue: The `TVFocusGuide` `autofocus` API has problems on Apple TV when bridgeless is enabled. If you need to use Fabric without bridgeless on Apple TV, you can override the default by adding the method below in `AppDelegate.mm`:
36
+
37
+ ```objc
38
+ - (BOOL)bridgelessEnabled
39
+ {
40
+ return false;
41
+ }
42
+ ```
43
+
28
44
  ### Typescript
29
45
 
30
46
  Typescript types for TV-specific components and APIs have been added to `types/public`.
@@ -33,21 +49,26 @@ Typescript types for TV-specific components and APIs have been added to `types/p
33
49
 
34
50
  TV device support has been implemented with the intention of making existing React Native applications "just work" on TV, with few or no changes needed in the JavaScript code for the applications.
35
51
 
36
- The RNTester app supports Apple TV and Android TV. In this repo, `RNTester/Podfile` and `RNTester/RNTesterPods.xcodeproj` have been modified to work for tvOS. Run `pod install`, then open `RNTesterPods.xcworkspace` and build.
52
+ The RNTester app supports Apple TV and Android TV. In this repo, `RNTester/Podfile` and `RNTester/RNTesterPods.xcodeproj` have been modified to work for tvOS.
37
53
 
54
+ Minimum operating system versions:
38
55
 
39
- You should also install `yarn` globally, as it should be used instead of `npm` for working in React Native projects.
56
+ - Apple TV: tvOS 13.4
57
+ - Android TV:
58
+ - API level 21 (for the 0.73 releases)
59
+ - API level 23 (for the 0.74 release)
40
60
 
41
61
  ## Build changes
42
62
 
43
63
  - _Native layer for Apple TV_: React Native Xcode projects all now have Apple TV build targets, with names ending in the string '-tvOS'. Changes in the React Native podspecs in 0.73 now require that your application `Podfile` only have one target. This repo supports either an iOS target or a tvOS target, but both targets should not be active at the same time. The new app template now has the iOS target commented out.
44
- - _Maven artifacts for Android TV_: In 0.71, the React Native Android prebuilt archives are published to Maven instead of being included in the NPM. We are following the same model, except that the Maven artifacts will be in group `io.github.react-native-tvos` instead of `com.facebook.react`. The `@react-native/gradle-plugin` module has been upgraded so that the Android dependencies will be detected correctly during build.
64
+ - _Maven artifacts for Android TV_: In 0.71 and later releases, the React Native Android prebuilt archives are published to Maven instead of being included in the NPM. We are following the same model, except that the Maven artifacts will be in group `io.github.react-native-tvos` instead of `com.facebook.react`. The `@react-native/gradle-plugin` module has been upgraded so that the Android dependencies will be detected correctly during build.
45
65
 
46
66
  ## _(New)_ Project creation using the Expo CLI
47
67
 
48
68
  > _Pitfall:_ Make sure you do not globally install `react-native` or `react-native-tvos`. If you have done this the wrong way, you may get error messages like `ld: library not found for -lPods-TestApp-tvOS`.
49
69
 
50
70
  We strongly recommend [Yarn](https://classic.yarnpkg.com/en/docs/install) as the package manager.
71
+ You should install `yarn` globally, as it should be used instead of `npm` for working in React Native projects.
51
72
 
52
73
  To create a new project, use `yarn create react-native-app` as shown below. (This will install the Expo tool `create-react-native-app` for you if it is not already present.)
53
74
 
@@ -104,8 +125,6 @@ var running_on_tv = Platform.isTV;
104
125
  var running_on_apple_tv = Platform.isTVOS;
105
126
  ```
106
127
 
107
-
108
-
109
128
  - _Common codebase for iOS and tvOS_: Since tvOS and iOS share most Objective-C and JavaScript code in common, most documentation for iOS applies equally to tvOS. Apple TV specific changes in native code are all wrapped by the TARGET_OS_TV define. These include changes to suppress APIs that are not supported on tvOS (e.g. web views, sliders, switches, status bar, etc.), and changes to support user input from the TV remote or keyboard.
110
129
 
111
130
  - _Common codebase for Android phone and Android TV_: Apps built for Android using this repo will run on both Android phone and Android TV. Most of the changes for TV are specific to handling focus-based navigation on a TV using the D-Pad on the remote control.
@@ -114,9 +133,10 @@ var running_on_apple_tv = Platform.isTVOS;
114
133
 
115
134
  - `onFocus` will be executed when the touchable view goes into focus
116
135
  - `onBlur` will be executed when the touchable view goes out of focus
117
- - `onPress` will be executed when the touchable view is actually selected by pressing the "select" button on the TV remote.
136
+ - `onPress` will be executed when the touchable view is actually selected by pressing the "select" button on the TV remote (center button on Apple TV remote, or center button on Android TV DPad).
137
+ - `onLongPress` will be executed twice if the "select" button is held down for a length of time. The two events passed into `onLongPress()` will have different values for their `eventKeyAction` property, 0 for key down (start) and 1 for key up (end).
118
138
 
119
- - _Pressable controls_: The `Pressable` API works with TV. Additional `onFocus` and `onBlur` props are provided to allow you to customize behavior when a Pressable enters or leaves focus. Similar to the `pressed` state that is true while a user is pressing the component on a touchscreen, the `focused` state will be true when it is focused on TV. `PressableExample` in RNTester has been modified appropriately.
139
+ - _Pressable controls_: The `Pressable` API works with TV. Additional `onFocus` and `onBlur` props are provided to allow you to customize behavior when a Pressable enters or leaves focus. Similar to the `pressed` state that is true while a user is pressing the component on a touchscreen, the `focused` state will be true when it is focused on TV. `PressableExample` in RNTester has been modified appropriately. The `onPress()` and `onLongPress()` methods work the same way as with `Touchable` components.
120
140
 
121
141
  - _TV remote/keyboard input_: Application code that needs to implement custom handling of TV remote events can create an instance of `TVEventHandler` and listen for these events. For a more convenient API, we provide `useTVEventHandler`.
122
142
 
@@ -189,7 +209,7 @@ class Game2048 extends React.Component {
189
209
 
190
210
  - _Flipper_: We do not support Flipper.
191
211
 
192
- - _LogBox_: The new LogBox error/warning display (which replaced YellowBox in 0.63) is working as expected on TV platforms, after a few adjustments to make the controls accessible to the focus engine.
212
+ - _LogBox_: The LogBox error/warning display (which replaced YellowBox in 0.63) is working as expected on TV platforms, after a few adjustments to make the controls accessible to the focus engine.
193
213
 
194
214
  - _Dev Menu support_: On the Apple TV simulator, cmd-D will bring up the developer menu, just like on iOS. To bring it up on a real Apple TV device, make a long press on the play/pause button on the remote. (Please do not shake the Apple TV device, that will not work :) ). Android TV dev menu behavior is the same as on Android phone.
195
215
 
@@ -562,17 +562,37 @@ UIWindow *__nullable RCTKeyWindow(void)
562
562
  return nil;
563
563
  }
564
564
 
565
- for (UIScene *scene in RCTSharedApplication().connectedScenes) {
566
- if (scene.activationState != UISceneActivationStateForegroundActive ||
567
- ![scene isKindOfClass:[UIWindowScene class]]) {
565
+ NSSet<UIScene *> *connectedScenes = RCTSharedApplication().connectedScenes;
566
+
567
+ UIScene *foregroundActiveScene;
568
+ UIScene *foregroundInactiveScene;
569
+
570
+ for (UIScene *scene in connectedScenes) {
571
+ if (![scene isKindOfClass:[UIWindowScene class]]) {
568
572
  continue;
569
573
  }
570
- UIWindowScene *windowScene = (UIWindowScene *)scene;
571
574
 
572
- for (UIWindow *window in windowScene.windows) {
573
- if (window.isKeyWindow) {
574
- return window;
575
- }
575
+ if (scene.activationState == UISceneActivationStateForegroundActive) {
576
+ foregroundActiveScene = scene;
577
+ break;
578
+ }
579
+
580
+ if (!foregroundInactiveScene && scene.activationState == UISceneActivationStateForegroundInactive) {
581
+ foregroundInactiveScene = scene;
582
+ // no break, we can have the active scene later in the set.
583
+ }
584
+ }
585
+
586
+ UIScene *sceneToUse = foregroundActiveScene ? foregroundActiveScene : foregroundInactiveScene;
587
+ UIWindowScene *windowScene = (UIWindowScene *)sceneToUse;
588
+
589
+ if (@available(iOS 15.0, *)) {
590
+ return windowScene.keyWindow;
591
+ }
592
+
593
+ for (UIWindow *window in windowScene.windows) {
594
+ if (window.isKeyWindow) {
595
+ return window;
576
596
  }
577
597
  }
578
598
 
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(74),
26
- RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"0rc3",
26
+ RCTVersionPatch: @(2),
27
+ RCTVersionPrerelease: @"0",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -146,13 +146,11 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
146
146
  [super surface:surface didChangeStage:stage];
147
147
  if (RCTSurfaceStageIsRunning(stage)) {
148
148
  [_bridge.performanceLogger markStopForTag:RCTPLTTI];
149
- dispatch_async(dispatch_get_main_queue(), ^{
150
149
  #if TARGET_OS_TV
150
+ dispatch_async(dispatch_get_main_queue(), ^{
151
151
  self.tvRemoteHandler = [[RCTTVRemoteHandler alloc] initWithView:[self contentView]];
152
- #endif
153
-
154
- [[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification object:self];
155
152
  });
153
+ #endif
156
154
  }
157
155
  }
158
156
 
@@ -7,19 +7,22 @@
7
7
 
8
8
  #import "RCTRootComponentView.h"
9
9
 
10
+ #import <React/RCTRootView.h>
10
11
  #import <react/renderer/components/root/RootComponentDescriptor.h>
11
12
  #import <react/renderer/components/root/RootProps.h>
12
13
  #import "RCTConversions.h"
13
14
 
14
15
  using namespace facebook::react;
15
16
 
16
- @implementation RCTRootComponentView
17
+ @implementation RCTRootComponentView {
18
+ BOOL _contentHasAppeared;
19
+ }
17
20
 
18
21
  - (instancetype)initWithFrame:(CGRect)frame
19
22
  {
20
23
  if (self = [super initWithFrame:frame]) {
21
24
  _props = RootShadowNode::defaultSharedProps();
22
-
25
+ _contentHasAppeared = NO;
23
26
  }
24
27
 
25
28
  return self;
@@ -48,6 +51,23 @@ using namespace facebook::react;
48
51
 
49
52
  #pragma mark - RCTComponentViewProtocol
50
53
 
54
+ - (void)prepareForRecycle
55
+ {
56
+ [super prepareForRecycle];
57
+ _contentHasAppeared = NO;
58
+ }
59
+
60
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
61
+ {
62
+ [super mountChildComponentView:childComponentView index:index];
63
+ if (!self->_contentHasAppeared) {
64
+ self->_contentHasAppeared = YES;
65
+ dispatch_async(dispatch_get_main_queue(), ^{
66
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification object:self];
67
+ });
68
+ }
69
+ }
70
+
51
71
  + (ComponentDescriptorProvider)componentDescriptorProvider
52
72
  {
53
73
  return concreteComponentDescriptorProvider<RootComponentDescriptor>();
@@ -437,6 +437,11 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
437
437
 
438
438
  - (void)prepareForRecycle
439
439
  {
440
+ [super prepareForRecycle];
441
+ // Must invalidate state before setting contentOffset on ScrollView.
442
+ // Otherwise the state will be propagated to shadow tree.
443
+ _state.reset();
444
+
440
445
  const auto &props = static_cast<const ScrollViewProps &>(*_props);
441
446
  _scrollView.contentOffset = RCTCGPointFromPoint(props.contentOffset);
442
447
  // We set the default behavior to "never" so that iOS
@@ -444,7 +449,6 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
444
449
  // and keeps it as an opt-in behavior.
445
450
  _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
446
451
  _shouldUpdateContentInsetAdjustmentBehavior = YES;
447
- _state.reset();
448
452
  _isUserTriggeredScrolling = NO;
449
453
  CGRect oldFrame = self.frame;
450
454
  self.frame = CGRectZero;
@@ -30,6 +30,8 @@ NS_ASSUME_NONNULL_BEGIN
30
30
 
31
31
  - (void)schedulerDidFinishTransaction:(facebook::react::MountingCoordinator::Shared)mountingCoordinator;
32
32
 
33
+ - (void)schedulerShouldRenderTransactions:(facebook::react::MountingCoordinator::Shared)mountingCoordinator;
34
+
33
35
  - (void)schedulerDidDispatchCommand:(const facebook::react::ShadowView &)shadowView
34
36
  commandName:(const std::string &)commandName
35
37
  args:(const folly::dynamic &)args;
@@ -30,6 +30,12 @@ class SchedulerDelegateProxy : public SchedulerDelegate {
30
30
  [scheduler.delegate schedulerDidFinishTransaction:mountingCoordinator];
31
31
  }
32
32
 
33
+ void schedulerShouldRenderTransactions(const MountingCoordinator::Shared &mountingCoordinator) override
34
+ {
35
+ RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
36
+ [scheduler.delegate schedulerShouldRenderTransactions:mountingCoordinator];
37
+ }
38
+
33
39
  void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, const ShadowNode &shadowNode) override
34
40
  {
35
41
  // Does nothing.
@@ -354,6 +354,11 @@ static BackgroundExecutor RCTGetBackgroundExecutor()
354
354
  #pragma mark - RCTSchedulerDelegate
355
355
 
356
356
  - (void)schedulerDidFinishTransaction:(MountingCoordinator::Shared)mountingCoordinator
357
+ {
358
+ // no-op, we will flush the transaction from schedulerShouldRenderTransactions
359
+ }
360
+
361
+ - (void)schedulerShouldRenderTransactions:(MountingCoordinator::Shared)mountingCoordinator
357
362
  {
358
363
  [_mountingManager scheduleTransaction:mountingCoordinator];
359
364
  }
@@ -1678,8 +1678,8 @@ static UIView *_jsResponder;
1678
1678
  {
1679
1679
  self = [super init];
1680
1680
  if (self) {
1681
- self->_uiManager = uiManager;
1682
- self->_registry = registry;
1681
+ _uiManager = uiManager;
1682
+ _registry = registry;
1683
1683
  }
1684
1684
  return self;
1685
1685
  }
@@ -1697,26 +1697,27 @@ static UIView *_jsResponder;
1697
1697
  - (id)objectForKey:(id)key
1698
1698
  {
1699
1699
  if (![key isKindOfClass:[NSNumber class]]) {
1700
- return [super objectForKeyedSubscript:key];
1700
+ return NULL;
1701
1701
  }
1702
1702
 
1703
1703
  NSNumber *index = (NSNumber *)key;
1704
- UIView *view = [_uiManager viewForReactTag:index];
1704
+ UIView *view = _registry[index];
1705
1705
  if (view) {
1706
1706
  return [RCTUIManager paperViewOrCurrentView:view];
1707
1707
  }
1708
- view = _registry[index];
1708
+ view = [_uiManager viewForReactTag:index];
1709
1709
  if (view) {
1710
1710
  return [RCTUIManager paperViewOrCurrentView:view];
1711
1711
  }
1712
- return [super objectForKeyedSubscript:key];
1712
+ return NULL;
1713
1713
  }
1714
1714
 
1715
1715
  - (void)removeObjectForKey:(id)key
1716
1716
  {
1717
1717
  if (![key isKindOfClass:[NSNumber class]]) {
1718
- return [super removeObjectForKey:key];
1718
+ return;
1719
1719
  }
1720
+
1720
1721
  NSNumber *tag = (NSNumber *)key;
1721
1722
 
1722
1723
  if (_registry[key]) {
@@ -1724,8 +1725,6 @@ static UIView *_jsResponder;
1724
1725
  [mutableRegistry removeObjectForKey:tag];
1725
1726
  } else if ([_uiManager viewForReactTag:tag]) {
1726
1727
  [_uiManager removeViewFromRegistry:tag];
1727
- } else {
1728
- [super removeObjectForKey:key];
1729
1728
  }
1730
1729
  }
1731
1730
 
@@ -418,7 +418,20 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
418
418
  + (NSDictionary<NSString *, id> *)constantsForViewMangerClass:(Class)managerClass
419
419
  {
420
420
  if ([managerClass instancesRespondToSelector:@selector(constantsToExport)]) {
421
- return [[managerClass new] constantsToExport];
421
+ BOOL shouldRunOnMainThread = NO;
422
+
423
+ if ([managerClass respondsToSelector:@selector(requiresMainQueueSetup)]) {
424
+ shouldRunOnMainThread = [managerClass requiresMainQueueSetup];
425
+ }
426
+ if (shouldRunOnMainThread) {
427
+ __block NSDictionary<NSString *, id> *constants;
428
+ RCTUnsafeExecuteOnMainQueueSync(^{
429
+ constants = [[managerClass new] constantsToExport];
430
+ });
431
+ return constants;
432
+ } else {
433
+ return [[managerClass new] constantsToExport];
434
+ }
422
435
  }
423
436
  return @{};
424
437
  }
@@ -1002,13 +1002,13 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
1002
1002
  // scroll to bottom
1003
1003
  // Similarly for left and right
1004
1004
  if (context.focusHeading == UIFocusHeadingUp && self.snapToStart) {
1005
- [self swipeVerticalScrollToOffset:0.0];
1005
+ [self scrollToVerticalOffset:0.0];
1006
1006
  } else if(context.focusHeading == UIFocusHeadingDown && self.snapToEnd) {
1007
- [self swipeVerticalScrollToOffset:self.scrollView.contentSize.height];
1007
+ [self scrollToVerticalOffset:self.scrollView.contentSize.height];
1008
1008
  } else if(context.focusHeading == UIFocusHeadingLeft && self.snapToStart) {
1009
- [self swipeHorizontalScrollToOffset:0.0];
1009
+ [self scrollToHorizontalOffset:0.0];
1010
1010
  } else if(context.focusHeading == UIFocusHeadingRight && self.snapToEnd) {
1011
- [self swipeHorizontalScrollToOffset:self.scrollView.contentSize.width];
1011
+ [self scrollToHorizontalOffset:self.scrollView.contentSize.width];
1012
1012
  }
1013
1013
 
1014
1014
  }
@@ -1119,7 +1119,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
1119
1119
  return duration;
1120
1120
  }
1121
1121
 
1122
- - (void)swipeVerticalScrollToOffset:(CGFloat)yOffset
1122
+ - (void)scrollToVerticalOffset:(CGFloat)yOffset
1123
1123
  {
1124
1124
  _blockFirstTouch = NO;
1125
1125
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -1133,7 +1133,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
1133
1133
  });
1134
1134
  }
1135
1135
 
1136
- - (void)swipeHorizontalScrollToOffset:(CGFloat)xOffset
1136
+ - (void)scrollToHorizontalOffset:(CGFloat)xOffset
1137
1137
  {
1138
1138
  _blockFirstTouch = NO;
1139
1139
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -1149,30 +1149,46 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
1149
1149
 
1150
1150
  - (void)swipedUp
1151
1151
  {
1152
+ if (!self.scrollView.scrollEnabled) {
1153
+ return;
1154
+ }
1155
+
1152
1156
  CGFloat newOffset = self.scrollView.contentOffset.y - [self swipeVerticalInterval];
1153
1157
  NSLog(@"Swiped up to %f", newOffset);
1154
- [self swipeVerticalScrollToOffset:newOffset];
1158
+ [self scrollToVerticalOffset:newOffset];
1155
1159
  }
1156
1160
 
1157
1161
  - (void)swipedDown
1158
1162
  {
1163
+ if (!self.scrollView.scrollEnabled) {
1164
+ return;
1165
+ }
1166
+
1159
1167
  CGFloat newOffset = self.scrollView.contentOffset.y + [self swipeVerticalInterval];
1160
1168
  NSLog(@"Swiped down to %f", newOffset);
1161
- [self swipeVerticalScrollToOffset:newOffset];
1169
+ [self scrollToVerticalOffset:newOffset];
1162
1170
  }
1163
1171
 
1164
1172
  - (void)swipedLeft
1165
1173
  {
1166
- CGFloat newOffset = self.scrollView.contentOffset.x - [self swipeHorizontalInterval];
1167
- NSLog(@"Swiped left to %f", newOffset);
1168
- [self swipeHorizontalScrollToOffset:newOffset];
1174
+ if (!self.scrollView.scrollEnabled) {
1175
+ return;
1176
+ }
1177
+
1178
+ CGFloat newOffset = self.scrollView.contentOffset.x - [self swipeHorizontalInterval];
1179
+ NSLog(@"Swiped left to %f", newOffset);
1180
+ [self scrollToHorizontalOffset:newOffset];
1169
1181
  }
1170
1182
 
1171
1183
  - (void)swipedRight
1172
1184
  {
1173
- CGFloat newOffset = self.scrollView.contentOffset.x + [self swipeHorizontalInterval];
1174
- NSLog(@"Swiped right to %f", newOffset);
1175
- [self swipeHorizontalScrollToOffset:newOffset];
1185
+ if (!self.scrollView.scrollEnabled) {
1186
+ return;
1187
+ }
1188
+
1189
+ CGFloat newOffset = self.scrollView.contentOffset.x + [self swipeHorizontalInterval];
1190
+ NSLog(@"Swiped right to %f", newOffset);
1191
+ [self scrollToHorizontalOffset:newOffset];
1176
1192
  }
1177
1193
 
1178
1194
  - (void)addSwipeGestureRecognizers