react-native-tvos 0.77.0-0rc5 → 0.77.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.
- package/Libraries/Components/TV/TVFocusGuideView.js +0 -1
- package/Libraries/Components/View/ViewPropTypes.d.ts +4 -2
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Core/setUpDeveloperTools.js +2 -3
- package/Libraries/Image/RCTImageLoader.mm +9 -1
- package/Libraries/Pressability/Pressability.js +2 -2
- package/Libraries/Text/TextInput/RCTBaseTextInputView.mm +1 -1
- package/Libraries/Utilities/HMRClient.js +0 -28
- package/Libraries/Utilities/HMRClientProdShim.js +0 -1
- package/React/Base/RCTConvert.mm +3 -1
- package/React/Base/RCTVersion.m +2 -2
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +85 -31
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +5 -2
- package/React/Views/RCTTVView.m +5 -2
- package/React/Views/ScrollView/RCTScrollView.m +63 -26
- package/ReactAndroid/api/ReactAndroid.api +3 -0
- package/ReactAndroid/cmake-utils/ReactNative-application.cmake +13 -3
- package/ReactAndroid/gradle.properties +3 -3
- package/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +8 -0
- package/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +8 -0
- package/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java +37 -0
- package/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +15 -8
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt +9 -8
- package/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +22 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java +16 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +1 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +12 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.mm +13 -4
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h +5 -0
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +27 -9
- package/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +6 -0
- package/ReactCommon/react/renderer/attributedstring/TextAttributes.h +2 -0
- package/ReactCommon/react/renderer/attributedstring/conversions.h +5 -0
- package/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +12 -0
- package/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h +2 -3
- package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +5 -3
- package/package.json +13 -10
- package/sdks/hermes-engine/hermes-utils.rb +2 -2
- package/sdks/hermesc/linux64-bin/hermesc +0 -0
- 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/src/private/featureflags/ReactNativeFeatureFlags.js +2 -2
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
PointerEvents,
|
|
18
18
|
FocusEvents,
|
|
19
19
|
PressEvents,
|
|
20
|
+
NativeFocusEvent,
|
|
21
|
+
NativeBlurEvent,
|
|
20
22
|
} from '../../Types/CoreEventTypes';
|
|
21
23
|
import {Touchable} from '../Touchable/Touchable';
|
|
22
24
|
import {AccessibilityProps} from './ViewAccessibility';
|
|
@@ -227,6 +229,6 @@ export interface ViewProps
|
|
|
227
229
|
*/
|
|
228
230
|
experimental_layoutConformance?: 'strict' | 'classic' | undefined;
|
|
229
231
|
|
|
230
|
-
readonly onFocus?: BubblingEventHandler<
|
|
231
|
-
readonly onBlur?: BubblingEventHandler<
|
|
232
|
+
readonly onFocus?: BubblingEventHandler<NativeFocusEvent> | undefined;
|
|
233
|
+
readonly onBlur?: BubblingEventHandler<NativeBlurEvent> | undefined;
|
|
232
234
|
}
|
|
@@ -42,9 +42,8 @@ if (__DEV__) {
|
|
|
42
42
|
if (!Platform.isTesting) {
|
|
43
43
|
const HMRClient = require('../Utilities/HMRClient');
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} else if (console._isPolyfilled) {
|
|
45
|
+
// TODO(T214991636): Remove legacy Metro log forwarding
|
|
46
|
+
if (console._isPolyfilled) {
|
|
48
47
|
// We assume full control over the console and send JavaScript logs to Metro.
|
|
49
48
|
[
|
|
50
49
|
'trace',
|
|
@@ -477,7 +477,15 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, CGSize size, CGFloat scal
|
|
|
477
477
|
|
|
478
478
|
// Add missing png extension
|
|
479
479
|
if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
|
|
480
|
-
|
|
480
|
+
// Check if there exists a file with that url on disk already
|
|
481
|
+
// This should fix issue https://github.com/facebook/react-native/issues/46870
|
|
482
|
+
if ([[NSFileManager defaultManager] fileExistsAtPath:request.URL.path]) {
|
|
483
|
+
mutableRequest.URL = request.URL;
|
|
484
|
+
} else {
|
|
485
|
+
// This is the default behavior in case there is no file on disk with no extension.
|
|
486
|
+
// We assume that the extension is `png`.
|
|
487
|
+
mutableRequest.URL = [request.URL URLByAppendingPathExtension:@"png"];
|
|
488
|
+
}
|
|
481
489
|
}
|
|
482
490
|
if (_redirectDelegate != nil) {
|
|
483
491
|
mutableRequest.URL = [_redirectDelegate redirectAssetsURL:mutableRequest.URL];
|
|
@@ -439,7 +439,7 @@ export default class Pressability {
|
|
|
439
439
|
_createEventHandlers(): EventHandlers {
|
|
440
440
|
const tvPressEventHandlers = {
|
|
441
441
|
onPressIn: (evt: any): void => {
|
|
442
|
-
if (this._config.disabled ===
|
|
442
|
+
if (this._config.disabled === true) {
|
|
443
443
|
return;
|
|
444
444
|
}
|
|
445
445
|
|
|
@@ -460,7 +460,7 @@ export default class Pressability {
|
|
|
460
460
|
}, delayLongPress + delayPressIn);
|
|
461
461
|
},
|
|
462
462
|
onPressOut: (evt: any): void => {
|
|
463
|
-
if (this._config.disabled ===
|
|
463
|
+
if (this._config.disabled === true) {
|
|
464
464
|
return;
|
|
465
465
|
}
|
|
466
466
|
this._cancelLongPressDelayTimeout();
|
|
@@ -480,7 +480,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
|
|
480
480
|
_maxLength.integerValue - (NSInteger)backedTextInputView.attributedText.string.length + (NSInteger)range.length,
|
|
481
481
|
0);
|
|
482
482
|
|
|
483
|
-
if (text.length >
|
|
483
|
+
if (text.length > allowedLength) {
|
|
484
484
|
// If we typed/pasted more than one character, limit the text inputted.
|
|
485
485
|
if (text.length > 1) {
|
|
486
486
|
if (allowedLength > 0) {
|
|
@@ -26,7 +26,6 @@ let hmrUnavailableReason: string | null = null;
|
|
|
26
26
|
let currentCompileErrorMessage: string | null = null;
|
|
27
27
|
let didConnect: boolean = false;
|
|
28
28
|
let pendingLogs: Array<[LogLevel, $ReadOnlyArray<mixed>]> = [];
|
|
29
|
-
let pendingFuseboxConsoleNotification = false;
|
|
30
29
|
|
|
31
30
|
type LogLevel =
|
|
32
31
|
| 'trace'
|
|
@@ -52,7 +51,6 @@ export type HMRClientNativeInterface = {|
|
|
|
52
51
|
isEnabled: boolean,
|
|
53
52
|
scheme?: string,
|
|
54
53
|
): void,
|
|
55
|
-
unstable_notifyFuseboxConsoleEnabled(): void,
|
|
56
54
|
|};
|
|
57
55
|
|
|
58
56
|
/**
|
|
@@ -142,29 +140,6 @@ const HMRClient: HMRClientNativeInterface = {
|
|
|
142
140
|
}
|
|
143
141
|
},
|
|
144
142
|
|
|
145
|
-
unstable_notifyFuseboxConsoleEnabled() {
|
|
146
|
-
if (!hmrClient) {
|
|
147
|
-
pendingFuseboxConsoleNotification = true;
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
hmrClient.send(
|
|
151
|
-
JSON.stringify({
|
|
152
|
-
type: 'log',
|
|
153
|
-
level: 'info',
|
|
154
|
-
data: [
|
|
155
|
-
'\n' +
|
|
156
|
-
'\u001B[7m' +
|
|
157
|
-
' \u001B[1m💡 JavaScript logs have moved!\u001B[22m They can now be ' +
|
|
158
|
-
'viewed in React Native DevTools. Tip: Type \u001B[1mj\u001B[22m in ' +
|
|
159
|
-
'the terminal to open (requires Google Chrome or Microsoft Edge).' +
|
|
160
|
-
'\u001B[27m' +
|
|
161
|
-
'\n',
|
|
162
|
-
],
|
|
163
|
-
}),
|
|
164
|
-
);
|
|
165
|
-
pendingFuseboxConsoleNotification = false;
|
|
166
|
-
},
|
|
167
|
-
|
|
168
143
|
// Called once by the bridge on startup, even if Fast Refresh is off.
|
|
169
144
|
// It creates the HMR client but doesn't actually set up the socket yet.
|
|
170
145
|
setup(
|
|
@@ -341,9 +316,6 @@ function flushEarlyLogs(client: MetroHMRClient) {
|
|
|
341
316
|
pendingLogs.forEach(([level, data]) => {
|
|
342
317
|
HMRClient.log(level, data);
|
|
343
318
|
});
|
|
344
|
-
if (pendingFuseboxConsoleNotification) {
|
|
345
|
-
HMRClient.unstable_notifyFuseboxConsoleEnabled();
|
|
346
|
-
}
|
|
347
319
|
} finally {
|
|
348
320
|
pendingLogs.length = 0;
|
|
349
321
|
}
|
package/React/Base/RCTConvert.mm
CHANGED
|
@@ -529,17 +529,19 @@ RCT_ENUM_CONVERTER(
|
|
|
529
529
|
}),
|
|
530
530
|
NSNotFound,
|
|
531
531
|
unsignedIntegerValue)
|
|
532
|
+
#endif
|
|
532
533
|
RCT_ENUM_CONVERTER(
|
|
533
534
|
UIModalPresentationStyle,
|
|
534
535
|
(@{
|
|
535
536
|
@"fullScreen" : @(UIModalPresentationFullScreen),
|
|
537
|
+
#if !TARGET_OS_TV
|
|
536
538
|
@"pageSheet" : @(UIModalPresentationPageSheet),
|
|
537
539
|
@"formSheet" : @(UIModalPresentationFormSheet),
|
|
540
|
+
#endif
|
|
538
541
|
@"overFullScreen" : @(UIModalPresentationOverFullScreen),
|
|
539
542
|
}),
|
|
540
543
|
UIModalPresentationFullScreen,
|
|
541
544
|
integerValue)
|
|
542
|
-
#endif
|
|
543
545
|
|
|
544
546
|
RCT_ENUM_CONVERTER(
|
|
545
547
|
UIViewContentMode,
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(77),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(1),
|
|
27
|
+
RCTVersionPrerelease: @"0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -1023,18 +1023,23 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1023
1023
|
[self sendBlurNotification];
|
|
1024
1024
|
[self removeSwipeGestureRecognizers];
|
|
1025
1025
|
[self resignFirstResponder];
|
|
1026
|
-
//
|
|
1027
|
-
//
|
|
1028
|
-
// Similarly
|
|
1026
|
+
// If scrolling is enabled:
|
|
1027
|
+
// - Scroll to the top when moving up and to the bottom when moving down.
|
|
1028
|
+
// - Similarly, scroll towards leading edge when moving towards leading edge and to the trailing edge when moving towards the trailing edge.
|
|
1029
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1030
|
+
BOOL isMovingTowardsLeadingEdge = (isRTL ? context.focusHeading == UIFocusHeadingRight : context.focusHeading == UIFocusHeadingLeft);
|
|
1031
|
+
BOOL isMovingTowardsTrailingEdge = (isRTL ? context.focusHeading == UIFocusHeadingLeft : context.focusHeading == UIFocusHeadingRight);
|
|
1029
1032
|
RCTEnhancedScrollView *scrollView = (RCTEnhancedScrollView *)_scrollView;
|
|
1030
|
-
if (
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1033
|
+
if (scrollView.isScrollEnabled) {
|
|
1034
|
+
if (context.focusHeading == UIFocusHeadingUp && scrollView.snapToStart) {
|
|
1035
|
+
[self scrollToVerticalOffset:0.0];
|
|
1036
|
+
} else if(context.focusHeading == UIFocusHeadingDown && scrollView.snapToEnd) {
|
|
1037
|
+
[self scrollToVerticalOffset:scrollView.contentSize.height];
|
|
1038
|
+
} else if(isMovingTowardsLeadingEdge && scrollView.snapToStart) {
|
|
1039
|
+
[self scrollToHorizontalOffset:0.0];
|
|
1040
|
+
} else if(isMovingTowardsTrailingEdge && scrollView.snapToEnd) {
|
|
1041
|
+
[self scrollToHorizontalOffset:scrollView.contentSize.width];
|
|
1042
|
+
}
|
|
1038
1043
|
}
|
|
1039
1044
|
}
|
|
1040
1045
|
}
|
|
@@ -1093,23 +1098,32 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1093
1098
|
|
|
1094
1099
|
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
1095
1100
|
{
|
|
1101
|
+
// If the previously focused item is this view and scrolling is disabled, defer to the superclass
|
|
1102
|
+
if (context.previouslyFocusedItem == self && !self.scrollView.isScrollEnabled) {
|
|
1103
|
+
return [super shouldUpdateFocusInContext:context];
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1096
1106
|
// Determine if the layout is Right-to-Left
|
|
1097
1107
|
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1098
1108
|
BOOL isHorizontal = _scrollView.contentSize.width > self.frame.size.width;
|
|
1099
1109
|
// Adjust for horizontal scrolling with RTL support
|
|
1100
1110
|
if (isHorizontal) {
|
|
1101
|
-
BOOL
|
|
1102
|
-
BOOL
|
|
1111
|
+
BOOL isMovingTowardsLeadingEdge = (isRTL ? context.focusHeading == UIFocusHeadingRight : context.focusHeading == UIFocusHeadingLeft);
|
|
1112
|
+
BOOL isMovingTowardsTrailingEdge = (isRTL ? context.focusHeading == UIFocusHeadingLeft : context.focusHeading == UIFocusHeadingRight);
|
|
1103
1113
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1114
|
+
BOOL isScrollingToLeading = (isMovingTowardsLeadingEdge && self.scrollView.contentOffset.x > 0);
|
|
1115
|
+
BOOL isScrollingToTrailing = (isMovingTowardsTrailingEdge && self.scrollView.contentOffset.x < self.scrollView.contentSize.width - MAX(self.scrollView.visibleSize.width, 1));
|
|
1116
|
+
|
|
1117
|
+
if (isScrollingToLeading || isScrollingToTrailing) {
|
|
1118
|
+
return (context.nextFocusedItem && [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem]);
|
|
1107
1119
|
}
|
|
1108
1120
|
} else {
|
|
1109
1121
|
// Handle vertical scrolling as before
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1122
|
+
BOOL isMovingUp = (context.focusHeading == UIFocusHeadingUp && self.scrollView.contentOffset.y > 0);
|
|
1123
|
+
BOOL isMovingDown = (context.focusHeading == UIFocusHeadingDown && self.scrollView.contentOffset.y < self.scrollView.contentSize.height - MAX(self.scrollView.visibleSize.height, 1));
|
|
1124
|
+
|
|
1125
|
+
if (isMovingUp || isMovingDown) {
|
|
1126
|
+
return (context.nextFocusedItem && [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem]);
|
|
1113
1127
|
}
|
|
1114
1128
|
}
|
|
1115
1129
|
return [super shouldUpdateFocusInContext:context];
|
|
@@ -1153,60 +1167,100 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
1153
1167
|
return duration;
|
|
1154
1168
|
}
|
|
1155
1169
|
|
|
1156
|
-
- (void)
|
|
1170
|
+
- (void)scrollToVerticalOffset:(CGFloat)yOffset
|
|
1157
1171
|
{
|
|
1158
1172
|
_blockFirstTouch = NO;
|
|
1159
1173
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1160
1174
|
CGFloat limitedOffset = yOffset;
|
|
1175
|
+
|
|
1176
|
+
// Ensure content size and visible size are non-negative
|
|
1177
|
+
CGFloat contentHeight = MAX(self.scrollView.contentSize.height, 0.0);
|
|
1178
|
+
CGFloat visibleHeight = MAX(self.scrollView.visibleSize.height, 0.0);
|
|
1179
|
+
|
|
1180
|
+
// Compute the maximum offset, ensuring it's non-negative
|
|
1181
|
+
CGFloat maxOffset = MAX(contentHeight - visibleHeight, 0.0);
|
|
1182
|
+
|
|
1183
|
+
// Clamp the offset within valid bounds
|
|
1161
1184
|
limitedOffset = MAX(limitedOffset, 0.0);
|
|
1162
|
-
limitedOffset = MIN(limitedOffset,
|
|
1185
|
+
limitedOffset = MIN(limitedOffset, maxOffset);
|
|
1186
|
+
|
|
1163
1187
|
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
1164
1188
|
self.scrollView.contentOffset =
|
|
1165
|
-
|
|
1189
|
+
CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
|
|
1166
1190
|
}];
|
|
1167
1191
|
});
|
|
1168
1192
|
}
|
|
1169
1193
|
|
|
1170
|
-
- (void)
|
|
1194
|
+
- (void)scrollToHorizontalOffset:(CGFloat)xOffset
|
|
1171
1195
|
{
|
|
1172
1196
|
_blockFirstTouch = NO;
|
|
1173
1197
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1174
1198
|
CGFloat limitedOffset = xOffset;
|
|
1199
|
+
|
|
1200
|
+
// Ensure content size and visible size are non-negative
|
|
1201
|
+
CGFloat contentWidth = MAX(self.scrollView.contentSize.width, 0.0);
|
|
1202
|
+
CGFloat visibleWidth = MAX(self.scrollView.visibleSize.width, 0.0);
|
|
1203
|
+
|
|
1204
|
+
// Compute the maximum offset, ensuring it's non-negative
|
|
1205
|
+
CGFloat maxOffset = MAX(contentWidth - visibleWidth, 0.0);
|
|
1206
|
+
|
|
1207
|
+
// Clamp the offset within valid bounds
|
|
1175
1208
|
limitedOffset = MAX(limitedOffset, 0.0);
|
|
1176
|
-
limitedOffset = MIN(limitedOffset,
|
|
1209
|
+
limitedOffset = MIN(limitedOffset, maxOffset);
|
|
1210
|
+
|
|
1177
1211
|
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
1178
1212
|
self.scrollView.contentOffset =
|
|
1179
|
-
|
|
1213
|
+
CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
|
|
1180
1214
|
}];
|
|
1181
1215
|
});
|
|
1182
1216
|
}
|
|
1183
1217
|
|
|
1184
1218
|
- (void)swipedUp
|
|
1185
1219
|
{
|
|
1220
|
+
if (!self.scrollView.scrollEnabled) {
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1186
1224
|
CGFloat newOffset = self.scrollView.contentOffset.y - [self swipeVerticalInterval];
|
|
1187
1225
|
// NSLog(@"Swiped up to %f", newOffset);
|
|
1188
|
-
[self
|
|
1226
|
+
[self scrollToVerticalOffset:newOffset];
|
|
1189
1227
|
}
|
|
1190
1228
|
|
|
1191
1229
|
- (void)swipedDown
|
|
1192
1230
|
{
|
|
1231
|
+
if (!self.scrollView.scrollEnabled) {
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1193
1235
|
CGFloat newOffset = self.scrollView.contentOffset.y + [self swipeVerticalInterval];
|
|
1194
1236
|
// NSLog(@"Swiped down to %f", newOffset);
|
|
1195
|
-
[self
|
|
1237
|
+
[self scrollToVerticalOffset:newOffset];
|
|
1196
1238
|
}
|
|
1197
1239
|
|
|
1198
1240
|
- (void)swipedLeft
|
|
1199
1241
|
{
|
|
1200
|
-
|
|
1242
|
+
if (!self.scrollView.scrollEnabled) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1247
|
+
NSInteger horizontalInterval = [self swipeHorizontalInterval];
|
|
1248
|
+
CGFloat newOffset = self.scrollView.contentOffset.x + (isRTL ? horizontalInterval : -horizontalInterval);
|
|
1201
1249
|
// NSLog(@"Swiped left to %f", newOffset);
|
|
1202
|
-
[self
|
|
1250
|
+
[self scrollToHorizontalOffset:newOffset];
|
|
1203
1251
|
}
|
|
1204
1252
|
|
|
1205
1253
|
- (void)swipedRight
|
|
1206
1254
|
{
|
|
1207
|
-
|
|
1255
|
+
if (!self.scrollView.scrollEnabled) {
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1260
|
+
NSInteger horizontalInterval = [self swipeHorizontalInterval];
|
|
1261
|
+
CGFloat newOffset = self.scrollView.contentOffset.x + (isRTL ? -horizontalInterval : horizontalInterval);
|
|
1208
1262
|
// NSLog(@"Swiped right to %f", newOffset);
|
|
1209
|
-
[self
|
|
1263
|
+
[self scrollToHorizontalOffset:newOffset];
|
|
1210
1264
|
}
|
|
1211
1265
|
|
|
1212
1266
|
- (void)addSwipeGestureRecognizers
|
|
@@ -585,7 +585,7 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
585
585
|
[self handleFocusGuide];
|
|
586
586
|
}
|
|
587
587
|
|
|
588
|
-
if (context.nextFocusedView == self
|
|
588
|
+
if (context.nextFocusedView == self) {
|
|
589
589
|
if(_eventEmitter) _eventEmitter->onFocus();
|
|
590
590
|
|
|
591
591
|
[self becomeFirstResponder];
|
|
@@ -594,7 +594,10 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
594
594
|
[self addParallaxMotionEffects];
|
|
595
595
|
[self sendFocusNotification:context];
|
|
596
596
|
} completion:^(void){}];
|
|
597
|
-
|
|
597
|
+
// Without this check, onBlur would also trigger when `TVFocusGuideView` transfers focus to its children.
|
|
598
|
+
// [self isTVFocusGuide] is false when autofocus and destinations are not used, so we cannot use that.
|
|
599
|
+
// Generally speaking, it would happen for any non-collapsable `View`.
|
|
600
|
+
} else if (context.previouslyFocusedView == self) {
|
|
598
601
|
if (_eventEmitter) _eventEmitter->onBlur();
|
|
599
602
|
|
|
600
603
|
[self disableDirectionalFocusGuides];
|
package/React/Views/RCTTVView.m
CHANGED
|
@@ -303,7 +303,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
303
303
|
[self handleFocusGuide];
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
if (context.nextFocusedView == self
|
|
306
|
+
if (context.nextFocusedView == self) {
|
|
307
307
|
if (self.onFocus) self.onFocus(nil);
|
|
308
308
|
[self becomeFirstResponder];
|
|
309
309
|
[self enableDirectionalFocusGuides];
|
|
@@ -311,7 +311,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
311
311
|
[self addParallaxMotionEffects];
|
|
312
312
|
[self sendFocusNotification:context];
|
|
313
313
|
} completion:^(void){}];
|
|
314
|
-
|
|
314
|
+
// Without this check, onBlur would also trigger when `TVFocusGuideView` transfers focus to its children.
|
|
315
|
+
// [self isTVFocusGuide] is false when autofocus and destinations are not used, so we cannot use that.
|
|
316
|
+
// Generally speaking, it would happen for any non-collapsable `View`.
|
|
317
|
+
} else if (context.previouslyFocusedView == self ) {
|
|
315
318
|
if (self.onBlur) self.onBlur(nil);
|
|
316
319
|
[self disableDirectionalFocusGuides];
|
|
317
320
|
[coordinator addCoordinatedAnimations:^(void){
|
|
@@ -1025,19 +1025,23 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
1025
1025
|
[self sendBlurNotification];
|
|
1026
1026
|
[self removeSwipeGestureRecognizers];
|
|
1027
1027
|
[self resignFirstResponder];
|
|
1028
|
-
//
|
|
1029
|
-
//
|
|
1030
|
-
// Similarly
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1028
|
+
// If scrolling is enabled:
|
|
1029
|
+
// - Scroll to the top when moving up and to the bottom when moving down.
|
|
1030
|
+
// - Similarly, scroll towards leading edge when moving towards leading edge and to the trailing edge when moving towards the trailing edge.
|
|
1031
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1032
|
+
BOOL isMovingTowardsLeadingEdge = (isRTL ? context.focusHeading == UIFocusHeadingRight : context.focusHeading == UIFocusHeadingLeft);
|
|
1033
|
+
BOOL isMovingTowardsTrailingEdge = (isRTL ? context.focusHeading == UIFocusHeadingLeft : context.focusHeading == UIFocusHeadingRight);
|
|
1034
|
+
if (self.scrollView.isScrollEnabled) {
|
|
1035
|
+
if (context.focusHeading == UIFocusHeadingUp && self.snapToStart) {
|
|
1036
|
+
[self scrollToVerticalOffset:0.0];
|
|
1037
|
+
} else if(context.focusHeading == UIFocusHeadingDown && self.snapToEnd) {
|
|
1038
|
+
[self scrollToVerticalOffset:self.scrollView.contentSize.height];
|
|
1039
|
+
} else if(isMovingTowardsLeadingEdge && self.snapToStart) {
|
|
1040
|
+
[self scrollToHorizontalOffset:0.0];
|
|
1041
|
+
} else if(isMovingTowardsLeadingEdge && self.snapToEnd) {
|
|
1042
|
+
[self scrollToHorizontalOffset:self.scrollView.contentSize.width];
|
|
1043
|
+
}
|
|
1039
1044
|
}
|
|
1040
|
-
|
|
1041
1045
|
}
|
|
1042
1046
|
}
|
|
1043
1047
|
|
|
@@ -1093,22 +1097,31 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
1093
1097
|
|
|
1094
1098
|
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
1095
1099
|
{
|
|
1100
|
+
// If the previously focused item is this view and scrolling is disabled, defer to the superclass
|
|
1101
|
+
if (context.previouslyFocusedItem == self && !self.scrollView.isScrollEnabled) {
|
|
1102
|
+
return [super shouldUpdateFocusInContext:context];
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1096
1105
|
// Determine if the layout is Right-to-Left
|
|
1097
1106
|
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1098
1107
|
// Adjust for horizontal scrolling with RTL support
|
|
1099
1108
|
if ([self isHorizontal:self.scrollView]) {
|
|
1100
|
-
BOOL
|
|
1101
|
-
BOOL
|
|
1109
|
+
BOOL isMovingTowardsLeadingEdge = (isRTL ? context.focusHeading == UIFocusHeadingRight : context.focusHeading == UIFocusHeadingLeft);
|
|
1110
|
+
BOOL isMovingTowardsTrailingEdge = (isRTL ? context.focusHeading == UIFocusHeadingLeft : context.focusHeading == UIFocusHeadingRight);
|
|
1111
|
+
|
|
1112
|
+
BOOL isScrollingToLeading = (isMovingTowardsLeadingEdge && self.scrollView.contentOffset.x > 0);
|
|
1113
|
+
BOOL isScrollingToTrailing = (isMovingTowardsTrailingEdge && self.scrollView.contentOffset.x < self.scrollView.contentSize.width - MAX(self.scrollView.visibleSize.width, 1));
|
|
1102
1114
|
|
|
1103
|
-
if (
|
|
1104
|
-
(
|
|
1105
|
-
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
1115
|
+
if (isScrollingToLeading || isScrollingToTrailing) {
|
|
1116
|
+
return (context.nextFocusedItem && [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem]);
|
|
1106
1117
|
}
|
|
1107
1118
|
} else {
|
|
1108
1119
|
// Handle vertical scrolling as before
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1120
|
+
BOOL isMovingUp = (context.focusHeading == UIFocusHeadingUp && self.scrollView.contentOffset.y > 0);
|
|
1121
|
+
BOOL isMovingDown = (context.focusHeading == UIFocusHeadingDown && self.scrollView.contentOffset.y < self.scrollView.contentSize.height - MAX(self.scrollView.visibleSize.height, 1));
|
|
1122
|
+
|
|
1123
|
+
if (isMovingUp || isMovingDown) {
|
|
1124
|
+
return (context.nextFocusedItem && [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem]);
|
|
1112
1125
|
}
|
|
1113
1126
|
}
|
|
1114
1127
|
return [super shouldUpdateFocusInContext:context];
|
|
@@ -1154,11 +1167,21 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
1154
1167
|
_blockFirstTouch = NO;
|
|
1155
1168
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1156
1169
|
CGFloat limitedOffset = yOffset;
|
|
1170
|
+
|
|
1171
|
+
// Ensure content size and visible size are non-negative
|
|
1172
|
+
CGFloat contentHeight = MAX(self.scrollView.contentSize.height, 0.0);
|
|
1173
|
+
CGFloat visibleHeight = MAX(self.scrollView.visibleSize.height, 0.0);
|
|
1174
|
+
|
|
1175
|
+
// Compute the maximum offset, ensuring it's non-negative
|
|
1176
|
+
CGFloat maxOffset = MAX(contentHeight - visibleHeight, 0.0);
|
|
1177
|
+
|
|
1178
|
+
// Clamp the offset within valid bounds
|
|
1157
1179
|
limitedOffset = MAX(limitedOffset, 0.0);
|
|
1158
|
-
limitedOffset = MIN(limitedOffset,
|
|
1180
|
+
limitedOffset = MIN(limitedOffset, maxOffset);
|
|
1181
|
+
|
|
1159
1182
|
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
1160
1183
|
self.scrollView.contentOffset =
|
|
1161
|
-
|
|
1184
|
+
CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
|
|
1162
1185
|
}];
|
|
1163
1186
|
});
|
|
1164
1187
|
}
|
|
@@ -1168,11 +1191,21 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
1168
1191
|
_blockFirstTouch = NO;
|
|
1169
1192
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1170
1193
|
CGFloat limitedOffset = xOffset;
|
|
1194
|
+
|
|
1195
|
+
// Ensure content size and visible size are non-negative
|
|
1196
|
+
CGFloat contentWidth = MAX(self.scrollView.contentSize.width, 0.0);
|
|
1197
|
+
CGFloat visibleWidth = MAX(self.scrollView.visibleSize.width, 0.0);
|
|
1198
|
+
|
|
1199
|
+
// Compute the maximum offset, ensuring it's non-negative
|
|
1200
|
+
CGFloat maxOffset = MAX(contentWidth - visibleWidth, 0.0);
|
|
1201
|
+
|
|
1202
|
+
// Clamp the offset within valid bounds
|
|
1171
1203
|
limitedOffset = MAX(limitedOffset, 0.0);
|
|
1172
|
-
limitedOffset = MIN(limitedOffset,
|
|
1204
|
+
limitedOffset = MIN(limitedOffset, maxOffset);
|
|
1205
|
+
|
|
1173
1206
|
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
1174
1207
|
self.scrollView.contentOffset =
|
|
1175
|
-
|
|
1208
|
+
CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
|
|
1176
1209
|
}];
|
|
1177
1210
|
});
|
|
1178
1211
|
}
|
|
@@ -1205,7 +1238,9 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
1205
1238
|
return;
|
|
1206
1239
|
}
|
|
1207
1240
|
|
|
1208
|
-
|
|
1241
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1242
|
+
NSInteger horizontalInterval = [self swipeHorizontalInterval];
|
|
1243
|
+
CGFloat newOffset = self.scrollView.contentOffset.x + (isRTL ? horizontalInterval : -horizontalInterval);
|
|
1209
1244
|
// NSLog(@"Swiped left to %f", newOffset);
|
|
1210
1245
|
[self scrollToHorizontalOffset:newOffset];
|
|
1211
1246
|
}
|
|
@@ -1216,7 +1251,9 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
1216
1251
|
return;
|
|
1217
1252
|
}
|
|
1218
1253
|
|
|
1219
|
-
|
|
1254
|
+
BOOL isRTL = [[RCTI18nUtil sharedInstance] isRTL];
|
|
1255
|
+
NSInteger horizontalInterval = [self swipeHorizontalInterval];
|
|
1256
|
+
CGFloat newOffset = self.scrollView.contentOffset.x + (isRTL ? -horizontalInterval : horizontalInterval);
|
|
1220
1257
|
// NSLog(@"Swiped right to %f", newOffset);
|
|
1221
1258
|
[self scrollToHorizontalOffset:newOffset];
|
|
1222
1259
|
}
|
|
@@ -608,6 +608,7 @@ public abstract class com/facebook/react/bridge/BaseJavaModule : com/facebook/re
|
|
|
608
608
|
protected final fun getReactApplicationContextIfActiveOrWarn ()Lcom/facebook/react/bridge/ReactApplicationContext;
|
|
609
609
|
public fun initialize ()V
|
|
610
610
|
public fun invalidate ()V
|
|
611
|
+
protected fun setEventEmitterCallback (Lcom/facebook/react/bridge/CxxCallbackImpl;)V
|
|
611
612
|
}
|
|
612
613
|
|
|
613
614
|
public abstract interface class com/facebook/react/bridge/BridgeReactContext$RCTDeviceEventEmitter : com/facebook/react/bridge/JavaScriptModule {
|
|
@@ -7443,6 +7444,7 @@ public class com/facebook/react/views/text/TextAttributeProps {
|
|
|
7443
7444
|
public static final field TA_KEY_LETTER_SPACING S
|
|
7444
7445
|
public static final field TA_KEY_LINE_BREAK_STRATEGY S
|
|
7445
7446
|
public static final field TA_KEY_LINE_HEIGHT S
|
|
7447
|
+
public static final field TA_KEY_MAX_FONT_SIZE_MULTIPLIER S
|
|
7446
7448
|
public static final field TA_KEY_OPACITY S
|
|
7447
7449
|
public static final field TA_KEY_ROLE S
|
|
7448
7450
|
public static final field TA_KEY_TEXT_DECORATION_COLOR S
|
|
@@ -7475,6 +7477,7 @@ public class com/facebook/react/views/text/TextAttributeProps {
|
|
|
7475
7477
|
protected field mLetterSpacingInput F
|
|
7476
7478
|
protected field mLineHeight F
|
|
7477
7479
|
protected field mLineHeightInput F
|
|
7480
|
+
protected field mMaxFontSizeMultiplier F
|
|
7478
7481
|
protected field mNumberOfLines I
|
|
7479
7482
|
protected field mOpacity F
|
|
7480
7483
|
protected field mRole Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$Role;
|
|
@@ -39,9 +39,19 @@ if (PROJECT_ROOT_DIR)
|
|
|
39
39
|
# variable is defined if user need to access it.
|
|
40
40
|
endif ()
|
|
41
41
|
|
|
42
|
-
file(GLOB
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
file(GLOB override_cpp_SRC CONFIGURE_DEPENDS *.cpp)
|
|
43
|
+
# We check if the user is providing a custom OnLoad.cpp file. If so, we pick that
|
|
44
|
+
# for compilation. Otherwise we fallback to using the `default-app-setup/OnLoad.cpp`
|
|
45
|
+
# file instead.
|
|
46
|
+
if(override_cpp_SRC)
|
|
47
|
+
file(GLOB input_SRC CONFIGURE_DEPENDS
|
|
48
|
+
*.cpp
|
|
49
|
+
${BUILD_DIR}/generated/autolinking/src/main/jni/*.cpp)
|
|
50
|
+
else()
|
|
51
|
+
file(GLOB input_SRC CONFIGURE_DEPENDS
|
|
52
|
+
${REACT_ANDROID_DIR}/cmake-utils/default-app-setup/*.cpp
|
|
53
|
+
${BUILD_DIR}/generated/autolinking/src/main/jni/*.cpp)
|
|
54
|
+
endif()
|
|
45
55
|
|
|
46
56
|
add_library(${CMAKE_PROJECT_NAME} SHARED ${input_SRC})
|
|
47
57
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
VERSION_NAME=0.77.0
|
|
2
|
-
react.internal.publishingGroup=
|
|
1
|
+
VERSION_NAME=0.77.1-0
|
|
2
|
+
react.internal.publishingGroup=io.github.react-native-tvos
|
|
3
3
|
|
|
4
4
|
android.useAndroidX=true
|
|
5
5
|
|
|
@@ -31,4 +31,4 @@ binaryCompatibilityValidator.ignoredPackages=com.facebook.debug,\
|
|
|
31
31
|
binaryCompatibilityValidator.nonPublicMarkers=com.facebook.react.common.annotations.VisibleForTesting,\
|
|
32
32
|
com.facebook.react.common.annotations.UnstableReactNativeAPI
|
|
33
33
|
binaryCompatibilityValidator.validationDisabled=true
|
|
34
|
-
binaryCompatibilityValidator.outputApiFileName=ReactAndroid
|
|
34
|
+
binaryCompatibilityValidator.outputApiFileName=ReactAndroid
|