react-native-tvos 0.76.1-1 → 0.76.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.
- package/Libraries/AppDelegate/React-RCTAppDelegate.podspec +1 -1
- package/Libraries/Components/Pressable/Pressable.d.ts +8 -0
- package/Libraries/Components/Pressable/Pressable.js +4 -1
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Core/setUpErrorHandling.js +1 -7
- package/Libraries/LogBox/Data/LogBoxData.js +2 -2
- package/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h +1 -0
- package/Libraries/Types/CoreEventTypes.d.ts +3 -3
- package/README.md +9 -7
- package/React/Base/RCTTVRemoteHandler.m +0 -19
- package/React/Base/RCTTVRemoteSelectHandler.h +27 -0
- package/React/Base/RCTTVRemoteSelectHandler.m +120 -0
- package/React/Base/RCTVersion.m +2 -2
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +12 -8
- package/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +47 -3
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +8 -0
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +35 -42
- package/React/Views/RCTTVView.h +6 -6
- package/React/Views/RCTTVView.m +34 -46
- package/React/Views/ScrollView/RCTScrollView.m +12 -8
- package/ReactAndroid/api/ReactAndroid.api +0 -1
- package/ReactAndroid/cmake-utils/ReactNative-application.cmake +1 -1
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.kt +2 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/core/TimingModule.kt +0 -8
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +11 -3
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.cpp +3 -2
- package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h +12 -1
- package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +165 -2
- package/cli.js +1 -1
- package/index.js +0 -4
- package/package.json +8 -8
- package/scripts/codegen/generate-artifacts-executor.js +3 -3
- package/sdks/.hermesversion +1 -1
- package/sdks/hermesc/osx-bin/hermes +0 -0
- package/sdks/hermesc/osx-bin/hermesc +0 -0
- package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
- package/types/modules/Codegen.d.ts +6 -0
- package/types/public/ReactNativeTVTypes.d.ts +1 -1
- package/Libraries/Components/TabBarIOS/RCTTabBarItemNativeComponent.js +0 -99
- package/Libraries/Components/TabBarIOS/RCTTabBarNativeComponent.js +0 -32
- package/Libraries/Components/TabBarIOS/TabBarIOS.ios.js +0 -59
- package/Libraries/Components/TabBarIOS/TabBarIOS.js +0 -52
- package/Libraries/Components/TabBarIOS/TabBarIOSProps.js +0 -52
- package/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js +0 -177
- package/Libraries/Components/TabBarIOS/TabBarItemIOS.js +0 -55
- package/React/Views/RCTTabBar.h +0 -22
- package/React/Views/RCTTabBar.m +0 -237
- package/React/Views/RCTTabBarItem.h +0 -35
- package/React/Views/RCTTabBarItem.m +0 -139
- package/React/Views/RCTTabBarItemManager.h +0 -12
- package/React/Views/RCTTabBarItemManager.m +0 -38
- package/React/Views/RCTTabBarManager.h +0 -12
- package/React/Views/RCTTabBarManager.m +0 -81
|
@@ -63,7 +63,7 @@ Pod::Spec.new do |s|
|
|
|
63
63
|
"CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
|
|
64
64
|
"DEFINES_MODULE" => "YES"
|
|
65
65
|
}
|
|
66
|
-
s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\""}
|
|
66
|
+
s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\" \"$(PODS_ROOT)/Headers/Private/Yoga\""}
|
|
67
67
|
|
|
68
68
|
s.dependency "React-Core"
|
|
69
69
|
s.dependency "RCT-Folly", folly_version
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import {View} from '../View/View';
|
|
21
21
|
import {AccessibilityProps} from '../View/ViewAccessibility';
|
|
22
22
|
import {ViewProps} from '../View/ViewPropTypes';
|
|
23
|
+
import {TVParallaxProperties} from '../../../types/public/ReactNativeTVTypes';
|
|
23
24
|
|
|
24
25
|
export interface PressableStateCallbackType {
|
|
25
26
|
readonly pressed: boolean;
|
|
@@ -159,6 +160,13 @@ export interface PressableProps
|
|
|
159
160
|
* Duration (in milliseconds) to wait after press down before calling onPressIn.
|
|
160
161
|
*/
|
|
161
162
|
unstable_pressDelay?: number | undefined;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* *(Apple TV only)* Object with properties to control Apple TV parallax effects.
|
|
166
|
+
*
|
|
167
|
+
* @platform ios
|
|
168
|
+
*/
|
|
169
|
+
tvParallaxProperties?: TVParallaxProperties;
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
// TODO use React.AbstractComponent when available
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type {
|
|
12
12
|
FocusEvent,
|
|
13
|
+
BlurEvent,
|
|
13
14
|
LayoutEvent,
|
|
14
15
|
MouseEvent,
|
|
15
16
|
PressEvent,
|
|
@@ -52,7 +53,9 @@ type TVProps = $ReadOnly<{|
|
|
|
52
53
|
nextFocusRight?: ?number,
|
|
53
54
|
nextFocusUp?: ?number,
|
|
54
55
|
onFocus?: ?(event: FocusEvent) => mixed,
|
|
55
|
-
onBlur?: ?(event:
|
|
56
|
+
onBlur?: ?(event: BlurEvent) => mixed,
|
|
57
|
+
onFocusCapture?: ?(event: FocusEvent) => void,
|
|
58
|
+
onBlurCapture?: ?(event: BlurEvent) => void,
|
|
56
59
|
|}>;
|
|
57
60
|
|
|
58
61
|
type Props = $ReadOnly<{|
|
|
@@ -21,13 +21,7 @@ ExceptionsManager.installConsoleErrorReporter();
|
|
|
21
21
|
if (!global.__fbDisableExceptionsManager) {
|
|
22
22
|
const handleError = (e: mixed, isFatal: boolean) => {
|
|
23
23
|
try {
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
!global.RN$handleException ||
|
|
27
|
-
!global.RN$handleException(e, isFatal)
|
|
28
|
-
) {
|
|
29
|
-
ExceptionsManager.handleException(e, isFatal);
|
|
30
|
-
}
|
|
24
|
+
ExceptionsManager.handleException(e, isFatal);
|
|
31
25
|
} catch (ee) {
|
|
32
26
|
console.log('Failed to print error: ', ee.message);
|
|
33
27
|
throw e;
|
|
@@ -82,9 +82,9 @@ let warningFilter: WarningFilter = function (format) {
|
|
|
82
82
|
return {
|
|
83
83
|
finalFormat: format,
|
|
84
84
|
forceDialogImmediately: false,
|
|
85
|
-
suppressDialog_LEGACY:
|
|
85
|
+
suppressDialog_LEGACY: false,
|
|
86
86
|
suppressCompletely: false,
|
|
87
|
-
monitorEvent: '
|
|
87
|
+
monitorEvent: 'warning_unhandled',
|
|
88
88
|
monitorListVersion: 0,
|
|
89
89
|
monitorSampleRate: 1,
|
|
90
90
|
};
|
|
@@ -35,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
35
35
|
@property (nonatomic, assign, readonly) CGFloat zoomScale;
|
|
36
36
|
@property (nonatomic, assign, readonly) CGPoint contentOffset;
|
|
37
37
|
@property (nonatomic, assign, readonly) UIEdgeInsets contentInset;
|
|
38
|
+
@property (nullable, nonatomic, copy) NSDictionary<NSAttributedStringKey, id> *typingAttributes;
|
|
38
39
|
|
|
39
40
|
// This protocol disallows direct access to `selectedTextRange` property because
|
|
40
41
|
// unwise usage of it can break the `delegate` behavior. So, we always have to
|
|
@@ -246,13 +246,13 @@ export interface GestureResponderEvent
|
|
|
246
246
|
|
|
247
247
|
export interface MouseEvent extends NativeSyntheticEvent<NativeMouseEvent> {}
|
|
248
248
|
|
|
249
|
-
export interface NativeFocusEvent {}
|
|
249
|
+
export interface NativeFocusEvent extends TargetedEvent {}
|
|
250
250
|
export interface FocusEvent extends NativeSyntheticEvent<NativeFocusEvent> {}
|
|
251
251
|
|
|
252
|
-
export interface NativeBlurEvent {}
|
|
252
|
+
export interface NativeBlurEvent extends TargetedEvent {}
|
|
253
253
|
export interface BlurEvent extends NativeSyntheticEvent<NativeBlurEvent> {}
|
|
254
254
|
|
|
255
|
-
export interface NativePressEvent {}
|
|
255
|
+
export interface NativePressEvent extends TargetedEvent {}
|
|
256
256
|
export interface PressEvent extends NativeSyntheticEvent<NativePressEvent> {}
|
|
257
257
|
|
|
258
258
|
export interface TargetedEvent {
|
package/README.md
CHANGED
|
@@ -176,19 +176,21 @@ var running_on_apple_tv = Platform.isTVOS;
|
|
|
176
176
|
|
|
177
177
|
- _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.
|
|
178
178
|
|
|
179
|
-
-
|
|
179
|
+
- _Pressable and Touchable controls_: In RNTV 0.76.1-1 and later, TV controls are supported with fully native events.
|
|
180
|
+
Code has been 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 `Pressable`, `TouchableHighlight` and `TouchableOpacity` will "just work" on both Apple TV and Android TV. In particular:
|
|
180
181
|
|
|
181
182
|
- `onFocus()` will be executed when the touchable view goes into focus
|
|
182
183
|
- `onBlur()` will be executed when the touchable view goes out of focus
|
|
183
184
|
- `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
|
-
- `
|
|
185
|
+
- `onPressIn()` will be executed when the TV remote "select" button is pressed down (center button on Apple TV remote, or center button on Android TV DPad)
|
|
186
|
+
- `onPressOut()` will be executed when the TV remote "select" button is released
|
|
187
|
+
- `onLongPress()` will be executed if the "select" button is held down for a length of time (this event is generated in the `Pressability` module, the same as for touchscreen long press events).
|
|
185
188
|
|
|
186
|
-
|
|
189
|
+
`TouchableNativeFeedback` and `TouchableWithoutFeedback` respond to press events, but do not respond to focus and blur events, and are not recommended for TV.
|
|
187
190
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
- The `focus:` pseudo class is also supported via the `onFocus()` and `onBlur()` events.
|
|
191
|
+
Because focus and blur events are now fully native core events, they will respond correctly to capturing and bubbling event handlers in `View` components. A demo of this has been added to the TVEventHandlerExample in RNTester.
|
|
192
|
+
|
|
193
|
+
- _Tailwind styles for Pressable and Touchable controls_: The above events allow RNTV to support the [`focus:` and `active:` pseudo classes for Tailwind styles](https://www.nativewind.dev/v4/core-concepts/states#hover-focus-and-active-).
|
|
192
194
|
|
|
193
195
|
- _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`.
|
|
194
196
|
|
|
@@ -119,11 +119,6 @@ static __volatile BOOL __gestureHandlersCancelTouches = YES;
|
|
|
119
119
|
pressType:UIPressTypePlayPause
|
|
120
120
|
name:RCTTVRemoteEventPlayPause];
|
|
121
121
|
|
|
122
|
-
// Select
|
|
123
|
-
[self addTapGestureRecognizerWithSelector:@selector(selectPressed:)
|
|
124
|
-
pressType:UIPressTypeSelect
|
|
125
|
-
name:RCTTVRemoteEventSelect];
|
|
126
|
-
|
|
127
122
|
// Page Up/Down
|
|
128
123
|
if (@available(tvOS 14.3, *)) {
|
|
129
124
|
[self addTapGestureRecognizerWithSelector:@selector(tappedPageUp:)
|
|
@@ -162,10 +157,6 @@ static __volatile BOOL __gestureHandlersCancelTouches = YES;
|
|
|
162
157
|
pressType:UIPressTypePlayPause
|
|
163
158
|
name:RCTTVRemoteEventLongPlayPause];
|
|
164
159
|
|
|
165
|
-
[self addLongPressGestureRecognizerWithSelector:@selector(longSelectPressed:)
|
|
166
|
-
pressType:UIPressTypeSelect
|
|
167
|
-
name:RCTTVRemoteEventLongSelect];
|
|
168
|
-
|
|
169
160
|
[self addLongPressGestureRecognizerWithSelector:@selector(longUpPressed:)
|
|
170
161
|
pressType:UIPressTypeUpArrow
|
|
171
162
|
name:RCTTVRemoteEventLongUp];
|
|
@@ -355,11 +346,6 @@ static __volatile BOOL __gestureHandlersCancelTouches = YES;
|
|
|
355
346
|
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventMenu keyAction:r.eventKeyAction tag:nil target:nil];
|
|
356
347
|
}
|
|
357
348
|
|
|
358
|
-
- (void)selectPressed:(UIGestureRecognizer *)r
|
|
359
|
-
{
|
|
360
|
-
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventSelect keyAction:r.eventKeyAction tag:nil target:nil];
|
|
361
|
-
}
|
|
362
|
-
|
|
363
349
|
- (void)longPlayPausePressed:(UIGestureRecognizer *)r
|
|
364
350
|
{
|
|
365
351
|
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventLongPlayPause keyAction:r.eventKeyAction tag:nil target:nil];
|
|
@@ -370,11 +356,6 @@ static __volatile BOOL __gestureHandlersCancelTouches = YES;
|
|
|
370
356
|
#endif
|
|
371
357
|
}
|
|
372
358
|
|
|
373
|
-
- (void)longSelectPressed:(UIGestureRecognizer *)r
|
|
374
|
-
{
|
|
375
|
-
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventLongSelect keyAction:r.eventKeyAction tag:nil target:nil];
|
|
376
|
-
}
|
|
377
|
-
|
|
378
359
|
- (void)longUpPressed:(UIGestureRecognizer *)r
|
|
379
360
|
{
|
|
380
361
|
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventLongUp keyAction:r.eventKeyAction tag:nil target:nil];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
#import <Foundation/Foundation.h>
|
|
3
|
+
|
|
4
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
+
|
|
6
|
+
@protocol RCTTVRemoteSelectHandlerDelegate <NSObject>
|
|
7
|
+
|
|
8
|
+
- (void)animatePressIn;
|
|
9
|
+
- (void)animatePressOut;
|
|
10
|
+
|
|
11
|
+
- (void)emitPressInEvent;
|
|
12
|
+
- (void)emitPressOutEvent;
|
|
13
|
+
|
|
14
|
+
- (void)sendSelectNotification;
|
|
15
|
+
- (void)sendLongSelectBeganNotification;
|
|
16
|
+
- (void)sendLongSelectEndedNotification;
|
|
17
|
+
|
|
18
|
+
@end
|
|
19
|
+
|
|
20
|
+
@interface RCTTVRemoteSelectHandler : NSObject <UIGestureRecognizerDelegate>
|
|
21
|
+
|
|
22
|
+
- (instancetype _Nonnull )initWithView:(UIView<RCTTVRemoteSelectHandlerDelegate> * _Nonnull)view;
|
|
23
|
+
- (instancetype _Nonnull )init __attribute__((unavailable("init not available, use initWithView:")));
|
|
24
|
+
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#import "RCTTVRemoteSelectHandler.h"
|
|
2
|
+
|
|
3
|
+
@interface RCTTVRemoteSelectHandler()
|
|
4
|
+
|
|
5
|
+
@property (nonatomic, strong) UILongPressGestureRecognizer * pressRecognizer;
|
|
6
|
+
@property (nonatomic, strong) UILongPressGestureRecognizer * longPressRecognizer;
|
|
7
|
+
|
|
8
|
+
@property (nonatomic, weak) UIView<RCTTVRemoteSelectHandlerDelegate> *view;
|
|
9
|
+
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
@implementation RCTTVRemoteSelectHandler {
|
|
13
|
+
NSMutableDictionary<NSString *, UIGestureRecognizer *> *_tvRemoteGestureRecognizers;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#pragma mark -
|
|
17
|
+
#pragma mark Public methods
|
|
18
|
+
|
|
19
|
+
- (instancetype)initWithView:(UIView <RCTTVRemoteSelectHandlerDelegate> *)view
|
|
20
|
+
{
|
|
21
|
+
if ((self = [super init])) {
|
|
22
|
+
_view = view;
|
|
23
|
+
[self attachToView];
|
|
24
|
+
}
|
|
25
|
+
return self;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
- (void)dealloc
|
|
29
|
+
{
|
|
30
|
+
[self detachFromView];
|
|
31
|
+
_view = nil;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#pragma mark -
|
|
35
|
+
#pragma UIGestureRecognizerDelegate method
|
|
36
|
+
|
|
37
|
+
// Press recognizer should allow long press recognizer to work (but not the reverse)
|
|
38
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
|
39
|
+
return gestureRecognizer == _pressRecognizer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#pragma mark -
|
|
43
|
+
#pragma mark Private methods
|
|
44
|
+
|
|
45
|
+
- (void)attachToView {
|
|
46
|
+
UILongPressGestureRecognizer *pressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePress:)];
|
|
47
|
+
pressRecognizer.allowedPressTypes = @[ @(UIPressTypeSelect) ];
|
|
48
|
+
pressRecognizer.minimumPressDuration = 0.0;
|
|
49
|
+
pressRecognizer.delegate = self; // Press recognizer allows other recognizers to run
|
|
50
|
+
|
|
51
|
+
[self.view addGestureRecognizer:pressRecognizer];
|
|
52
|
+
self.pressRecognizer = pressRecognizer;
|
|
53
|
+
|
|
54
|
+
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
|
55
|
+
longPressRecognizer.allowedPressTypes = @[ @(UIPressTypeSelect) ];
|
|
56
|
+
longPressRecognizer.minimumPressDuration = 0.5;
|
|
57
|
+
|
|
58
|
+
[self.view addGestureRecognizer:longPressRecognizer];
|
|
59
|
+
self.longPressRecognizer = longPressRecognizer;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
- (void)detachFromView {
|
|
63
|
+
if (_pressRecognizer) {
|
|
64
|
+
[self.view removeGestureRecognizer:_pressRecognizer];
|
|
65
|
+
self.pressRecognizer = nil;
|
|
66
|
+
}
|
|
67
|
+
if (_longPressRecognizer) {
|
|
68
|
+
[self.view removeGestureRecognizer:_longPressRecognizer];
|
|
69
|
+
self.longPressRecognizer = nil;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (void)handlePress:(UIGestureRecognizer *)r
|
|
74
|
+
{
|
|
75
|
+
switch (r.state) {
|
|
76
|
+
case UIGestureRecognizerStateBegan:
|
|
77
|
+
[self.view emitPressInEvent];
|
|
78
|
+
[self.view animatePressIn];
|
|
79
|
+
break;
|
|
80
|
+
case UIGestureRecognizerStateCancelled:
|
|
81
|
+
case UIGestureRecognizerStateEnded:
|
|
82
|
+
if (r.enabled) {
|
|
83
|
+
[self.view animatePressOut];
|
|
84
|
+
[self.view emitPressOutEvent];
|
|
85
|
+
[self.view sendSelectNotification];
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
default:
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
When a long press starts, the press recognizer has already started
|
|
95
|
+
and called selectGestureBegan(). We disable the press recognizer
|
|
96
|
+
when the long press starts. At the end of the gesture, we execute the
|
|
97
|
+
code for pressOut (since the press recognizer cannot), and then reenable
|
|
98
|
+
the press recgonizer. This guarantees
|
|
99
|
+
only one pressIn and one pressOut, and only longSelect notifications.
|
|
100
|
+
*/
|
|
101
|
+
- (void)handleLongPress:(UIGestureRecognizer *)r
|
|
102
|
+
{
|
|
103
|
+
switch (r.state) {
|
|
104
|
+
case UIGestureRecognizerStateBegan:
|
|
105
|
+
self.pressRecognizer.enabled = NO;
|
|
106
|
+
[self.view sendLongSelectBeganNotification];
|
|
107
|
+
break;
|
|
108
|
+
case UIGestureRecognizerStateEnded:
|
|
109
|
+
case UIGestureRecognizerStateCancelled:
|
|
110
|
+
[self.view animatePressOut];
|
|
111
|
+
[self.view emitPressOutEvent];
|
|
112
|
+
[self.view sendLongSelectEndedNotification];
|
|
113
|
+
self.pressRecognizer.enabled = YES;
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@end
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(76),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(2),
|
|
27
|
+
RCTVersionPrerelease: @"0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
#if TARGET_OS_TV
|
|
28
28
|
#import <React/RCTTVRemoteHandler.h>
|
|
29
29
|
#import <React/RCTTVNavigationEventNotification.h>
|
|
30
|
+
#import "React/RCTI18nUtil.h"
|
|
30
31
|
#endif
|
|
31
32
|
|
|
32
33
|
using namespace facebook::react;
|
|
@@ -1100,22 +1101,25 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1100
1101
|
|
|
1101
1102
|
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
1102
1103
|
{
|
|
1104
|
+
// Determine if the layout is Right-to-Left
|
|
1105
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1103
1106
|
BOOL isHorizontal = _scrollView.contentSize.width > self.frame.size.width;
|
|
1104
|
-
//
|
|
1107
|
+
// Adjust for horizontal scrolling with RTL support
|
|
1105
1108
|
if (isHorizontal) {
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
+
BOOL isNavigatingToEnd = (isRTL ? context.focusHeading == UIFocusHeadingLeft : context.focusHeading == UIFocusHeadingRight);
|
|
1110
|
+
BOOL isNavigatingToStart = (isRTL ? context.focusHeading == UIFocusHeadingRight : context.focusHeading == UIFocusHeadingLeft);
|
|
1111
|
+
|
|
1112
|
+
if ((isNavigatingToEnd && self.scrollView.contentOffset.x < self.scrollView.contentSize.width - self.scrollView.visibleSize.width) ||
|
|
1113
|
+
(isNavigatingToStart && self.scrollView.contentOffset.x > 0)) {
|
|
1109
1114
|
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
1110
1115
|
}
|
|
1111
1116
|
} else {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1117
|
+
// Handle vertical scrolling as before
|
|
1118
|
+
if ((context.focusHeading == UIFocusHeadingUp && self.scrollView.contentOffset.y > 0) ||
|
|
1119
|
+
(context.focusHeading == UIFocusHeadingDown && self.scrollView.contentOffset.y < self.scrollView.contentSize.height - self.scrollView.visibleSize.height)) {
|
|
1115
1120
|
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
1116
1121
|
}
|
|
1117
1122
|
}
|
|
1118
|
-
|
|
1119
1123
|
return [super shouldUpdateFocusInContext:context];
|
|
1120
1124
|
}
|
|
1121
1125
|
|
|
@@ -61,6 +61,13 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
61
61
|
*/
|
|
62
62
|
BOOL _comingFromJS;
|
|
63
63
|
BOOL _didMoveToWindow;
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* Newly initialized default typing attributes contain a no-op NSParagraphStyle and NSShadow. These cause inequality
|
|
67
|
+
* between the AttributedString backing the input and those generated from state. We store these attributes to make
|
|
68
|
+
* later comparison insensitive to them.
|
|
69
|
+
*/
|
|
70
|
+
NSDictionary<NSAttributedStringKey, id> *_originalTypingAttributes;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
#pragma mark - UIView overrides
|
|
@@ -76,6 +83,7 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
76
83
|
_ignoreNextTextInputCall = NO;
|
|
77
84
|
_comingFromJS = NO;
|
|
78
85
|
_didMoveToWindow = NO;
|
|
86
|
+
_originalTypingAttributes = [_backedTextInputView.typingAttributes copy];
|
|
79
87
|
|
|
80
88
|
[self addSubview:_backedTextInputView];
|
|
81
89
|
[self initializeReturnKeyType];
|
|
@@ -84,6 +92,20 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
84
92
|
return self;
|
|
85
93
|
}
|
|
86
94
|
|
|
95
|
+
- (void)updateEventEmitter:(const EventEmitter::Shared &)eventEmitter
|
|
96
|
+
{
|
|
97
|
+
[super updateEventEmitter:eventEmitter];
|
|
98
|
+
|
|
99
|
+
NSMutableDictionary<NSAttributedStringKey, id> *defaultAttributes =
|
|
100
|
+
[_backedTextInputView.defaultTextAttributes mutableCopy];
|
|
101
|
+
|
|
102
|
+
RCTWeakEventEmitterWrapper *eventEmitterWrapper = [RCTWeakEventEmitterWrapper new];
|
|
103
|
+
eventEmitterWrapper.eventEmitter = _eventEmitter;
|
|
104
|
+
defaultAttributes[RCTAttributedStringEventEmitterKey] = eventEmitterWrapper;
|
|
105
|
+
|
|
106
|
+
_backedTextInputView.defaultTextAttributes = defaultAttributes;
|
|
107
|
+
}
|
|
108
|
+
|
|
87
109
|
- (void)didMoveToWindow
|
|
88
110
|
{
|
|
89
111
|
[super didMoveToWindow];
|
|
@@ -236,8 +258,11 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
236
258
|
}
|
|
237
259
|
|
|
238
260
|
if (newTextInputProps.textAttributes != oldTextInputProps.textAttributes) {
|
|
239
|
-
|
|
261
|
+
NSMutableDictionary<NSAttributedStringKey, id> *defaultAttributes =
|
|
240
262
|
RCTNSTextAttributesFromTextAttributes(newTextInputProps.getEffectiveTextAttributes(RCTFontSizeMultiplier()));
|
|
263
|
+
defaultAttributes[RCTAttributedStringEventEmitterKey] =
|
|
264
|
+
_backedTextInputView.defaultTextAttributes[RCTAttributedStringEventEmitterKey];
|
|
265
|
+
_backedTextInputView.defaultTextAttributes = defaultAttributes;
|
|
241
266
|
}
|
|
242
267
|
|
|
243
268
|
if (newTextInputProps.selectionColor != oldTextInputProps.selectionColor) {
|
|
@@ -418,6 +443,7 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
418
443
|
|
|
419
444
|
- (void)textInputDidChangeSelection
|
|
420
445
|
{
|
|
446
|
+
[self _updateTypingAttributes];
|
|
421
447
|
if (_comingFromJS) {
|
|
422
448
|
return;
|
|
423
449
|
}
|
|
@@ -680,9 +706,26 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
680
706
|
[_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
|
|
681
707
|
}
|
|
682
708
|
[self _restoreTextSelection];
|
|
709
|
+
[self _updateTypingAttributes];
|
|
683
710
|
_lastStringStateWasUpdatedWith = attributedString;
|
|
684
711
|
}
|
|
685
712
|
|
|
713
|
+
// Ensure that newly typed text will inherit any custom attributes. We follow the logic of RN Android, where attributes
|
|
714
|
+
// to the left of the cursor are copied into new text, unless we are at the start of the field, in which case we will
|
|
715
|
+
// copy the attributes from text to the right. This allows consistency between backed input and new AttributedText
|
|
716
|
+
// https://github.com/facebook/react-native/blob/3102a58df38d96f3dacef0530e4dbb399037fcd2/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/SetSpanOperation.kt#L30
|
|
717
|
+
- (void)_updateTypingAttributes
|
|
718
|
+
{
|
|
719
|
+
if (_backedTextInputView.attributedText.length > 0) {
|
|
720
|
+
NSUInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
|
|
721
|
+
toPosition:_backedTextInputView.selectedTextRange.start];
|
|
722
|
+
|
|
723
|
+
NSUInteger samplePoint = offsetStart == 0 ? 0 : offsetStart - 1;
|
|
724
|
+
_backedTextInputView.typingAttributes = [_backedTextInputView.attributedText attributesAtIndex:samplePoint
|
|
725
|
+
effectiveRange:NULL];
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
686
729
|
- (void)_setMultiline:(BOOL)multiline
|
|
687
730
|
{
|
|
688
731
|
[_backedTextInputView removeFromSuperview];
|
|
@@ -738,9 +781,10 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
|
|
738
781
|
_backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem;
|
|
739
782
|
|
|
740
783
|
if (shouldFallbackToBareTextComparison) {
|
|
741
|
-
return
|
|
784
|
+
return [newText.string isEqualToString:oldText.string];
|
|
742
785
|
} else {
|
|
743
|
-
return (
|
|
786
|
+
return RCTIsAttributedStringEffectivelySame(
|
|
787
|
+
newText, oldText, _originalTypingAttributes, static_cast<const TextInputProps &>(*_props).textAttributes);
|
|
744
788
|
}
|
|
745
789
|
}
|
|
746
790
|
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
#import <React/RCTConstants.h>
|
|
12
12
|
#import <React/RCTTouchableComponentViewProtocol.h>
|
|
13
13
|
#import <React/UIView+ComponentViewProtocol.h>
|
|
14
|
+
#if TARGET_OS_TV
|
|
15
|
+
#import <React/RCTTVRemoteSelectHandler.h>
|
|
16
|
+
#endif
|
|
14
17
|
#import <react/renderer/components/view/ViewEventEmitter.h>
|
|
15
18
|
#import <react/renderer/components/view/ViewProps.h>
|
|
16
19
|
#import <react/renderer/core/EventEmitter.h>
|
|
@@ -25,7 +28,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
25
28
|
/**
|
|
26
29
|
* UIView class for <View> component.
|
|
27
30
|
*/
|
|
31
|
+
#if TARGET_OS_TV
|
|
32
|
+
@interface RCTViewComponentView : UIView <RCTComponentViewProtocol, RCTTouchableComponentViewProtocol, RCTTVRemoteSelectHandlerDelegate> {
|
|
33
|
+
#else
|
|
28
34
|
@interface RCTViewComponentView : UIView <RCTComponentViewProtocol, RCTTouchableComponentViewProtocol> {
|
|
35
|
+
#endif
|
|
29
36
|
@protected
|
|
30
37
|
facebook::react::LayoutMetrics _layoutMetrics;
|
|
31
38
|
facebook::react::SharedViewProps _props;
|
|
@@ -72,6 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
72
79
|
@property(nonatomic, nullable) UIFocusGuide *focusGuideDown;
|
|
73
80
|
@property(nonatomic, nullable) UIFocusGuide *focusGuideLeft;
|
|
74
81
|
@property(nonatomic, nullable) UIFocusGuide *focusGuideRight;
|
|
82
|
+
@property(nonatomic, nullable, strong) RCTTVRemoteSelectHandler *tvRemoteSelectHandler;
|
|
75
83
|
#endif
|
|
76
84
|
|
|
77
85
|
/**
|
|
@@ -63,7 +63,6 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
63
63
|
BOOL _removeClippedSubviews;
|
|
64
64
|
NSMutableArray<UIView *> *_reactSubviews;
|
|
65
65
|
BOOL _motionEffectsAdded;
|
|
66
|
-
UILongPressGestureRecognizer * _pressRecognizer;
|
|
67
66
|
NSSet<NSString *> *_Nullable _propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN;
|
|
68
67
|
UIView *_containerView;
|
|
69
68
|
BOOL _useCustomContainerView;
|
|
@@ -267,62 +266,63 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
267
266
|
[[NSNotificationCenter defaultCenter] postNavigationBlurEventWithTag:@(self.tag) target:@(self.tag)];
|
|
268
267
|
}
|
|
269
268
|
|
|
270
|
-
- (void)sendSelectNotification
|
|
269
|
+
- (void)sendSelectNotification
|
|
271
270
|
{
|
|
272
|
-
|
|
271
|
+
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventSelect keyAction:RCTTVRemoteEventKeyActionUp tag:@(self.tag) target:@(self.tag)];
|
|
273
272
|
}
|
|
274
273
|
|
|
275
|
-
- (void)
|
|
274
|
+
- (void)sendLongSelectBeganNotification
|
|
276
275
|
{
|
|
277
|
-
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventLongSelect keyAction:
|
|
276
|
+
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventLongSelect keyAction:RCTTVRemoteEventKeyActionDown tag:@(self.tag) target:@(self.tag)];
|
|
278
277
|
}
|
|
279
278
|
|
|
280
|
-
- (void)
|
|
279
|
+
- (void)sendLongSelectEndedNotification
|
|
280
|
+
{
|
|
281
|
+
[[NSNotificationCenter defaultCenter] postNavigationPressEventWithType:RCTTVRemoteEventLongSelect keyAction:RCTTVRemoteEventKeyActionUp tag:@(self.tag) target:@(self.tag)];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
- (void)animatePressIn
|
|
281
285
|
{
|
|
282
286
|
if (_tvParallaxProperties.enabled == YES) {
|
|
283
|
-
float magnification = _tvParallaxProperties.magnification;
|
|
284
287
|
float pressMagnification = _tvParallaxProperties.pressMagnification;
|
|
285
288
|
|
|
286
289
|
// Duration of press animation
|
|
287
290
|
float pressDuration = _tvParallaxProperties.pressDuration;
|
|
288
291
|
|
|
289
|
-
// Delay of press animation
|
|
290
|
-
float pressDelay = _tvParallaxProperties.pressDelay;
|
|
291
|
-
|
|
292
|
-
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:pressDelay]];
|
|
293
|
-
|
|
294
292
|
[UIView animateWithDuration:(pressDuration/2)
|
|
295
293
|
animations:^{
|
|
296
294
|
self.transform = CGAffineTransformMakeScale(pressMagnification, pressMagnification);
|
|
297
295
|
}
|
|
298
|
-
completion:^(__unused BOOL
|
|
299
|
-
[UIView animateWithDuration:(pressDuration/2)
|
|
300
|
-
animations:^{
|
|
301
|
-
self.transform = CGAffineTransformMakeScale(magnification, magnification);
|
|
302
|
-
}
|
|
303
|
-
completion:^(__unused BOOL finished2) {
|
|
304
|
-
}];
|
|
305
|
-
}];
|
|
306
|
-
|
|
296
|
+
completion:^(__unused BOOL finished){}];
|
|
307
297
|
}
|
|
308
298
|
}
|
|
309
299
|
|
|
310
|
-
- (void)
|
|
300
|
+
- (void) animatePressOut
|
|
311
301
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
302
|
+
if (_tvParallaxProperties.enabled == YES) {
|
|
303
|
+
float magnification = _tvParallaxProperties.magnification;
|
|
304
|
+
|
|
305
|
+
// Duration of press animation
|
|
306
|
+
float pressDuration = _tvParallaxProperties.pressDuration;
|
|
307
|
+
|
|
308
|
+
[UIView animateWithDuration:(pressDuration/2)
|
|
309
|
+
animations:^{
|
|
310
|
+
self.transform = CGAffineTransformMakeScale(magnification, magnification);
|
|
311
|
+
}
|
|
312
|
+
completion:^(__unused BOOL finished){}];
|
|
323
313
|
}
|
|
324
314
|
}
|
|
325
315
|
|
|
316
|
+
- (void)emitPressInEvent
|
|
317
|
+
{
|
|
318
|
+
_eventEmitter->onPressIn();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
- (void)emitPressOutEvent
|
|
322
|
+
{
|
|
323
|
+
_eventEmitter->onPressOut();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
326
|
- (void)addParallaxMotionEffects
|
|
327
327
|
{
|
|
328
328
|
if(!_tvParallaxProperties.enabled) {
|
|
@@ -1040,16 +1040,9 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
1040
1040
|
// `isTVSelectable`
|
|
1041
1041
|
if (oldViewProps.isTVSelectable != newViewProps.isTVSelectable) {
|
|
1042
1042
|
if (newViewProps.isTVSelectable && ![self isTVFocusGuide]) {
|
|
1043
|
-
|
|
1044
|
-
pressRecognizer.allowedPressTypes = @[ @(UIPressTypeSelect) ];
|
|
1045
|
-
pressRecognizer.minimumPressDuration = 0;
|
|
1046
|
-
|
|
1047
|
-
[self addGestureRecognizer:pressRecognizer];
|
|
1048
|
-
_pressRecognizer = pressRecognizer;
|
|
1043
|
+
self.tvRemoteSelectHandler = [[RCTTVRemoteSelectHandler alloc]initWithView:self];
|
|
1049
1044
|
} else {
|
|
1050
|
-
|
|
1051
|
-
[self removeGestureRecognizer:_pressRecognizer];
|
|
1052
|
-
}
|
|
1045
|
+
self.tvRemoteSelectHandler = nil;
|
|
1053
1046
|
}
|
|
1054
1047
|
}
|
|
1055
1048
|
// `tvParallaxProperties
|