react-native-tvos 0.68.0-0 → 0.68.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 (125) hide show
  1. package/Libraries/Components/AppleTV/{TVMenuControl.js → TVEventControl.js} +8 -0
  2. package/Libraries/Components/AppleTV/tagForComponentOrHandle.js +34 -0
  3. package/Libraries/Components/Touchable/TouchableHighlight.js +19 -5
  4. package/Libraries/Components/Touchable/TouchableOpacity.js +10 -7
  5. package/Libraries/Core/ReactNativeVersion.js +1 -1
  6. package/README.md +5 -2
  7. package/React/Base/RCTRootView.m +2 -3
  8. package/React/Base/RCTRootViewInternal.h +1 -1
  9. package/React/Base/RCTTVRemoteHandler.h +26 -15
  10. package/React/Base/RCTTVRemoteHandler.m +128 -20
  11. package/React/Base/RCTVersion.m +1 -1
  12. package/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm +1 -1
  13. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +4 -0
  14. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +83 -30
  15. package/React/Modules/RCTTVMenuBridge.m +12 -0
  16. package/React/Views/RCTTVView.h +9 -5
  17. package/React/Views/RCTTVView.m +98 -52
  18. package/ReactAndroid/build.gradle +12 -4
  19. package/ReactAndroid/gradle.properties +1 -1
  20. package/ReactAndroid/src/main/java/com/facebook/hermes/instrumentation/Android.mk +1 -0
  21. package/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/Android.mk +2 -0
  22. package/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer/jni/Android.mk +1 -0
  23. package/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +1 -0
  24. package/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/Android.mk +1 -0
  25. package/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk +1 -0
  26. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
  27. package/ReactAndroid/src/main/java/com/facebook/react/reactperflogger/jni/Android.mk +1 -0
  28. package/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/Android.mk +2 -0
  29. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/jni/Android.mk +1 -0
  30. package/ReactAndroid/src/main/jni/first-party/yogajni/Android.mk +1 -0
  31. package/ReactAndroid/src/main/jni/react/jni/Android.mk +2 -0
  32. package/ReactAndroid/src/main/jni/third-party/boost/Android.mk +1 -0
  33. package/ReactCommon/butter/Android.mk +1 -0
  34. package/ReactCommon/cxxreact/Android.mk +1 -0
  35. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  36. package/ReactCommon/hermes/executor/Android.mk +2 -0
  37. package/ReactCommon/hermes/inspector/Android.mk +1 -0
  38. package/ReactCommon/hermes/inspector/tools/msggen/yarn.lock +6 -6
  39. package/ReactCommon/jsi/Android.mk +2 -0
  40. package/ReactCommon/jsiexecutor/Android.mk +1 -0
  41. package/ReactCommon/jsinspector/Android.mk +1 -0
  42. package/ReactCommon/logger/Android.mk +1 -0
  43. package/ReactCommon/react/config/Android.mk +1 -0
  44. package/ReactCommon/react/debug/Android.mk +1 -0
  45. package/ReactCommon/react/nativemodule/core/Android.mk +1 -0
  46. package/ReactCommon/react/nativemodule/samples/platform/android/Android.mk +1 -0
  47. package/ReactCommon/react/renderer/animations/Android.mk +1 -0
  48. package/ReactCommon/react/renderer/attributedstring/Android.mk +1 -0
  49. package/ReactCommon/react/renderer/componentregistry/Android.mk +1 -0
  50. package/ReactCommon/react/renderer/componentregistry/native/Android.mk +1 -0
  51. package/ReactCommon/react/renderer/components/image/Android.mk +1 -0
  52. package/ReactCommon/react/renderer/components/modal/Android.mk +1 -0
  53. package/ReactCommon/react/renderer/components/progressbar/Android.mk +1 -0
  54. package/ReactCommon/react/renderer/components/root/Android.mk +1 -0
  55. package/ReactCommon/react/renderer/components/scrollview/Android.mk +1 -0
  56. package/ReactCommon/react/renderer/components/slider/Android.mk +1 -0
  57. package/ReactCommon/react/renderer/components/switch/Android.mk +1 -0
  58. package/ReactCommon/react/renderer/components/text/Android.mk +1 -0
  59. package/ReactCommon/react/renderer/components/textinput/Android.mk +1 -0
  60. package/ReactCommon/react/renderer/components/unimplementedview/Android.mk +1 -0
  61. package/ReactCommon/react/renderer/components/view/Android.mk +1 -0
  62. package/ReactCommon/react/renderer/core/Android.mk +1 -0
  63. package/ReactCommon/react/renderer/debug/Android.mk +1 -0
  64. package/ReactCommon/react/renderer/graphics/Android.mk +1 -0
  65. package/ReactCommon/react/renderer/imagemanager/Android.mk +1 -0
  66. package/ReactCommon/react/renderer/leakchecker/Android.mk +1 -0
  67. package/ReactCommon/react/renderer/mapbuffer/Android.mk +1 -0
  68. package/ReactCommon/react/renderer/mounting/Android.mk +1 -0
  69. package/ReactCommon/react/renderer/runtimescheduler/Android.mk +1 -0
  70. package/ReactCommon/react/renderer/scheduler/Android.mk +1 -0
  71. package/ReactCommon/react/renderer/telemetry/Android.mk +1 -0
  72. package/ReactCommon/react/renderer/templateprocessor/Android.mk +1 -0
  73. package/ReactCommon/react/renderer/textlayoutmanager/Android.mk +1 -0
  74. package/ReactCommon/react/renderer/uimanager/Android.mk +1 -0
  75. package/ReactCommon/react/utils/Android.mk +1 -0
  76. package/ReactCommon/reactperflogger/Android.mk +1 -0
  77. package/ReactCommon/yoga/Android.mk +1 -0
  78. package/android/com/facebook/react/react-native/{0.68.0-0/react-native-0.68.0-0-sources.jar → 0.68.2-0/react-native-0.68.2-0-sources.jar} +0 -0
  79. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0-sources.jar.md5 +1 -0
  80. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0-sources.jar.sha1 +1 -0
  81. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0-sources.jar.sha256 +1 -0
  82. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0-sources.jar.sha512 +1 -0
  83. package/android/com/facebook/react/react-native/{0.68.0-0/react-native-0.68.0-0.aar → 0.68.2-0/react-native-0.68.2-0.aar} +0 -0
  84. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.aar.md5 +1 -0
  85. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.aar.sha1 +1 -0
  86. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.aar.sha256 +1 -0
  87. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.aar.sha512 +1 -0
  88. package/android/com/facebook/react/react-native/{0.68.0-0/react-native-0.68.0-0.module → 0.68.2-0/react-native-0.68.2-0.module} +15 -15
  89. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.module.md5 +1 -0
  90. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.module.sha1 +1 -0
  91. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.module.sha256 +1 -0
  92. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.module.sha512 +1 -0
  93. package/android/com/facebook/react/react-native/{0.68.0-0/react-native-0.68.0-0.pom → 0.68.2-0/react-native-0.68.2-0.pom} +1 -1
  94. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.pom.md5 +1 -0
  95. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.pom.sha1 +1 -0
  96. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.pom.sha256 +1 -0
  97. package/android/com/facebook/react/react-native/0.68.2-0/react-native-0.68.2-0.pom.sha512 +1 -0
  98. package/android/com/facebook/react/react-native/maven-metadata.xml +4 -4
  99. package/android/com/facebook/react/react-native/maven-metadata.xml.md5 +1 -1
  100. package/android/com/facebook/react/react-native/maven-metadata.xml.sha1 +1 -1
  101. package/android/com/facebook/react/react-native/maven-metadata.xml.sha256 +1 -1
  102. package/android/com/facebook/react/react-native/maven-metadata.xml.sha512 +1 -1
  103. package/index.js +9 -2
  104. package/package.json +5 -5
  105. package/template/Gemfile.lock +2 -2
  106. package/template/android/app/build.gradle +10 -0
  107. package/template/android/build.gradle +10 -1
  108. package/template/package.json +1 -1
  109. package/tvos-types.d.ts +23 -18
  110. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0-sources.jar.md5 +0 -1
  111. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0-sources.jar.sha1 +0 -1
  112. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0-sources.jar.sha256 +0 -1
  113. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0-sources.jar.sha512 +0 -1
  114. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.aar.md5 +0 -1
  115. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.aar.sha1 +0 -1
  116. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.aar.sha256 +0 -1
  117. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.aar.sha512 +0 -1
  118. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.module.md5 +0 -1
  119. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.module.sha1 +0 -1
  120. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.module.sha256 +0 -1
  121. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.module.sha512 +0 -1
  122. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.pom.md5 +0 -1
  123. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.pom.sha1 +0 -1
  124. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.pom.sha256 +0 -1
  125. package/android/com/facebook/react/react-native/0.68.0-0/react-native-0.68.0-0.pom.sha512 +0 -1
@@ -1,4 +1,6 @@
1
1
  /**
2
+ * Methods to enable and disable listening for Apple TV remote events (menu key, pan gesture)
3
+ *
2
4
  * @format
3
5
  * @flow
4
6
  */
@@ -14,4 +16,10 @@ module.exports = {
14
16
  disableTVMenuKey: () => {
15
17
  TVMenuBridge && TVMenuBridge.disableTVMenuKey();
16
18
  },
19
+ enableTVPanGesture: () => {
20
+ TVMenuBridge && TVMenuBridge.enableTVPanGesture();
21
+ },
22
+ disableTVPanGesture: () => {
23
+ TVMenuBridge && TVMenuBridge.disableTVPanGesture();
24
+ },
17
25
  };
@@ -0,0 +1,34 @@
1
+ // Replacement for findNodeHandle, since we need this for converting
2
+ // components to tags when rendering nextFocus props
3
+ // @flow
4
+
5
+ // TODO: make this work for Fabric
6
+
7
+ // import {findNodeHandle} from '../../Renderer/shims/ReactNative';
8
+
9
+ type TagForComponentOrHandleType = (
10
+ component: ?(
11
+ | {_nativeTag: ?number, canonical: ?{_nativeTag: ?number}}
12
+ | number
13
+ ),
14
+ ) => ?number;
15
+
16
+ const tagForComponentOrHandle: TagForComponentOrHandleType = (
17
+ component: ?(
18
+ | {_nativeTag: ?number, canonical: ?{_nativeTag: ?number}}
19
+ | number
20
+ ),
21
+ ): ?number => {
22
+ if (typeof component === 'number') {
23
+ return component;
24
+ }
25
+ if (typeof component?._nativeTag === 'number') {
26
+ return component?._nativeTag;
27
+ }
28
+ if (typeof component?.canonical?._nativeTag === 'number') {
29
+ return component?.canonical?._nativeTag;
30
+ }
31
+ return undefined;
32
+ };
33
+
34
+ export default tagForComponentOrHandle;
@@ -19,6 +19,8 @@ import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';
19
19
  import Platform from '../../Utilities/Platform';
20
20
  import View from '../../Components/View/View';
21
21
  import type {ViewProps} from '../../Components/View/ViewPropTypes';
22
+ import typeof TVParallaxPropertiesType from '../AppleTV/TVViewPropTypes';
23
+ import tagForComponentOrHandle from '../AppleTV/tagForComponentOrHandle';
22
24
  import * as React from 'react';
23
25
 
24
26
  type AndroidProps = $ReadOnly<{|
@@ -29,9 +31,21 @@ type AndroidProps = $ReadOnly<{|
29
31
  nextFocusUp?: ?number,
30
32
  |}>;
31
33
 
34
+ type TVProps = $ReadOnly<{|
35
+ hasTVPreferredFocus?: ?boolean,
36
+ isTVSelectable?: ?boolean,
37
+ tvParallaxProperties?: ?TVParallaxPropertiesType,
38
+ nextFocusDown?: ?number,
39
+ nextFocusForward?: ?number,
40
+ nextFocusLeft?: ?number,
41
+ nextFocusRight?: ?number,
42
+ nextFocusUp?: ?number,
43
+ |}>;
44
+
32
45
  type Props = $ReadOnly<{|
33
46
  ...React.ElementConfig<TouchableWithoutFeedback>,
34
47
  ...AndroidProps,
48
+ ...TVProps,
35
49
  ...ViewProps,
36
50
 
37
51
  activeOpacity?: ?number,
@@ -313,11 +327,11 @@ class TouchableHighlight extends React.Component<Props, State> {
313
327
  hasTVPreferredFocus={this.props.hasTVPreferredFocus === true}
314
328
  isTVSelectable={this.props.isTVSelectable !== false && this.props.accessible !== false}
315
329
  tvParallaxProperties={this.props.tvParallaxProperties}
316
- nextFocusDown={this.props.nextFocusDown}
317
- nextFocusForward={this.props.nextFocusForward}
318
- nextFocusLeft={this.props.nextFocusLeft}
319
- nextFocusRight={this.props.nextFocusRight}
320
- nextFocusUp={this.props.nextFocusUp}
330
+ nextFocusDown={tagForComponentOrHandle(this.props.nextFocusDown)}
331
+ nextFocusForward={tagForComponentOrHandle(this.props.nextFocusForward)}
332
+ nextFocusLeft={tagForComponentOrHandle(this.props.nextFocusLeft)}
333
+ nextFocusRight={tagForComponentOrHandle(this.props.nextFocusRight)}
334
+ nextFocusUp={tagForComponentOrHandle(this.props.nextFocusUp)}
321
335
  focusable={
322
336
  this.props.focusable !== false && this.props.onPress !== undefined
323
337
  }
@@ -20,6 +20,7 @@ import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
20
20
  import flattenStyle from '../../StyleSheet/flattenStyle';
21
21
  import Platform from '../../Utilities/Platform';
22
22
  import typeof TVParallaxPropertiesType from '../AppleTV/TVViewPropTypes';
23
+ import tagForComponentOrHandle from '../AppleTV/tagForComponentOrHandle';
23
24
 
24
25
  import * as React from 'react';
25
26
 
@@ -245,13 +246,15 @@ class TouchableOpacity extends React.Component<Props, State> {
245
246
  nativeID={this.props.nativeID}
246
247
  testID={this.props.testID}
247
248
  onLayout={this.props.onLayout}
248
- nextFocusDown={this.props.nextFocusDown}
249
- nextFocusForward={this.props.nextFocusForward}
250
- nextFocusLeft={this.props.nextFocusLeft}
251
- nextFocusRight={this.props.nextFocusRight}
252
- nextFocusUp={this.props.nextFocusUp}
249
+ nextFocusDown={tagForComponentOrHandle(this.props.nextFocusDown)}
250
+ nextFocusForward={tagForComponentOrHandle(this.props.nextFocusForward)}
251
+ nextFocusLeft={tagForComponentOrHandle(this.props.nextFocusLeft)}
252
+ nextFocusRight={tagForComponentOrHandle(this.props.nextFocusRight)}
253
+ nextFocusUp={tagForComponentOrHandle(this.props.nextFocusUp)}
253
254
  hasTVPreferredFocus={this.props.hasTVPreferredFocus === true}
254
- isTVSelectable={this.props.isTVSelectable !== false && this.props.accessible !== false}
255
+ isTVSelectable={
256
+ this.props.isTVSelectable !== false && this.props.accessible !== false
257
+ }
255
258
  tvParallaxProperties={this.props.tvParallaxProperties}
256
259
  hitSlop={this.props.hitSlop}
257
260
  focusable={
@@ -284,7 +287,7 @@ class TouchableOpacity extends React.Component<Props, State> {
284
287
  }
285
288
  },
286
289
  onPress: event => {
287
- if (this.props.onPress != null && Platform.OS !== "android") {
290
+ if (this.props.onPress != null && Platform.OS !== 'android') {
288
291
  this.props.onPress(event);
289
292
  }
290
293
  },
@@ -12,6 +12,6 @@
12
12
  exports.version = {
13
13
  major: 0,
14
14
  minor: 68,
15
- patch: 0,
15
+ patch: 1,
16
16
  prerelease: null,
17
17
  };
package/README.md CHANGED
@@ -28,6 +28,7 @@ Notes:
28
28
  - _Apple TV_: `pod install` will pick up the additional pods needed for the new architecture.
29
29
  - _Android TV_: Enabling the new architecture will cause your app to be built from React Native sources, including C++ sources, so you will need the NDK and the build will take much longer.
30
30
  - _Third party libraries_: As of this moment, third party libraries have not all enabled support for the new architecture.
31
+ - _Bugs_: There are some issues with interactions between Apple TV parallax properties implementation and the new renderer. TabBarIOS has not been reimplemented in the new architecture so it will show up as an "unimplemented component".
31
32
 
32
33
  ### Typescript
33
34
 
@@ -182,7 +183,7 @@ class Game2048 extends React.Component {
182
183
 
183
184
  - _Turbomodules_: Working as of the 0.61.2-0 release.
184
185
 
185
- - _Flipper_: Working in the 0.62.2-x releases. Working in the 0.63.x releases; however, tvOS requires the Flipper pods from 0.62.2-x. `scripts/react_native_pods.rb` contains macros for both versions. The new project template Podfile is correctly set up to provide the older Flipper for both iOS and tvOS targets. In 0.64.x, Flipper support has been temporarily removed until issues can be resolved with newer Xcode versions.
186
+ - _Flipper_: Working in the 0.62.2-x releases. Working in the 0.63.x releases; however, tvOS requires the Flipper pods from 0.62.2-x. `scripts/react_native_pods.rb` contains macros for both versions. The new project template Podfile is correctly set up to provide the older Flipper for both iOS and tvOS targets. In 0.64.x and later, Flipper support is removed until issues can be resolved with newer Xcode versions.
186
187
 
187
188
  - _Hermes for tvOS_: RN core added support for the Hermes JS engine on iOS in 0.64. tvOS does not yet have this, as it will require significant additions to the Hermes build structure.
188
189
 
@@ -196,7 +197,9 @@ class Game2048 extends React.Component {
196
197
 
197
198
  - _Back navigation with the TV remote menu button_: The `BackHandler` component, originally written to support the Android back button, now also supports back navigation on the Apple TV using the menu button on the TV remote.
198
199
 
199
- - _TVMenuControl_: This module provides methods to enable and disable navigation using the menu key on the TV remote. This is required in order to fix an issue with Apple's guidelines for menu key navigation (see https://github.com/facebook/react-native/issues/18930). The `RNTester` app uses this new module to implement correct menu key behavior.
200
+ - _TVEventControl_: (Formerly "TVMenuControl") (Apple TV only) This module provides methods to enable and disable firing of two types of events from the Apple TV Siri remote:
201
+ - `enableTVMenuKey`/`disableTVMenuKey`: Method to enable and disable the menu key gesture recognizer, in order to fix an issue with Apple's guidelines for menu key navigation (see https://github.com/facebook/react-native/issues/18930). The `RNTester` app uses these methods to implement correct menu key behavior for back navigation.
202
+ - `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.
200
203
 
201
204
  - _TVFocusGuideView_: This component provides support for Apple's `UIFocusGuide` API, 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.
202
205
 
@@ -40,8 +40,7 @@
40
40
 
41
41
  NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
42
42
 
43
- NSString *const RCTTVEnableMenuKeyNotification = @"RCTTVEnableMenuKeyNotification";
44
- NSString *const RCTTVDisableMenuKeyNotification = @"RCTTVDisableMenuKeyNotification";
43
+
45
44
 
46
45
 
47
46
  @interface RCTUIManager (RCTRootView)
@@ -168,7 +167,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
168
167
  #if TARGET_OS_TV
169
168
  - (NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments
170
169
  {
171
- if (self.reactPreferredFocusedView) {
170
+ if (self.reactPreferredFocusedView && self.reactPreferredFocusedView.window != nil) {
172
171
  return @[self.reactPreferredFocusedView];
173
172
  }
174
173
  return [super preferredFocusEnvironments];
@@ -26,7 +26,7 @@
26
26
  */
27
27
  #if TARGET_OS_TV
28
28
  @property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
29
- @property (nonatomic, strong) UIView *reactPreferredFocusedView;
29
+ @property (nonatomic, weak) UIView *reactPreferredFocusedView;
30
30
  #endif
31
31
 
32
32
  - (void)contentViewInvalidated;
@@ -7,25 +7,33 @@
7
7
 
8
8
  #import <UIKit/UIKit.h>
9
9
 
10
- extern NSString *const RCTTVRemoteEventMenu;
11
- extern NSString *const RCTTVRemoteEventPlayPause;
12
- extern NSString *const RCTTVRemoteEventSelect;
10
+ extern NSString * _Nonnull const RCTTVEnableMenuKeyNotification;
11
+ extern NSString * _Nonnull const RCTTVDisableMenuKeyNotification;
13
12
 
14
- extern NSString *const RCTTVRemoteEventLongPlayPause;
15
- extern NSString *const RCTTVRemoteEventLongSelect;
13
+ extern NSString * _Nonnull const RCTTVEnablePanGestureNotification;
14
+ extern NSString * _Nonnull const RCTTVDisablePanGestureNotification;
16
15
 
17
- extern NSString *const RCTTVRemoteEventLeft;
18
- extern NSString *const RCTTVRemoteEventRight;
19
- extern NSString *const RCTTVRemoteEventUp;
20
- extern NSString *const RCTTVRemoteEventDown;
16
+ extern NSString * _Nonnull const RCTTVRemoteEventMenu;
17
+ extern NSString * _Nonnull const RCTTVRemoteEventPlayPause;
18
+ extern NSString * _Nonnull const RCTTVRemoteEventSelect;
21
19
 
22
- extern NSString *const RCTTVRemoteEventPageUp;
23
- extern NSString *const RCTTVRemoteEventPageDown;
20
+ extern NSString * _Nonnull const RCTTVRemoteEventLongPlayPause;
21
+ extern NSString * _Nonnull const RCTTVRemoteEventLongSelect;
24
22
 
25
- extern NSString *const RCTTVRemoteEventSwipeLeft;
26
- extern NSString *const RCTTVRemoteEventSwipeRight;
27
- extern NSString *const RCTTVRemoteEventSwipeUp;
28
- extern NSString *const RCTTVRemoteEventSwipeDown;
23
+ extern NSString * _Nonnull const RCTTVRemoteEventLeft;
24
+ extern NSString * _Nonnull const RCTTVRemoteEventRight;
25
+ extern NSString * _Nonnull const RCTTVRemoteEventUp;
26
+ extern NSString * _Nonnull const RCTTVRemoteEventDown;
27
+
28
+ extern NSString * _Nonnull const RCTTVRemoteEventPageUp;
29
+ extern NSString * _Nonnull const RCTTVRemoteEventPageDown;
30
+
31
+ extern NSString * _Nonnull const RCTTVRemoteEventSwipeLeft;
32
+ extern NSString * _Nonnull const RCTTVRemoteEventSwipeRight;
33
+ extern NSString * _Nonnull const RCTTVRemoteEventSwipeUp;
34
+ extern NSString * _Nonnull const RCTTVRemoteEventSwipeDown;
35
+
36
+ extern NSString * _Nonnull const RCTTVRemoteEventPan;
29
37
 
30
38
  @interface RCTTVRemoteHandler : NSObject
31
39
 
@@ -35,4 +43,7 @@ extern NSString *const RCTTVRemoteEventSwipeDown;
35
43
  + (BOOL)useMenuKey;
36
44
  + (void)setUseMenuKey:(BOOL)useMenuKey;
37
45
 
46
+ + (BOOL)usePanGesture;
47
+ + (void)setUsePanGesture:(BOOL)usePanGesture;
48
+
38
49
  @end
@@ -20,6 +20,12 @@
20
20
  #import "RCTView.h"
21
21
  #import "UIView+React.h"
22
22
 
23
+ NSString *const RCTTVEnableMenuKeyNotification = @"RCTTVEnableMenuKeyNotification";
24
+ NSString *const RCTTVDisableMenuKeyNotification = @"RCTTVDisableMenuKeyNotification";
25
+
26
+ NSString *const RCTTVEnablePanGestureNotification = @"RCTTVEnablePanGestureNotification";
27
+ NSString *const RCTTVDisablePanGestureNotification = @"RCTTVDisablePanGestureNotification";
28
+
23
29
  NSString *const RCTTVRemoteEventMenu = @"menu";
24
30
  NSString *const RCTTVRemoteEventPlayPause = @"playPause";
25
31
  NSString *const RCTTVRemoteEventSelect = @"select";
@@ -40,10 +46,13 @@ NSString *const RCTTVRemoteEventSwipeRight = @"swipeRight";
40
46
  NSString *const RCTTVRemoteEventSwipeUp = @"swipeUp";
41
47
  NSString *const RCTTVRemoteEventSwipeDown = @"swipeDown";
42
48
 
49
+ NSString *const RCTTVRemoteEventPan = @"pan";
50
+
43
51
  @interface RCTTVRemoteHandler()
44
52
 
45
53
  @property (nonatomic, copy, readonly) NSDictionary *tvRemoteGestureRecognizers;
46
54
  @property (nonatomic, strong) UITapGestureRecognizer *tvMenuKeyRecognizer;
55
+ @property (nonatomic, strong) UIPanGestureRecognizer *tvPanGestureRecognizer;
47
56
  @property (nonatomic, weak) UIView *view;
48
57
 
49
58
  @end
@@ -53,9 +62,10 @@ NSString *const RCTTVRemoteEventSwipeDown = @"swipeDown";
53
62
  }
54
63
 
55
64
  #pragma mark -
56
- #pragma mark Static setting for using menu key
65
+ #pragma mark Static settings for menu key and pan gesture
57
66
 
58
67
  static __volatile BOOL __useMenuKey = NO;
68
+ static __volatile BOOL __usePanGesture = NO;
59
69
 
60
70
  + (BOOL)useMenuKey
61
71
  {
@@ -67,6 +77,16 @@ static __volatile BOOL __useMenuKey = NO;
67
77
  __useMenuKey = useMenuKey;
68
78
  }
69
79
 
80
+ + (BOOL)usePanGesture
81
+ {
82
+ return __usePanGesture;
83
+ }
84
+
85
+ + (void)setUsePanGesture:(BOOL)usePanGesture
86
+ {
87
+ __usePanGesture = usePanGesture;
88
+ }
89
+
70
90
  #pragma mark -
71
91
  #pragma mark Public methods
72
92
 
@@ -92,10 +112,14 @@ static __volatile BOOL __useMenuKey = NO;
92
112
  {
93
113
  _tvRemoteGestureRecognizers = [NSMutableDictionary dictionary];
94
114
  // Recognizers for Apple TV remote buttons
115
+
95
116
  // Menu recognizer
96
117
  self.tvMenuKeyRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuPressed:)];
97
118
  self.tvMenuKeyRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
98
119
 
120
+ // Pan gesture recognizer
121
+ self.tvPanGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panned:)];
122
+
99
123
  // Play/Pause
100
124
  [self addTapGestureRecognizerWithSelector:@selector(playPausePressed:)
101
125
  pressType:UIPressTypePlayPause
@@ -169,7 +193,6 @@ static __volatile BOOL __useMenuKey = NO;
169
193
  [self addSwipeGestureRecognizerWithSelector:@selector(swipedRight:)
170
194
  direction:UISwipeGestureRecognizerDirectionRight
171
195
  name:RCTTVRemoteEventSwipeRight];
172
-
173
196
  }
174
197
 
175
198
  - (void)attachToView
@@ -183,6 +206,17 @@ static __volatile BOOL __useMenuKey = NO;
183
206
  selector:@selector(disableTVMenuKey)
184
207
  name:RCTTVDisableMenuKeyNotification
185
208
  object:nil];
209
+
210
+ [[NSNotificationCenter defaultCenter] addObserver:self
211
+ selector:@selector(enableTVPanGesture)
212
+ name:RCTTVEnablePanGestureNotification
213
+ object:nil];
214
+
215
+ [[NSNotificationCenter defaultCenter] addObserver:self
216
+ selector:@selector(disableTVPanGesture)
217
+ name:RCTTVDisablePanGestureNotification
218
+ object:nil];
219
+
186
220
  for (NSString *key in [self.tvRemoteGestureRecognizers allKeys]) {
187
221
  [_view addGestureRecognizer:self.tvRemoteGestureRecognizers[key]];
188
222
  }
@@ -191,6 +225,11 @@ static __volatile BOOL __useMenuKey = NO;
191
225
  } else {
192
226
  [self disableTVMenuKey];
193
227
  }
228
+ if ([RCTTVRemoteHandler usePanGesture]) {
229
+ [self enableTVPanGesture];
230
+ } else {
231
+ [self disableTVPanGesture];
232
+ }
194
233
  }
195
234
 
196
235
  - (void)detachFromView
@@ -198,6 +237,9 @@ static __volatile BOOL __useMenuKey = NO;
198
237
  if ([[self.view gestureRecognizers] containsObject:self.tvMenuKeyRecognizer]) {
199
238
  [self.view removeGestureRecognizer:self.tvMenuKeyRecognizer];
200
239
  }
240
+ if ([[self.view gestureRecognizers] containsObject:self.tvPanGestureRecognizer]) {
241
+ [self.view removeGestureRecognizer:self.tvPanGestureRecognizer];
242
+ }
201
243
  for (NSString *key in [self.tvRemoteGestureRecognizers allKeys]) {
202
244
  [_view removeGestureRecognizer:self.tvRemoteGestureRecognizers[key]];
203
245
  }
@@ -207,7 +249,13 @@ static __volatile BOOL __useMenuKey = NO;
207
249
  [[NSNotificationCenter defaultCenter] removeObserver:self
208
250
  name:RCTTVDisableMenuKeyNotification
209
251
  object:nil];
210
-
252
+ [[NSNotificationCenter defaultCenter] removeObserver:self
253
+ name:RCTTVEnablePanGestureNotification
254
+ object:nil];
255
+ [[NSNotificationCenter defaultCenter] removeObserver:self
256
+ name:RCTTVDisablePanGestureNotification
257
+ object:nil];
258
+
211
259
  }
212
260
 
213
261
  # pragma mark -
@@ -231,27 +279,45 @@ static __volatile BOOL __useMenuKey = NO;
231
279
  });
232
280
  }
233
281
 
282
+ - (void)enableTVPanGesture
283
+ {
284
+ dispatch_async(dispatch_get_main_queue(), ^{
285
+ if (![[self.view gestureRecognizers] containsObject:self.tvPanGestureRecognizer]) {
286
+ [self.view addGestureRecognizer:self.tvPanGestureRecognizer];
287
+ }
288
+ });
289
+ }
290
+
291
+ - (void)disableTVPanGesture
292
+ {
293
+ dispatch_async(dispatch_get_main_queue(), ^{
294
+ if ([[self.view gestureRecognizers] containsObject:self.tvPanGestureRecognizer]) {
295
+ [self.view removeGestureRecognizer:self.tvPanGestureRecognizer];
296
+ }
297
+ });
298
+ }
299
+
234
300
  # pragma mark -
235
301
  # pragma mark Gesture handlers
236
302
 
237
303
  - (void)playPausePressed:(UIGestureRecognizer *)r
238
304
  {
239
- [self sendAppleTVEvent:RCTTVRemoteEventPlayPause toView:r.view];
305
+ [self sendAppleTVEvent:RCTTVRemoteEventPlayPause];
240
306
  }
241
307
 
242
308
  - (void)menuPressed:(UIGestureRecognizer *)r
243
309
  {
244
- [self sendAppleTVEvent:RCTTVRemoteEventMenu toView:r.view];
310
+ [self sendAppleTVEvent:RCTTVRemoteEventMenu];
245
311
  }
246
312
 
247
313
  - (void)selectPressed:(UIGestureRecognizer *)r
248
314
  {
249
- [self sendAppleTVEvent:RCTTVRemoteEventSelect toView:r.view];
315
+ [self sendAppleTVEvent:RCTTVRemoteEventSelect];
250
316
  }
251
317
 
252
318
  - (void)longPlayPausePressed:(UIGestureRecognizer *)r
253
319
  {
254
- [self sendAppleTVEvent:RCTTVRemoteEventLongPlayPause toView:r.view];
320
+ [self sendAppleTVEvent:RCTTVRemoteEventLongPlayPause];
255
321
 
256
322
  #if RCT_DEV
257
323
  // If shake to show is enabled on device, use long play/pause event to show dev menu
@@ -261,57 +327,73 @@ static __volatile BOOL __useMenuKey = NO;
261
327
 
262
328
  - (void)longSelectPressed:(UIGestureRecognizer *)r
263
329
  {
264
- [self sendAppleTVEvent:RCTTVRemoteEventLongSelect toView:r.view];
330
+ [self sendAppleTVEvent:RCTTVRemoteEventLongSelect];
265
331
  }
266
332
 
267
333
  - (void)swipedUp:(UIGestureRecognizer *)r
268
334
  {
269
- [self sendAppleTVEvent:RCTTVRemoteEventSwipeUp toView:r.view];
335
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeUp];
270
336
  }
271
337
 
272
338
  - (void)swipedDown:(UIGestureRecognizer *)r
273
339
  {
274
- [self sendAppleTVEvent:RCTTVRemoteEventSwipeDown toView:r.view];
340
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeDown];
275
341
  }
276
342
 
277
343
  - (void)swipedLeft:(UIGestureRecognizer *)r
278
344
  {
279
- [self sendAppleTVEvent:RCTTVRemoteEventSwipeLeft toView:r.view];
345
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeLeft];
280
346
  }
281
347
 
282
348
  - (void)swipedRight:(UIGestureRecognizer *)r
283
349
  {
284
- [self sendAppleTVEvent:RCTTVRemoteEventSwipeRight toView:r.view];
350
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeRight];
285
351
  }
286
352
 
287
353
  - (void)tappedUp:(UIGestureRecognizer *)r
288
354
  {
289
- [self sendAppleTVEvent:RCTTVRemoteEventUp toView:r.view];
355
+ [self sendAppleTVEvent:RCTTVRemoteEventUp];
290
356
  }
291
357
 
292
358
  - (void)tappedDown:(UIGestureRecognizer *)r
293
359
  {
294
- [self sendAppleTVEvent:RCTTVRemoteEventDown toView:r.view];
360
+ [self sendAppleTVEvent:RCTTVRemoteEventDown];
295
361
  }
296
362
 
297
363
  - (void)tappedPageUp:(UIGestureRecognizer *)r
298
364
  {
299
- [self sendAppleTVEvent:RCTTVRemoteEventPageUp toView:r.view];
365
+ [self sendAppleTVEvent:RCTTVRemoteEventPageUp];
300
366
  }
301
367
 
302
368
  - (void)tappedPageDown:(UIGestureRecognizer *)r
303
369
  {
304
- [self sendAppleTVEvent:RCTTVRemoteEventPageDown toView:r.view];
370
+ [self sendAppleTVEvent:RCTTVRemoteEventPageDown];
305
371
  }
306
372
 
307
373
  - (void)tappedLeft:(UIGestureRecognizer *)r
308
374
  {
309
- [self sendAppleTVEvent:RCTTVRemoteEventLeft toView:r.view];
375
+ [self sendAppleTVEvent:RCTTVRemoteEventLeft];
310
376
  }
311
377
 
312
378
  - (void)tappedRight:(UIGestureRecognizer *)r
313
379
  {
314
- [self sendAppleTVEvent:RCTTVRemoteEventRight toView:r.view];
380
+ [self sendAppleTVEvent:RCTTVRemoteEventRight];
381
+ }
382
+
383
+ - (void)panned:(UIPanGestureRecognizer *)gesture {
384
+ UIView *rootView = [self view];
385
+ NSString *gestureState = [self recognizerStateToString:gesture.state];
386
+ CGPoint translation = [gesture translationInView:rootView];
387
+ CGPoint velocity = [gesture velocityInView:rootView];
388
+
389
+ if (gestureState) {
390
+ [self sendAppleTVEvent:RCTTVRemoteEventPan withBody:@{@"state": gestureState,
391
+ @"x": [NSNumber numberWithInt:translation.x],
392
+ @"y": [NSNumber numberWithInt:translation.y],
393
+ @"velocityX": [NSNumber numberWithFloat:velocity.x],
394
+ @"velocityY": [NSNumber numberWithFloat:velocity.y],
395
+ }];
396
+ }
315
397
  }
316
398
 
317
399
  #pragma mark -
@@ -345,10 +427,36 @@ static __volatile BOOL __useMenuKey = NO;
345
427
  _tvRemoteGestureRecognizers[name] = recognizer;
346
428
  }
347
429
 
348
- - (void)sendAppleTVEvent:(NSString *)eventType toView:(__unused UIView *)v
430
+ #pragma mark -
431
+ #pragma mark Helper methods
432
+
433
+ - (void)sendAppleTVEvent:(NSString *)eventType
349
434
  {
435
+ [self sendAppleTVEvent:eventType withBody: nil];
436
+ }
437
+
438
+ - (void)sendAppleTVEvent:(NSString *)eventType
439
+ withBody:(NSDictionary * __nullable)body
440
+ {
441
+ NSDictionary *payload = (body != nil) ?
442
+ @{@"eventType" : eventType, @"body": body} :
443
+ @{@"eventType" : eventType};
444
+
350
445
  [[NSNotificationCenter defaultCenter] postNotificationName:@"RCTTVNavigationEventNotification"
351
- object:@{@"eventType" : eventType}];
446
+ object:payload];
447
+ }
448
+
449
+ - (NSString *)recognizerStateToString:(UIGestureRecognizerState)state {
450
+ switch (state) {
451
+ case UIGestureRecognizerStateBegan:
452
+ return @"Began";
453
+ case UIGestureRecognizerStateChanged:
454
+ return @"Changed";
455
+ case UIGestureRecognizerStateEnded:
456
+ return @"Ended";
457
+ default:
458
+ return nil;
459
+ }
352
460
  }
353
461
 
354
462
  @end
@@ -23,7 +23,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(68),
26
- RCTVersionPatch: @(0),
26
+ RCTVersionPatch: @(1),
27
27
  RCTVersionPrerelease: [NSNull null],
28
28
  };
29
29
  });
@@ -35,7 +35,7 @@ using namespace facebook::react;
35
35
  }
36
36
 
37
37
  - (NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
38
- if (self.reactPreferredFocusedView) {
38
+ if (self.reactPreferredFocusedView && self.reactPreferredFocusedView.window != nil) {
39
39
  return @[self.reactPreferredFocusedView];
40
40
  }
41
41
  return [super preferredFocusEnvironments];
@@ -71,6 +71,10 @@ NS_ASSUME_NONNULL_BEGIN
71
71
 
72
72
  #if TARGET_OS_TV
73
73
  @property(nonatomic, nullable) UIFocusGuide *focusGuide;
74
+ @property(nonatomic, nullable) UIFocusGuide *focusGuideUp;
75
+ @property(nonatomic, nullable) UIFocusGuide *focusGuideDown;
76
+ @property(nonatomic, nullable) UIFocusGuide *focusGuideLeft;
77
+ @property(nonatomic, nullable) UIFocusGuide *focusGuideRight;
74
78
  #endif
75
79
 
76
80
  /**