react-native-tvos 0.76.0-0rc5 → 0.76.1-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 (32) hide show
  1. package/Libraries/AppDelegate/RCTAppDelegate.mm +3 -2
  2. package/Libraries/Components/Pressable/Pressable.js +3 -36
  3. package/Libraries/Components/Pressable/useAndroidRippleForView.js +4 -4
  4. package/Libraries/Components/TV/TVViewPropTypes.js +1 -0
  5. package/Libraries/Core/ReactNativeVersion.js +2 -2
  6. package/Libraries/Pressability/Pressability.js +37 -0
  7. package/Libraries/ReactNative/AppRegistry.js +3 -3
  8. package/README.md +38 -26
  9. package/React/Base/RCTVersion.m +2 -2
  10. package/React/CoreModules/RCTDeviceInfo.mm +2 -0
  11. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +2 -0
  12. package/ReactAndroid/build.gradle.kts +0 -1
  13. package/ReactAndroid/gradle.properties +1 -1
  14. package/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java +4 -8
  15. package/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt +2 -1
  16. package/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt +1 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +0 -1
  18. package/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java +5 -57
  19. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
  20. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerDelegate.kt +2 -2
  21. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerDelegate.kt +19 -2
  22. package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
  23. package/package.json +8 -8
  24. package/scripts/cocoapods/utils.rb +4 -2
  25. package/scripts/codegen/generate-artifacts-executor.js +19 -4
  26. package/sdks/hermesc/osx-bin/hermes +0 -0
  27. package/sdks/hermesc/osx-bin/hermesc +0 -0
  28. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  29. package/sdks/hermesc/win64-bin/msvcp140.dll +0 -0
  30. package/sdks/hermesc/win64-bin/vcruntime140.dll +0 -0
  31. package/sdks/hermesc/win64-bin/vcruntime140_1.dll +0 -0
  32. package/ReactAndroid/src/main/res/views/alert/layout/alert_title_layout.xml +0 -22
@@ -76,7 +76,8 @@
76
76
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
77
77
  UIViewController *rootViewController = [self createRootViewController];
78
78
  [self setRootView:rootView toRootViewController:rootViewController];
79
- self.window.rootViewController = rootViewController;
79
+ _window.windowScene.delegate = self;
80
+ _window.rootViewController = rootViewController;
80
81
  #if TARGET_OS_TV
81
82
  UIUserInterfaceStyle style = rootViewController.traitCollection.userInterfaceStyle;
82
83
  if (style == UIUserInterfaceStyleDark) {
@@ -85,7 +86,7 @@
85
86
  rootView.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
86
87
  }
87
88
  #endif
88
- [self.window makeKeyAndVisible];
89
+ [_window makeKeyAndVisible];
89
90
  }
90
91
 
91
92
  - (void)applicationDidEnterBackground:(UIApplication *)application
@@ -392,52 +392,19 @@ function Pressable(
392
392
  // $FlowFixMe[incompatible-call]
393
393
  const eventHandlers = usePressability(config);
394
394
 
395
- const pressableTVFocusEventHandler = React.useCallback(
396
- (evt: any) => {
397
- if (isTVSelectable !== false || focusable !== false) {
398
- // $FlowFixMe[prop-missing]
399
- if (evt?.eventType === 'focus') {
400
- shouldUpdatePressed && setFocused(true);
401
- onFocus && onFocus(evt);
402
- // $FlowFixMe[prop-missing]
403
- } else if (evt.eventType === 'blur') {
404
- onBlur && onBlur(evt);
405
- shouldUpdatePressed && setFocused(false);
406
- }
407
- }
408
- // $FlowFixMe[prop-missing]
409
- if (evt.eventType === 'select') {
410
- // $FlowFixMe[incompatible-exact]
411
- onPress && onPress(evt);
412
- }
413
- // $FlowFixMe[prop-missing]
414
- if (evt.eventType === 'longSelect') {
415
- // $FlowFixMe[incompatible-exact]
416
- onLongPress && onLongPress(evt);
417
- }
418
- },
419
- [
420
- onBlur,
421
- onFocus,
422
- onLongPress,
423
- onPress,
424
- focusable,
425
- isTVSelectable,
426
- shouldUpdatePressed,
427
- ],
428
- );
429
-
430
395
  React.useEffect(() => {
431
396
  if (!tvFocusEventHandler) {
432
397
  return;
433
398
  }
399
+ const pressableTVFocusEventHandler = (evt: any) =>
400
+ eventHandlers?.onTVEvent(evt);
434
401
  // $FlowFixMe[prop-missing]
435
402
  const viewTag = tagForComponentOrHandle(viewRef?.current);
436
403
  tvFocusEventHandler.register(viewTag, pressableTVFocusEventHandler);
437
404
  return () => {
438
405
  tvFocusEventHandler.unregister(viewTag);
439
406
  };
440
- }, [pressableTVFocusEventHandler, viewRef]);
407
+ }, [eventHandlers, viewRef]);
441
408
 
442
409
  return (
443
410
  <View
@@ -80,8 +80,8 @@ export default function useAndroidRippleForView(
80
80
  if (view != null) {
81
81
  Commands.hotspotUpdate(
82
82
  view,
83
- event.nativeEvent.locationX ?? 0,
84
- event.nativeEvent.locationY ?? 0,
83
+ event.nativeEvent?.locationX ?? 0,
84
+ event.nativeEvent?.locationY ?? 0,
85
85
  );
86
86
  Commands.setPressed(view, true);
87
87
  }
@@ -91,8 +91,8 @@ export default function useAndroidRippleForView(
91
91
  if (view != null) {
92
92
  Commands.hotspotUpdate(
93
93
  view,
94
- event.nativeEvent.locationX ?? 0,
95
- event.nativeEvent.locationY ?? 0,
94
+ event.nativeEvent?.locationX ?? 0,
95
+ event.nativeEvent?.locationY ?? 0,
96
96
  );
97
97
  }
98
98
  },
@@ -85,4 +85,5 @@ export type TVViewProps = $ReadOnly<{|
85
85
  enabled?: boolean,
86
86
  autoFocus?: boolean,
87
87
  safePadding?: string | null,
88
+ onTVEvent?: (event: any) => void,
88
89
  |}>;
@@ -16,8 +16,8 @@ const version: $ReadOnly<{
16
16
  }> = {
17
17
  major: 0,
18
18
  minor: 76,
19
- patch: 0,
20
- prerelease: '0rc5',
19
+ patch: 1,
20
+ prerelease: '0',
21
21
  };
22
22
 
23
23
  module.exports = {version};
@@ -131,6 +131,11 @@ export type PressabilityConfig = $ReadOnly<{|
131
131
  */
132
132
  onPressOut?: ?(event: PressEvent) => mixed,
133
133
 
134
+ /**
135
+ * Called when a TV event is passed to the config.
136
+ */
137
+ onTVEvent?: ?(event: any) => void,
138
+
134
139
  /**
135
140
  * Whether to prevent any other native components from becoming responder
136
141
  * while this pressable is responder.
@@ -152,6 +157,7 @@ export type EventHandlers = $ReadOnly<{|
152
157
  onResponderTerminate: (event: PressEvent) => void,
153
158
  onResponderTerminationRequest: () => boolean,
154
159
  onStartShouldSetResponder: () => boolean,
160
+ onTVEvent: (event: any) => void,
155
161
  |}>;
156
162
 
157
163
  type TouchState =
@@ -430,6 +436,35 @@ export default class Pressability {
430
436
  }
431
437
 
432
438
  _createEventHandlers(): EventHandlers {
439
+ const tvEventHandlers = {
440
+ onTVEvent: (evt: any): void => {
441
+ if (this._config.disabled !== false) {
442
+ // $FlowFixMe[prop-missing]
443
+ if (evt?.eventType === 'focus') {
444
+ const {onFocus} = this._config;
445
+ onFocus && onFocus(evt);
446
+ // $FlowFixMe[prop-missing]
447
+ } else if (evt.eventType === 'blur') {
448
+ const {onBlur} = this._config;
449
+ onBlur && onBlur(evt);
450
+ } else if (evt.eventType === 'select') {
451
+ const {onPress, onPressIn, onPressOut} = this._config;
452
+ // $FlowFixMe[incompatible-exact]
453
+ onPressIn && onPressIn(evt);
454
+ onPress && onPress(evt);
455
+ setTimeout(() => {
456
+ onPressOut && onPressOut(evt);
457
+ }, this._config.minPressDuration ?? DEFAULT_MIN_PRESS_DURATION);
458
+ } else if (evt.eventType === 'longSelect') {
459
+ const {onLongPress, onPressIn, onPressOut} = this._config;
460
+ onLongPress && onLongPress(evt);
461
+ evt?.eventKeyAction === 0
462
+ ? onPressIn && onPressIn(evt)
463
+ : onPressOut && onPressOut(evt);
464
+ }
465
+ }
466
+ },
467
+ };
433
468
  const focusEventHandlers = {
434
469
  onBlur: (event: BlurEvent): void => {
435
470
  const {onBlur} = this._config;
@@ -610,6 +645,7 @@ export default class Pressability {
610
645
  };
611
646
  }
612
647
  return {
648
+ ...tvEventHandlers,
613
649
  ...focusEventHandlers,
614
650
  ...responderEventHandlers,
615
651
  ...hoverPointerEvents,
@@ -662,6 +698,7 @@ export default class Pressability {
662
698
  },
663
699
  };
664
700
  return {
701
+ ...tvEventHandlers,
665
702
  ...focusEventHandlers,
666
703
  ...responderEventHandlers,
667
704
  ...mouseEventHandlers,
@@ -13,7 +13,7 @@ import type {RootTag} from '../Types/RootTagTypes';
13
13
  import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
14
14
  import type {DisplayModeType} from './DisplayMode';
15
15
 
16
- import BatchedBridge from '../BatchedBridge/BatchedBridge';
16
+ import registerCallableModule from '../Core/registerCallableModule';
17
17
  import BugReporting from '../BugReporting/BugReporting';
18
18
  import createPerformanceLogger from '../Utilities/createPerformanceLogger';
19
19
  import infoLog from '../Utilities/infoLog';
@@ -363,8 +363,8 @@ global.RN$SurfaceRegistry = {
363
363
 
364
364
  if (global.RN$Bridgeless === true) {
365
365
  console.log('Bridgeless mode is enabled');
366
- } else {
367
- BatchedBridge.registerCallableModule('AppRegistry', AppRegistry);
368
366
  }
369
367
 
368
+ registerCallableModule('AppRegistry', AppRegistry);
369
+
370
370
  module.exports = AppRegistry;
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.75.2-0 release of this package will be derived from the 0.75.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.
5
+ Releases of `react-native-tvos` will be based on a public release of `react-native`; e.g. the 0.76.0-0 release of this package will be derived from the 0.76.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
 
@@ -23,20 +23,29 @@ This README covers only TV-specific features. For more general documentation and
23
23
 
24
24
  ### Hermes JS support
25
25
 
26
- As of the 0.71 release, Hermes is fully working on both Apple TV and Android TV, and is enabled by default.
26
+ - As of the 0.71 release, Hermes is fully working on both Apple TV and Android TV, and is enabled by default.
27
27
 
28
28
  ### React Native new architecture (Fabric) support
29
29
 
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. Components that have not been reimplemented in the new architecture will show up as an "unimplemented component".
31
- - _Android TV_: To enable Fabric, modify `android/gradle.properties` in your app and set `newArchEnabled=true`, then rebuild your app.
30
+ React Native TV 0.76 enables the New Architecture by default. You can read more about it in this blog post from the RN core team: [The New Architecture Is Here](https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here)
32
31
 
33
- As of the 0.74 release, bridgeless is the default when Fabric 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`:
32
+ If, for any reason, the New Architecture is not behaving properly in your application, there is always the option to opt-out from it until you are ready to turn it on again.
34
33
 
35
- ```objc
36
- - (BOOL)bridgelessEnabled
37
- {
38
- return false;
39
- }
34
+ To opt-out from the New Architecture:
35
+
36
+ - _Expo apps_: RN 0.76 will be supported in SDK 52. See the [SDK 52 beta release notes](https://expo.dev/changelog/2024/10-24-sdk-52-beta) for more information on new arch support in Expo.
37
+
38
+ - _Apple TV_: You can reinstall the dependencies by running the command:
39
+
40
+ ```sh
41
+ RCT_NEW_ARCH_ENABLED=0 bundle exec pod install
42
+ ```
43
+
44
+ - _Android TV_: On Android, modify the android/gradle.properties file and turn off the newArchEnabled flag, then do a clean rebuild:
45
+
46
+ ```diff
47
+ -newArchEnabled=true
48
+ +newArchEnabled=false
40
49
  ```
41
50
 
42
51
  ### Typescript
@@ -51,17 +60,19 @@ The RNTester app supports Apple TV and Android TV. In this repo, `RNTester/Podf
51
60
 
52
61
  Minimum operating system versions:
53
62
 
54
- - Apple TV: tvOS 13.4
63
+ - Apple TV:
64
+ - tvOS 13.4 (for the 0.74 and 0.75 releases)
65
+ - tvOS 15.1 (for the 0.76 release)
55
66
  - Android TV:
56
- - API level 21 (for the 0.73 releases)
57
- - API level 23 (for the 0.74 release)
67
+ - API level 23 (for the 0.74 and 0.75 releases)
68
+ - API level 24 (for the 0.76 release)
58
69
 
59
70
  ## Build changes
60
71
 
61
- - _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.
72
+ - _Native layer for Apple TV_: Changes in the React Native podspecs (in 0.73 and later) require that your application `Podfile` only have one target. This repo supports either an iOS target or a tvOS target.
62
73
  - _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.
63
74
 
64
- ## _(New)_ TV project creation in React Native 0.75 and later
75
+ ## TV project creation in React Native 0.75 and later
65
76
 
66
77
  > _Warning:_ 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`.
67
78
 
@@ -81,7 +92,7 @@ As of React Native 0.75.x, the template that used to reside in the `react-native
81
92
 
82
93
  > _Note:_ The new TV template will only build apps for Apple TV and Android TV. Multiple platform targets are no longer supported in React Native app Podfiles.
83
94
 
84
- To create a new project:
95
+ To create a new project for RNTV 0.76:
85
96
 
86
97
  ```sh
87
98
  #
@@ -115,7 +126,7 @@ $ npx @react-native-community/cli@latest init TVTest --template @react-native-tv
115
126
  ###### ######
116
127
 
117
128
 
118
- Welcome to React Native 0.75.2!
129
+ Welcome to React Native 0.76!
119
130
  Learn once, write anywhere
120
131
 
121
132
  ✔ Downloading template
@@ -135,8 +146,6 @@ npx react-native run-ios --simulator "Apple TV"
135
146
  npx react-native run:android --device tv_api_31
136
147
  ```
137
148
 
138
- See [this document](https://docs.expo.dev/bare/using-expo-cli/) for more details on Expo CLI functionality. (Note that many of these features require that Expo SDK modules be built into your app. Expo SDK support requires a different project configuration as described below.)
139
-
140
149
  ## How to support TV specific file extensions
141
150
 
142
151
  The template contains an [example Metro configuration](./packages/react-native/template/metro.config.js) that allows Metro to resolve application source files with TV-specific code, indicated by specific file extensions (e.g. `*.ios.tv.tsx`, `*.android.tv.tsx`, `*.tv.tsx`). The config will work the same way with the other standard source file extensions (`.js`, etc.), as documented in [Metro docs](https://metrobundler.dev/docs/configuration/#sourceexts)
@@ -169,13 +178,18 @@ var running_on_apple_tv = Platform.isTVOS;
169
178
 
170
179
  - _Access to touchable controls_: The `Touchable` mixin has code added to detect focus changes and use existing methods to style the components properly and initiate the proper actions when the view is selected using the TV remote, so `TouchableWithoutFeedback`, `TouchableHighlight` and `TouchableOpacity` will "just work" on both Apple TV and Android TV. In particular:
171
180
 
172
- - `onFocus` will be executed when the touchable view goes into focus
173
- - `onBlur` will be executed when the touchable view goes out of focus
174
- - `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).
175
- - `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).
181
+ - `onFocus()` will be executed when the touchable view goes into focus
182
+ - `onBlur()` will be executed when the touchable view goes out of focus
183
+ - `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).
184
+ - `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).
176
185
 
177
186
  - _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.
178
187
 
188
+ - _Tailwind styles for Pressable controls_: For the 0.76 release, the `Pressable` component also generates the `onPressIn()` and `onPressOut()` events needed to support the [`active:` pseudo class for Tailwind styles](https://www.nativewind.dev/v4/core-concepts/states#hover-focus-and-active-).
189
+ - For `onPress()` events (the "select" button on the remote is pressed once), `onPressIn()` is generated, then `onPressOut()` is generated a short time later.
190
+ - For `onLongPress()` events (the "select" button on the remote is held down for a length of time), `onPressIn()` is generated once the press down is detected, and `onPressOut()` is generated when the button is released.
191
+ - The `focus:` pseudo class is also supported via the `onFocus()` and `onBlur()` events.
192
+
179
193
  - _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`.
180
194
 
181
195
  ```javascript
@@ -244,8 +258,6 @@ class Game2048 extends React.Component {
244
258
  }
245
259
  ```
246
260
 
247
- - _Flipper_: We do not support Flipper.
248
-
249
261
  - _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.
250
262
 
251
263
  - _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.
@@ -259,7 +271,7 @@ class Game2048 extends React.Component {
259
271
  - `enableTVPanGesture`/`disableTVPanGesture`: Methods to enable and disable detection of finger touches that pan across the touch surface of the Siri remote. See `TVEventHandlerExample` in the `RNTester` app for a demo.
260
272
  - `enableGestureHandlersCancelTouches`/`disableGestureHandlersCancelTouches`: Methods to turn on and turn off cancellation of touches by the gesture handlers in `RCTTVRemoteHandler` (see #366). Cancellation of touches is turned on (enabled) by default in 0.69 and earlier releases.
261
273
 
262
- - Accessibility: We have an additional `accessibilityFocus` [accessibility action](https://reactnative.dev/docs/accessibility#accessibility-actions) on Android that you can use for detecting focus changes on every *accessible* element (like a regular `Text`) when `TalkBack` is enabled.
274
+ - _Accessibility_: We have an additional `accessibilityFocus` [accessibility action](https://reactnative.dev/docs/accessibility#accessibility-actions) on Android that you can use for detecting focus changes on every *accessible* element (like a regular `Text`) when `TalkBack` is enabled.
263
275
 
264
276
  - _TVFocusGuideView_: This component provides support for Apple's `UIFocusGuide` API and is implemented in the same way for Android TV, to help ensure that focusable controls can be navigated to, even if they are not directly in line with other controls. An example is provided in `RNTester` that shows two different ways of using this component.
265
277
 
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(76),
26
- RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"0rc5",
26
+ RCTVersionPatch: @(1),
27
+ RCTVersionPrerelease: @"0",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -56,6 +56,7 @@ RCT_EXPORT_MODULE()
56
56
 
57
57
  _currentInterfaceDimensions = [self _exportedDimensions];
58
58
 
59
+ #if !TARGET_OS_TV
59
60
  [[NSNotificationCenter defaultCenter] addObserver:self
60
61
  selector:@selector(interfaceOrientationDidChange)
61
62
  name:UIApplicationDidBecomeActiveNotification
@@ -70,6 +71,7 @@ RCT_EXPORT_MODULE()
70
71
  selector:@selector(interfaceFrameDidChange)
71
72
  name:RCTWindowFrameDidChangeNotification
72
73
  object:nil];
74
+ #endif
73
75
 
74
76
  #if TARGET_OS_IOS
75
77
 
@@ -1479,6 +1479,8 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
1479
1479
  _backgroundColorLayer.mask = maskLayer;
1480
1480
  _backgroundColorLayer.cornerRadius = 0;
1481
1481
  }
1482
+
1483
+ [_backgroundColorLayer removeAllAnimations];
1482
1484
  }
1483
1485
 
1484
1486
  // borders
@@ -559,7 +559,6 @@ android {
559
559
  listOf(
560
560
  "src/main/res/devsupport",
561
561
  "src/main/res/shell",
562
- "src/main/res/views/alert",
563
562
  "src/main/res/views/modal",
564
563
  "src/main/res/views/uimanager"))
565
564
  java.exclude("com/facebook/react/processing")
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.76.0-0rc5
1
+ VERSION_NAME=0.76.1-0
2
2
  react.internal.publishingGroup=io.github.react-native-tvos
3
3
 
4
4
  android.useAndroidX=true
@@ -124,15 +124,11 @@ public abstract class HeadlessJsTaskService extends Service implements HeadlessJ
124
124
  @Override
125
125
  public void onDestroy() {
126
126
  super.onDestroy();
127
+ ReactContext reactContext = getReactContext();
127
128
 
128
- if (getReactNativeHost().hasInstance()) {
129
- ReactInstanceManager reactInstanceManager = getReactNativeHost().getReactInstanceManager();
130
- ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
131
- if (reactContext != null) {
132
- HeadlessJsTaskContext headlessJsTaskContext =
133
- HeadlessJsTaskContext.getInstance(reactContext);
134
- headlessJsTaskContext.removeTaskEventListener(this);
135
- }
129
+ if (reactContext != null) {
130
+ HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(reactContext);
131
+ headlessJsTaskContext.removeTaskEventListener(this);
136
132
  }
137
133
  if (sWakeLock != null) {
138
134
  sWakeLock.release();
@@ -12,6 +12,7 @@ import androidx.annotation.AnyThread
12
12
  import androidx.annotation.UiThread
13
13
  import com.facebook.infer.annotation.ThreadConfined
14
14
  import com.facebook.react.common.annotations.UnstableReactNativeAPI
15
+ import com.facebook.react.uimanager.events.EventDispatcher
15
16
 
16
17
  @OptIn(UnstableReactNativeAPI::class)
17
18
  public interface UIManager : PerformanceCounter {
@@ -78,7 +79,7 @@ public interface UIManager : PerformanceCounter {
78
79
  public fun dispatchCommand(reactTag: Int, commandId: String, commandArgs: ReadableArray?)
79
80
 
80
81
  /** @return the [EventDispatcher] object that is used by this class. */
81
- public fun <T> getEventDispatcher(): T
82
+ public val eventDispatcher: EventDispatcher
82
83
 
83
84
  /**
84
85
  * Used by native animated module to bypass the process of updating the values through the shadow
@@ -111,7 +111,7 @@ protected constructor(
111
111
  packages,
112
112
  jsMainModuleName,
113
113
  bundleAssetName ?: "index",
114
- null,
114
+ jsBundleFile,
115
115
  isHermesEnabled ?: true,
116
116
  useDeveloperSupport,
117
117
  )
@@ -1021,7 +1021,6 @@ public class FabricUIManager
1021
1021
 
1022
1022
  @Override
1023
1023
  @NonNull
1024
- @SuppressWarnings("unchecked")
1025
1024
  public EventDispatcher getEventDispatcher() {
1026
1025
  return mEventDispatcher;
1027
1026
  }
@@ -12,20 +12,11 @@ import android.app.Dialog;
12
12
  import android.content.Context;
13
13
  import android.content.DialogInterface;
14
14
  import android.content.res.TypedArray;
15
- import android.os.Build;
16
15
  import android.os.Bundle;
17
- import android.view.LayoutInflater;
18
- import android.view.View;
19
- import android.widget.TextView;
20
16
  import androidx.annotation.Nullable;
21
17
  import androidx.appcompat.app.AlertDialog;
22
- import androidx.core.view.AccessibilityDelegateCompat;
23
- import androidx.core.view.ViewCompat;
24
- import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
25
18
  import androidx.fragment.app.DialogFragment;
26
- import com.facebook.infer.annotation.Assertions;
27
19
  import com.facebook.infer.annotation.Nullsafe;
28
- import com.facebook.react.R;
29
20
 
30
21
  /** A fragment used to display the dialog. */
31
22
  @Nullsafe(Nullsafe.Mode.LOCAL)
@@ -75,55 +66,15 @@ public class AlertFragment extends DialogFragment implements DialogInterface.OnC
75
66
  return isAppCompat;
76
67
  }
77
68
 
78
- /**
79
- * Creates a custom dialog title View that has the role of "Heading" and focusable for
80
- * accessibility purposes.
81
- *
82
- * @returns accessible TextView title
83
- */
84
- private static View getAccessibleTitle(Context activityContext, String titleText) {
85
- LayoutInflater inflater = LayoutInflater.from(activityContext);
86
-
87
- // This layout matches the sizing and styling of AlertDialog's title_template (minus the icon)
88
- // since the whole thing gets tossed out when setting a custom title
89
- View titleContainer = inflater.inflate(R.layout.alert_title_layout, null);
90
-
91
- TextView accessibleTitle =
92
- Assertions.assertNotNull(titleContainer.findViewById(R.id.alert_title));
93
- accessibleTitle.setText(titleText);
94
- accessibleTitle.setFocusable(true);
95
-
96
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
97
- accessibleTitle.setAccessibilityHeading(true);
98
- } else {
99
- ViewCompat.setAccessibilityDelegate(
100
- accessibleTitle,
101
- new AccessibilityDelegateCompat() {
102
- @Override
103
- public void onInitializeAccessibilityNodeInfo(
104
- View view, AccessibilityNodeInfoCompat info) {
105
- super.onInitializeAccessibilityNodeInfo(accessibleTitle, info);
106
- info.setHeading(true);
107
- }
108
- });
109
- }
110
-
111
- return titleContainer;
112
- }
113
-
114
69
  /**
115
70
  * Creates a dialog compatible only with AppCompat activities. This function should be kept in
116
71
  * sync with {@link createAppDialog}.
117
72
  */
118
73
  private static Dialog createAppCompatDialog(
119
74
  Context activityContext, Bundle arguments, DialogInterface.OnClickListener fragment) {
120
- AlertDialog.Builder builder = new AlertDialog.Builder(activityContext);
75
+ AlertDialog.Builder builder =
76
+ new AlertDialog.Builder(activityContext).setTitle(arguments.getString(ARG_TITLE));
121
77
 
122
- if (arguments.containsKey(ARG_TITLE)) {
123
- String title = Assertions.assertNotNull(arguments.getString(ARG_TITLE));
124
- View accessibleTitle = getAccessibleTitle(activityContext, title);
125
- builder.setCustomTitle(accessibleTitle);
126
- }
127
78
  if (arguments.containsKey(ARG_BUTTON_POSITIVE)) {
128
79
  builder.setPositiveButton(arguments.getString(ARG_BUTTON_POSITIVE), fragment);
129
80
  }
@@ -154,13 +105,10 @@ public class AlertFragment extends DialogFragment implements DialogInterface.OnC
154
105
  @Deprecated(since = "0.75.0", forRemoval = true)
155
106
  private static Dialog createAppDialog(
156
107
  Context activityContext, Bundle arguments, DialogInterface.OnClickListener fragment) {
157
- android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(activityContext);
108
+ android.app.AlertDialog.Builder builder =
109
+ new android.app.AlertDialog.Builder(activityContext)
110
+ .setTitle(arguments.getString(ARG_TITLE));
158
111
 
159
- if (arguments.containsKey(ARG_TITLE)) {
160
- String title = Assertions.assertNotNull(arguments.getString(ARG_TITLE));
161
- View accessibleTitle = getAccessibleTitle(activityContext, title);
162
- builder.setCustomTitle(accessibleTitle);
163
- }
164
112
  if (arguments.containsKey(ARG_BUTTON_POSITIVE)) {
165
113
  builder.setPositiveButton(arguments.getString(ARG_BUTTON_POSITIVE), fragment);
166
114
  }
@@ -17,6 +17,6 @@ public class ReactNativeVersion {
17
17
  public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
18
18
  "major", 0,
19
19
  "minor", 76,
20
- "patch", 0,
21
- "prerelease", "0rc5");
20
+ "patch", 1,
21
+ "prerelease", "0");
22
22
  }
@@ -22,7 +22,7 @@ import com.facebook.yoga.YogaConstants
22
22
  public abstract class BaseViewManagerDelegate<T : View, U : BaseViewManagerInterface<T>>(
23
23
  @Suppress("NoHungarianNotation") @JvmField protected val mViewManager: U
24
24
  ) : ViewManagerDelegate<T> {
25
- override public fun setProperty(view: T, propName: String, value: Any?) {
25
+ override public fun setProperty(view: T, propName: String?, value: Any?) {
26
26
  when (propName) {
27
27
  ViewProps.ACCESSIBILITY_ACTIONS ->
28
28
  mViewManager.setAccessibilityActions(view, value as ReadableArray?)
@@ -104,6 +104,6 @@ public abstract class BaseViewManagerDelegate<T : View, U : BaseViewManagerInter
104
104
  }
105
105
  }
106
106
 
107
- override public fun receiveCommand(view: T, commandName: String, args: ReadableArray?): Unit =
107
+ override public fun receiveCommand(view: T, commandName: String?, args: ReadableArray?): Unit =
108
108
  Unit
109
109
  }
@@ -18,7 +18,24 @@ import com.facebook.react.bridge.ReadableArray
18
18
  * @param <T> the type of the view supported by this delegate </T>
19
19
  */
20
20
  public interface ViewManagerDelegate<T : View?> {
21
- public fun setProperty(view: T, propName: String, value: Any?)
22
21
 
23
- public fun receiveCommand(view: T, commandName: String, args: ReadableArray?)
22
+ /**
23
+ * Sets a property on a view managed by this view manager.
24
+ *
25
+ * @param view the view to set the property on
26
+ * @param propName the name of the property to set (NOTE: should be `String` but is kept as
27
+ * `String?` to avoid breaking changes)
28
+ * @param value the value to set the property to
29
+ */
30
+ public fun setProperty(view: T, propName: String?, value: Any?)
31
+
32
+ /**
33
+ * Executes a command from JS to the view
34
+ *
35
+ * @param view the view to execute the command on
36
+ * @param commandName the name of the command to execute (NOTE: should be `String` but is kept as
37
+ * `String?` to avoid breaking changes)
38
+ * @param args the arguments to pass to the command
39
+ */
40
+ public fun receiveCommand(view: T, commandName: String?, args: ReadableArray?)
24
41
  }
@@ -17,8 +17,8 @@ namespace facebook::react {
17
17
  constexpr struct {
18
18
  int32_t Major = 0;
19
19
  int32_t Minor = 76;
20
- int32_t Patch = 0;
21
- std::string_view Prerelease = "0rc5";
20
+ int32_t Patch = 1;
21
+ std::string_view Prerelease = "0";
22
22
  } ReactNativeVersion;
23
23
 
24
24
  } // namespace facebook::react
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-tvos",
3
- "version": "0.76.0-0rc5",
3
+ "version": "0.76.1-0",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -110,13 +110,13 @@
110
110
  },
111
111
  "dependencies": {
112
112
  "@jest/create-cache-key-function": "^29.6.3",
113
- "@react-native/assets-registry": "0.76.0-rc.5",
114
- "@react-native/codegen": "0.76.0-rc.5",
115
- "@react-native/community-cli-plugin": "0.76.0-rc.5",
116
- "@react-native/gradle-plugin": "0.76.0-rc.5",
117
- "@react-native/js-polyfills": "0.76.0-rc.5",
118
- "@react-native/normalize-colors": "0.76.0-rc.5",
119
- "@react-native-tvos/virtualized-lists": "0.76.0-0rc5",
113
+ "@react-native/assets-registry": "0.76.1",
114
+ "@react-native/codegen": "0.76.1",
115
+ "@react-native/community-cli-plugin": "0.76.1",
116
+ "@react-native/gradle-plugin": "0.76.1",
117
+ "@react-native/js-polyfills": "0.76.1",
118
+ "@react-native/normalize-colors": "0.76.1",
119
+ "@react-native-tvos/virtualized-lists": "0.76.1-0",
120
120
  "abort-controller": "^3.0.0",
121
121
  "anser": "^1.4.9",
122
122
  "ansi-regex": "^5.0.0",
@@ -3,6 +3,8 @@
3
3
  # This source code is licensed under the MIT license found in the
4
4
  # LICENSE file in the root directory of this source tree.
5
5
 
6
+ require 'shellwords'
7
+
6
8
  require_relative "./helpers.rb"
7
9
 
8
10
  # Utilities class for React Native Cocoapods
@@ -237,8 +239,8 @@ class ReactNativePodsUtils
237
239
  # When installing pods with a yarn alias, yarn creates a fake yarn and node executables
238
240
  # in a temporary folder.
239
241
  # Using `node --print "process.argv[0]";` we are able to retrieve the actual path from which node is running.
240
- # see https://github.com/facebook/react-native/issues/43285 for more info
241
- node_binary = `node --print "process.argv[0]";`
242
+ # see https://github.com/facebook/react-native/issues/43285 for more info. We've tweaked this slightly.
243
+ node_binary = Shellwords.escape(`node --print "process.argv[0]"`.strip)
242
244
  system("echo 'export NODE_BINARY=#{node_binary}' > #{file_path}.local")
243
245
  end
244
246
  end
@@ -490,11 +490,22 @@ function rootCodegenTargetNeedsThirdPartyComponentProvider(pkgJson, platform) {
490
490
  return !pkgJsonIncludesGeneratedCode(pkgJson) && platform === 'ios';
491
491
  }
492
492
 
493
- function dependencyNeedsThirdPartyComponentProvider(schemaInfo, platform) {
493
+ function dependencyNeedsThirdPartyComponentProvider(
494
+ schemaInfo,
495
+ platform,
496
+ appCondegenConfigSpec,
497
+ ) {
494
498
  // Filter the react native core library out.
495
499
  // In the future, core library and third party library should
496
500
  // use the same way to generate/register the fabric components.
497
- return !isReactNativeCoreLibrary(schemaInfo.library.config.name, platform);
501
+ // We also have to filter out the the components defined in the app
502
+ // because the RCTThirdPartyComponentProvider is generated inside Fabric,
503
+ // which lives in a different target from the app and it has no visibility over
504
+ // the symbols defined in the app.
505
+ return (
506
+ !isReactNativeCoreLibrary(schemaInfo.library.config.name, platform) &&
507
+ schemaInfo.library.config.name !== appCondegenConfigSpec
508
+ );
498
509
  }
499
510
 
500
511
  function mustGenerateNativeCode(includeLibraryPath, schemaInfo) {
@@ -705,8 +716,12 @@ function execute(projectRoot, targetPlatform, baseOutputPath) {
705
716
  if (
706
717
  rootCodegenTargetNeedsThirdPartyComponentProvider(pkgJson, platform)
707
718
  ) {
708
- const filteredSchemas = schemaInfos.filter(
709
- dependencyNeedsThirdPartyComponentProvider,
719
+ const filteredSchemas = schemaInfos.filter(schemaInfo =>
720
+ dependencyNeedsThirdPartyComponentProvider(
721
+ schemaInfo,
722
+ platform,
723
+ pkgJson.codegenConfig?.appCondegenConfigSpec,
724
+ ),
710
725
  );
711
726
  const schemas = filteredSchemas.map(schemaInfo => schemaInfo.schema);
712
727
  const supportedApplePlatforms = filteredSchemas.map(
Binary file
Binary file
Binary file
Binary file
@@ -1,22 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
- android:layout_width="match_parent"
4
- android:layout_height="wrap_content"
5
- android:gravity="center_vertical|start"
6
- android:orientation="horizontal"
7
- android:paddingStart="?android:attr/dialogPreferredPadding"
8
- android:paddingTop="18dp"
9
- android:paddingEnd="?android:attr/dialogPreferredPadding">
10
-
11
- <TextView
12
- android:id="@+id/alert_title"
13
- style="?android:attr/windowTitleStyle"
14
- android:layout_width="match_parent"
15
- android:layout_height="wrap_content"
16
- android:ellipsize="end"
17
- android:singleLine="true"
18
- android:textAlignment="viewStart"
19
- android:textAppearance="?android:attr/textAppearanceMedium"
20
- android:textSize="18sp" />
21
-
22
- </LinearLayout>