react-native-tvos 0.73.4-0rc0 → 0.73.6-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/Touchable/TouchableHighlight.js +4 -1
- package/Libraries/Components/Touchable/TouchableNativeFeedback.js +1 -4
- package/Libraries/Components/Touchable/TouchableOpacity.js +1 -4
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.js +1 -4
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/LogBox/Data/parseLogBoxLog.js +1 -1
- package/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm +48 -0
- package/README.md +23 -14
- package/React/Base/RCTVersion.m +2 -2
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +246 -0
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +20 -13
- package/React/React-RCTFabric.podspec +3 -2
- package/React/Views/RCTTVView.m +7 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/package.json +7 -7
- package/scripts/cocoapods/new_architecture.rb +5 -1
- package/scripts/cocoapods/utils.rb +21 -0
- package/scripts/codegen/generate-artifacts-executor.js +18 -11
- package/scripts/react_native_pods.rb +1 -0
- package/scripts/xcode/with-environment.sh +1 -1
- package/sdks/.hermesversion +1 -1
- package/sdks/hermes-engine/hermes-utils.rb +4 -3
- 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/sdks/hermesc/win64-bin/msvcp140.dll +0 -0
- package/sdks/hermesc/win64-bin/vcruntime140.dll +0 -0
- package/sdks/hermesc/win64-bin/vcruntime140_1.dll +0 -0
- package/template/package.json +1 -1
|
@@ -348,7 +348,9 @@ class TouchableHighlight extends React.Component<Props, State> {
|
|
|
348
348
|
onLayout={this.props.onLayout}
|
|
349
349
|
hitSlop={this.props.hitSlop}
|
|
350
350
|
hasTVPreferredFocus={this.props.hasTVPreferredFocus === true}
|
|
351
|
-
isTVSelectable={
|
|
351
|
+
isTVSelectable={
|
|
352
|
+
this.props.isTVSelectable !== false && this.props.accessible !== false
|
|
353
|
+
}
|
|
352
354
|
tvParallaxProperties={this.props.tvParallaxProperties}
|
|
353
355
|
nextFocusDown={tagForComponentOrHandle(this.props.nextFocusDown)}
|
|
354
356
|
nextFocusForward={tagForComponentOrHandle(this.props.nextFocusForward)}
|
|
@@ -376,6 +378,7 @@ class TouchableHighlight extends React.Component<Props, State> {
|
|
|
376
378
|
}
|
|
377
379
|
|
|
378
380
|
componentDidMount(): void {
|
|
381
|
+
this.state.pressability.configure(this._createPressabilityConfig());
|
|
379
382
|
this._isMounted = true;
|
|
380
383
|
if (Platform.isTV) {
|
|
381
384
|
this._tvTouchable = new TVTouchable(this, {
|
|
@@ -340,6 +340,7 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
|
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
componentDidMount(): void {
|
|
343
|
+
this.state.pressability.configure(this._createPressabilityConfig());
|
|
343
344
|
if (Platform.isTV) {
|
|
344
345
|
this._tvTouchable = new TVTouchable(this, {
|
|
345
346
|
getDisabled: () => this.props.disabled === true,
|
|
@@ -371,10 +372,6 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
|
|
|
371
372
|
this.state.pressability.configure(this._createPressabilityConfig());
|
|
372
373
|
}
|
|
373
374
|
|
|
374
|
-
componentDidMount(): mixed {
|
|
375
|
-
this.state.pressability.configure(this._createPressabilityConfig());
|
|
376
|
-
}
|
|
377
|
-
|
|
378
375
|
componentWillUnmount(): void {
|
|
379
376
|
if (Platform.isTV) {
|
|
380
377
|
if (this._tvTouchable != null) {
|
|
@@ -312,6 +312,7 @@ class TouchableOpacity extends React.Component<Props, State> {
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
componentDidMount(): void {
|
|
315
|
+
this.state.pressability.configure(this._createPressabilityConfig());
|
|
315
316
|
if (Platform.isTV) {
|
|
316
317
|
this._tvTouchable = new TVTouchable(this, {
|
|
317
318
|
getDisabled: () => this.props.disabled === true,
|
|
@@ -356,10 +357,6 @@ class TouchableOpacity extends React.Component<Props, State> {
|
|
|
356
357
|
}
|
|
357
358
|
}
|
|
358
359
|
|
|
359
|
-
componentDidMount(): void {
|
|
360
|
-
this.state.pressability.configure(this._createPressabilityConfig());
|
|
361
|
-
}
|
|
362
|
-
|
|
363
360
|
componentWillUnmount(): void {
|
|
364
361
|
if (Platform.isTV) {
|
|
365
362
|
if (this._tvTouchable != null) {
|
|
@@ -192,6 +192,7 @@ class TouchableWithoutFeedback extends React.Component<Props, State> {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
componentDidMount(): void {
|
|
195
|
+
this.state.pressability.configure(createPressabilityConfig(this.props));
|
|
195
196
|
if (Platform.isTV) {
|
|
196
197
|
this._tvTouchable = new TVTouchable(this, {
|
|
197
198
|
getDisabled: () => this.props.disabled === true,
|
|
@@ -223,10 +224,6 @@ class TouchableWithoutFeedback extends React.Component<Props, State> {
|
|
|
223
224
|
this.state.pressability.configure(createPressabilityConfig(this.props));
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
componentDidMount(): mixed {
|
|
227
|
-
this.state.pressability.configure(createPressabilityConfig(this.props));
|
|
228
|
-
}
|
|
229
|
-
|
|
230
227
|
componentWillUnmount(): void {
|
|
231
228
|
if (Platform.isTV) {
|
|
232
229
|
if (this._tvTouchable != null) {
|
|
@@ -192,7 +192,7 @@ export function parseComponentStack(message: string): ComponentStack {
|
|
|
192
192
|
if (!s) {
|
|
193
193
|
return null;
|
|
194
194
|
}
|
|
195
|
-
const match = s.match(/(.*) \(at (.*\.js):([\d]+)\)/);
|
|
195
|
+
const match = s.match(/(.*) \(at (.*\.(?:js|jsx|ts|tsx)):([\d]+)\)/);
|
|
196
196
|
if (!match) {
|
|
197
197
|
return null;
|
|
198
198
|
}
|
|
@@ -158,6 +158,8 @@
|
|
|
158
158
|
[attributedText insertAttributedString:propertyAttributedText atIndex:0];
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
[self postprocessAttributedText:attributedText];
|
|
162
|
+
|
|
161
163
|
NSAttributedString *newAttributedText;
|
|
162
164
|
if (![_previousAttributedText isEqualToAttributedString:attributedText]) {
|
|
163
165
|
// We have to follow `set prop` pattern:
|
|
@@ -191,6 +193,52 @@
|
|
|
191
193
|
}];
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
- (void)postprocessAttributedText:(NSMutableAttributedString *)attributedText
|
|
197
|
+
{
|
|
198
|
+
__block CGFloat maximumLineHeight = 0;
|
|
199
|
+
|
|
200
|
+
[attributedText enumerateAttribute:NSParagraphStyleAttributeName
|
|
201
|
+
inRange:NSMakeRange(0, attributedText.length)
|
|
202
|
+
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
|
203
|
+
usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange range, __unused BOOL *stop) {
|
|
204
|
+
if (!paragraphStyle) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
maximumLineHeight = MAX(paragraphStyle.maximumLineHeight, maximumLineHeight);
|
|
209
|
+
}];
|
|
210
|
+
|
|
211
|
+
if (maximumLineHeight == 0) {
|
|
212
|
+
// `lineHeight` was not specified, nothing to do.
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
__block CGFloat maximumFontLineHeight = 0;
|
|
217
|
+
|
|
218
|
+
[attributedText enumerateAttribute:NSFontAttributeName
|
|
219
|
+
inRange:NSMakeRange(0, attributedText.length)
|
|
220
|
+
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
|
221
|
+
usingBlock:^(UIFont *font, NSRange range, __unused BOOL *stop) {
|
|
222
|
+
if (!font) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (maximumFontLineHeight <= font.lineHeight) {
|
|
227
|
+
maximumFontLineHeight = font.lineHeight;
|
|
228
|
+
}
|
|
229
|
+
}];
|
|
230
|
+
|
|
231
|
+
if (maximumLineHeight < maximumFontLineHeight) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
CGFloat baseLineOffset = maximumLineHeight / 2.0 - maximumFontLineHeight / 2.0;
|
|
236
|
+
|
|
237
|
+
[attributedText addAttribute:NSBaselineOffsetAttributeName
|
|
238
|
+
value:@(baseLineOffset)
|
|
239
|
+
range:NSMakeRange(0, attributedText.length)];
|
|
240
|
+
}
|
|
241
|
+
|
|
194
242
|
#pragma mark -
|
|
195
243
|
|
|
196
244
|
- (NSAttributedString *)measurableAttributedText
|
package/README.md
CHANGED
|
@@ -59,12 +59,12 @@ yarn create react-native-app TestApp --template https://github.com/react-native-
|
|
|
59
59
|
cd TestApp
|
|
60
60
|
# Now build and start the app in the tvOS Simulator - this will only work on a macOS machine.
|
|
61
61
|
# This command can also be run via "yarn tvos".
|
|
62
|
-
npx expo run:ios --scheme
|
|
62
|
+
npx expo run:ios --scheme TestApp-tvOS --device "Apple TV"
|
|
63
63
|
# You can also build and start the app on an iOS phone simulator.
|
|
64
64
|
# This command can also be run via "yarn ios".
|
|
65
65
|
npx expo run:ios
|
|
66
66
|
# or specify a simulator:
|
|
67
|
-
npx expo run:ios --scheme
|
|
67
|
+
npx expo run:ios --scheme TestApp --device "iPhone 15"
|
|
68
68
|
# This command builds and starts the app in an Android TV emulator or a phone emulator (needs to be created in advance).
|
|
69
69
|
# This command can also be run via "yarn android".
|
|
70
70
|
npx expo run:android --device tv_api_31
|
|
@@ -204,15 +204,24 @@ class Game2048 extends React.Component {
|
|
|
204
204
|
|
|
205
205
|
- _TVFocusGuideView_: This component provides support for Apple's `UIFocusGuide` API and is implemented in the same way for Android TV, to help ensure that focusable controls can be navigated to, even if they are not directly in line with other controls. An example is provided in `RNTester` that shows two different ways of using this component.
|
|
206
206
|
|
|
207
|
-
| Prop | Value | Description |
|
|
208
|
-
|---|---|---|
|
|
209
|
-
| destinations | any[]? | Array of `Component`s to register as destinations of the FocusGuideView |
|
|
210
|
-
| autoFocus | boolean? | If true, `TVFocusGuide` will automatically manage focus for you. It will redirect the focus to the first focusable child on the first visit. It also remembers the last focused child and redirects the focus to it on the subsequent visits. `destinations` prop takes precedence over this prop when used together. |
|
|
211
|
-
| trapFocus* (Up, Down, Left, Right) | Prevents focus escaping from the container for the given directions. |
|
|
212
|
-
|
|
213
|
-
More information on the focus handling improvements above can be found in [this article](https://medium.com/xite-engineering/revolutionizing-focus-management-in-tv-applications-with-react-native-10ba69bd90).
|
|
214
|
-
|
|
215
|
-
- _Next Focus Direction_: the props `nextFocus*` on `View` should work as expected on iOS too (previously android only). One caveat is that if there is no focusable in the `nextFocusable*` direction next to the starting view, iOS doesn't check if we want to override the destination.
|
|
216
|
-
|
|
217
|
-
- _TVTextScrollView_: On Apple TV, a ScrollView will not scroll unless there are focusable items inside it or above/below it. This component wraps ScrollView and uses tvOS-specific native code to allow scrolling using swipe gestures from the remote control.
|
|
218
|
-
|
|
207
|
+
| Prop | Value | Description |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| destinations | any[]? | Array of `Component`s to register as destinations of the FocusGuideView |
|
|
210
|
+
| autoFocus | boolean? | If true, `TVFocusGuide` will automatically manage focus for you. It will redirect the focus to the first focusable child on the first visit. It also remembers the last focused child and redirects the focus to it on the subsequent visits. `destinations` prop takes precedence over this prop when used together. |
|
|
211
|
+
| trapFocus* (Up, Down, Left, Right) | Prevents focus escaping from the container for the given directions. |
|
|
212
|
+
|
|
213
|
+
More information on the focus handling improvements above can be found in [this article](https://medium.com/xite-engineering/revolutionizing-focus-management-in-tv-applications-with-react-native-10ba69bd90).
|
|
214
|
+
|
|
215
|
+
- _Next Focus Direction_: the props `nextFocus*` on `View` should work as expected on iOS too (previously android only). One caveat is that if there is no focusable in the `nextFocusable*` direction next to the starting view, iOS doesn't check if we want to override the destination.
|
|
216
|
+
|
|
217
|
+
- _TVTextScrollView_: On Apple TV, a ScrollView will not scroll unless there are focusable items inside it or above/below it. This component wraps ScrollView and uses tvOS-specific native code to allow scrolling using swipe gestures from the remote control.
|
|
218
|
+
|
|
219
|
+
- VirtualizedList: We extend `VirtualizedList` to make virtualization work well with focus management in mind. All of the improvements that we made are automatically available to all the VirtualizedList based components such as `FlatList`.
|
|
220
|
+
- Defaults
|
|
221
|
+
- VirtualizeList contents are automatically wrapped with a `TVFocusGuideView` with `trapFocus*` properties enabled depending on the orientation of the list. This default makes sure that focus doesn't leave the list accidentally due to a virtualization issue etc. until reaching the beginning or the end of the list.
|
|
222
|
+
|
|
223
|
+
New Props:
|
|
224
|
+
|
|
225
|
+
| Prop | Value | Description |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| additionalRenderRegions | {first: number; last: number;}[]? | Array of `RenderRegions` that allows you to define regions in the list that are not subject to virtualization, ensuring they are always rendered. This is particularly useful for preventing blank areas in critical parts of the list. These regions are rendered lazily after the initial render and are specified as an array of objects, each with `first` and `last` indices marking the beginning and end of the non-virtualized region based on index. See the [feature proposal](https://github.com/react-native-tvos/react-native-tvos/discussions/663) for more context. |
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(73),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(6),
|
|
27
|
+
RCTVersionPrerelease: @"0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -24,9 +24,14 @@
|
|
|
24
24
|
#import "RCTEnhancedScrollView.h"
|
|
25
25
|
#import "RCTFabricComponentsPlugins.h"
|
|
26
26
|
|
|
27
|
+
#if TARGET_OS_TV
|
|
28
|
+
#import "RCTTVRemoteHandler.h"
|
|
29
|
+
#endif
|
|
30
|
+
|
|
27
31
|
using namespace facebook::react;
|
|
28
32
|
|
|
29
33
|
static const CGFloat kClippingLeeway = 44.0;
|
|
34
|
+
static const float TV_DEFAULT_SWIPE_DURATION = 0.3;
|
|
30
35
|
|
|
31
36
|
static UIScrollViewKeyboardDismissMode RCTUIKeyboardDismissModeFromProps(const ScrollViewProps &props)
|
|
32
37
|
{
|
|
@@ -105,6 +110,9 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
|
|
|
105
110
|
|
|
106
111
|
CGRect _prevFirstVisibleFrame;
|
|
107
112
|
__weak UIView *_firstVisibleView;
|
|
113
|
+
|
|
114
|
+
BOOL _blockFirstTouch;
|
|
115
|
+
NSMutableDictionary *_tvRemoteGestureRecognizers;
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
+ (RCTScrollViewComponentView *_Nullable)findScrollViewComponentViewForView:(UIView *)view
|
|
@@ -139,6 +147,8 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
|
|
|
139
147
|
} else {
|
|
140
148
|
_scrollEventThrottle = INFINITY;
|
|
141
149
|
}
|
|
150
|
+
|
|
151
|
+
_tvRemoteGestureRecognizers = [NSMutableDictionary new];
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
return self;
|
|
@@ -792,6 +802,242 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
|
|
|
792
802
|
}
|
|
793
803
|
}
|
|
794
804
|
|
|
805
|
+
#pragma mark Apple TV swipe and focus handling
|
|
806
|
+
|
|
807
|
+
#if TARGET_OS_TV
|
|
808
|
+
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
809
|
+
withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
|
|
810
|
+
{
|
|
811
|
+
if (context.previouslyFocusedView == context.nextFocusedView || !_props->isTVSelectable) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
if (context.nextFocusedView == self) {
|
|
815
|
+
[self becomeFirstResponder];
|
|
816
|
+
[self addSwipeGestureRecognizers];
|
|
817
|
+
[self sendFocusNotification];
|
|
818
|
+
// if we enter the scroll view from different view then block first touch event since it is the event that triggered the focus
|
|
819
|
+
_blockFirstTouch = (unsigned long)context.focusHeading != 0;
|
|
820
|
+
[self addArrowsListeners];
|
|
821
|
+
} else if (context.previouslyFocusedView == self) {
|
|
822
|
+
[self removeArrowsListeners];
|
|
823
|
+
[self sendBlurNotification];
|
|
824
|
+
[self removeSwipeGestureRecognizers];
|
|
825
|
+
[self resignFirstResponder];
|
|
826
|
+
// if we leave the scroll view and go up, then scroll to top; if going down,
|
|
827
|
+
// scroll to bottom
|
|
828
|
+
// Similarly for left and right
|
|
829
|
+
RCTEnhancedScrollView *scrollView = (RCTEnhancedScrollView *)_scrollView;
|
|
830
|
+
if (context.focusHeading == UIFocusHeadingUp && scrollView.snapToStart) {
|
|
831
|
+
[self swipeVerticalScrollToOffset:0.0];
|
|
832
|
+
} else if(context.focusHeading == UIFocusHeadingDown && scrollView.snapToEnd) {
|
|
833
|
+
[self swipeVerticalScrollToOffset:scrollView.contentSize.height];
|
|
834
|
+
} else if(context.focusHeading == UIFocusHeadingLeft && scrollView.snapToStart) {
|
|
835
|
+
[self swipeHorizontalScrollToOffset:0.0];
|
|
836
|
+
} else if(context.focusHeading == UIFocusHeadingRight && scrollView.snapToEnd) {
|
|
837
|
+
[self swipeHorizontalScrollToOffset:scrollView.contentSize.width];
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
- (void)addArrowsListeners
|
|
843
|
+
{
|
|
844
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
845
|
+
selector:@selector(handleTVNavigationEventNotification:)
|
|
846
|
+
name:@"RCTTVNavigationEventNotification"
|
|
847
|
+
object:nil];
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
- (void)removeArrowsListeners
|
|
851
|
+
{
|
|
852
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self
|
|
853
|
+
name:@"RCTTVNavigationEventNotification"
|
|
854
|
+
object:nil];
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
- (void)handleTVNavigationEventNotification:(NSNotification *)notif
|
|
858
|
+
{
|
|
859
|
+
NSArray *supportedEvents = [NSArray arrayWithObjects:@"up", @"down", @"left", @"right", nil];
|
|
860
|
+
|
|
861
|
+
if (notif.object == nil || notif.object[@"eventType"] == nil || ![supportedEvents containsObject:notif.object[@"eventType"]] ) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (_blockFirstTouch) {
|
|
866
|
+
_blockFirstTouch = NO;
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
BOOL isHorizontal = _scrollView.contentSize.width > self.frame.size.width;
|
|
871
|
+
if (!isHorizontal) {
|
|
872
|
+
if ([notif.object[@"eventType"] isEqual: @"down"]) {
|
|
873
|
+
[self swipedDown];
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if ([notif.object[@"eventType"] isEqual: @"up"]) {
|
|
878
|
+
[self swipedUp];
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if ([notif.object[@"eventType"] isEqual: @"left"]) {
|
|
884
|
+
[self swipedLeft];
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
if ([notif.object[@"eventType"] isEqual: @"right"]) {
|
|
889
|
+
[self swipedRight];
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
895
|
+
{
|
|
896
|
+
BOOL isHorizontal = _scrollView.contentSize.width > self.frame.size.width;
|
|
897
|
+
// Keep focus inside the scroll view till the end of the content
|
|
898
|
+
if (isHorizontal) {
|
|
899
|
+
if ((context.focusHeading == UIFocusHeadingLeft && self.scrollView.contentOffset.x > 0)
|
|
900
|
+
|| (context.focusHeading == UIFocusHeadingRight && self.scrollView.contentOffset.x < self.scrollView.contentSize.width - self.scrollView.visibleSize.width)
|
|
901
|
+
) {
|
|
902
|
+
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
if ((context.focusHeading == UIFocusHeadingUp && self.scrollView.contentOffset.y > 0)
|
|
906
|
+
|| (context.focusHeading == UIFocusHeadingDown && self.scrollView.contentOffset.y < self.scrollView.contentSize.height - self.scrollView.visibleSize.height)
|
|
907
|
+
) {
|
|
908
|
+
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return [super shouldUpdateFocusInContext:context];
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
- (void)sendFocusNotification
|
|
916
|
+
{
|
|
917
|
+
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTTVNavigationEventNotification"
|
|
918
|
+
object:@{ @"eventType": @"focus", @"tag": @([self tag]) }];
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
- (void)sendBlurNotification
|
|
922
|
+
{
|
|
923
|
+
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTTVNavigationEventNotification"
|
|
924
|
+
object:@{ @"eventType": @"blur", @"tag": @([self tag]) }];
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
- (NSInteger)swipeVerticalInterval
|
|
928
|
+
{
|
|
929
|
+
RCTEnhancedScrollView *scrollView = (RCTEnhancedScrollView *)_scrollView;
|
|
930
|
+
if (scrollView.snapToInterval) {
|
|
931
|
+
return scrollView.snapToInterval;
|
|
932
|
+
}
|
|
933
|
+
return scrollView.visibleSize.height / 2;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
- (NSInteger)swipeHorizontalInterval
|
|
937
|
+
{
|
|
938
|
+
RCTEnhancedScrollView *scrollView = (RCTEnhancedScrollView *)_scrollView;
|
|
939
|
+
if (scrollView.snapToInterval) {
|
|
940
|
+
return scrollView.snapToInterval;
|
|
941
|
+
}
|
|
942
|
+
return scrollView.visibleSize.width / 2;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
- (NSTimeInterval)swipeDuration
|
|
946
|
+
{
|
|
947
|
+
auto pressDuration = _props->tvParallaxProperties.pressDuration;
|
|
948
|
+
auto duration = pressDuration.has_value() ? pressDuration.value() : TV_DEFAULT_SWIPE_DURATION;
|
|
949
|
+
if (duration == 0.0) {
|
|
950
|
+
duration = TV_DEFAULT_SWIPE_DURATION;
|
|
951
|
+
}
|
|
952
|
+
return duration;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
- (void)swipeVerticalScrollToOffset:(CGFloat)yOffset
|
|
956
|
+
{
|
|
957
|
+
_blockFirstTouch = NO;
|
|
958
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
959
|
+
CGFloat limitedOffset = yOffset;
|
|
960
|
+
limitedOffset = MAX(limitedOffset, 0.0);
|
|
961
|
+
limitedOffset = MIN(limitedOffset, self.scrollView.contentSize.height - self.scrollView.visibleSize.height);
|
|
962
|
+
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
963
|
+
self.scrollView.contentOffset =
|
|
964
|
+
CGPointMake(self.scrollView.contentOffset.x, limitedOffset);
|
|
965
|
+
}];
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
- (void)swipeHorizontalScrollToOffset:(CGFloat)xOffset
|
|
970
|
+
{
|
|
971
|
+
_blockFirstTouch = NO;
|
|
972
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
973
|
+
CGFloat limitedOffset = xOffset;
|
|
974
|
+
limitedOffset = MAX(limitedOffset, 0.0);
|
|
975
|
+
limitedOffset = MIN(limitedOffset, self.scrollView.contentSize.width - self.scrollView.visibleSize.width);
|
|
976
|
+
[UIView animateWithDuration:[self swipeDuration] animations:^{
|
|
977
|
+
self.scrollView.contentOffset =
|
|
978
|
+
CGPointMake(limitedOffset, self.scrollView.contentOffset.y);
|
|
979
|
+
}];
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
- (void)swipedUp
|
|
984
|
+
{
|
|
985
|
+
CGFloat newOffset = self.scrollView.contentOffset.y - [self swipeVerticalInterval];
|
|
986
|
+
NSLog(@"Swiped up to %f", newOffset);
|
|
987
|
+
[self swipeVerticalScrollToOffset:newOffset];
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
- (void)swipedDown
|
|
991
|
+
{
|
|
992
|
+
CGFloat newOffset = self.scrollView.contentOffset.y + [self swipeVerticalInterval];
|
|
993
|
+
NSLog(@"Swiped down to %f", newOffset);
|
|
994
|
+
[self swipeVerticalScrollToOffset:newOffset];
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
- (void)swipedLeft
|
|
998
|
+
{
|
|
999
|
+
CGFloat newOffset = self.scrollView.contentOffset.x - [self swipeHorizontalInterval];
|
|
1000
|
+
NSLog(@"Swiped left to %f", newOffset);
|
|
1001
|
+
[self swipeHorizontalScrollToOffset:newOffset];
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
- (void)swipedRight
|
|
1005
|
+
{
|
|
1006
|
+
CGFloat newOffset = self.scrollView.contentOffset.x + [self swipeHorizontalInterval];
|
|
1007
|
+
NSLog(@"Swiped right to %f", newOffset);
|
|
1008
|
+
[self swipeHorizontalScrollToOffset:newOffset];
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
- (void)addSwipeGestureRecognizers
|
|
1012
|
+
{
|
|
1013
|
+
[self addSwipeGestureRecognizerWithSelector:@selector(swipedUp) direction:UISwipeGestureRecognizerDirectionUp name:RCTTVRemoteEventSwipeUp];
|
|
1014
|
+
[self addSwipeGestureRecognizerWithSelector:@selector(swipedDown) direction:UISwipeGestureRecognizerDirectionDown name:RCTTVRemoteEventSwipeDown];
|
|
1015
|
+
[self addSwipeGestureRecognizerWithSelector:@selector(swipedLeft) direction:UISwipeGestureRecognizerDirectionLeft name:RCTTVRemoteEventSwipeLeft];
|
|
1016
|
+
[self addSwipeGestureRecognizerWithSelector:@selector(swipedRight) direction:UISwipeGestureRecognizerDirectionRight name:RCTTVRemoteEventSwipeRight];
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
- (void)addSwipeGestureRecognizerWithSelector:(nonnull SEL)selector
|
|
1020
|
+
direction:(UISwipeGestureRecognizerDirection)direction
|
|
1021
|
+
name:(NSString *)name
|
|
1022
|
+
{
|
|
1023
|
+
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:selector];
|
|
1024
|
+
recognizer.direction = direction;
|
|
1025
|
+
|
|
1026
|
+
_tvRemoteGestureRecognizers[name] = recognizer;
|
|
1027
|
+
[self.scrollView addGestureRecognizer:recognizer];
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
- (void)removeSwipeGestureRecognizers
|
|
1031
|
+
{
|
|
1032
|
+
NSArray *names = [self->_tvRemoteGestureRecognizers allKeys];
|
|
1033
|
+
for (NSString *name in names) {
|
|
1034
|
+
UIGestureRecognizer *r = self->_tvRemoteGestureRecognizers[name];
|
|
1035
|
+
[self.scrollView removeGestureRecognizer:r];
|
|
1036
|
+
[self->_tvRemoteGestureRecognizers removeObjectForKey:name];
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
#endif // TARGET_OS_TV
|
|
1040
|
+
|
|
795
1041
|
@end
|
|
796
1042
|
|
|
797
1043
|
Class<RCTComponentViewProtocol> RCTScrollViewCls(void)
|
|
@@ -45,7 +45,7 @@ using namespace facebook::react;
|
|
|
45
45
|
|
|
46
46
|
@implementation RCTViewComponentView {
|
|
47
47
|
UIColor *_backgroundColor;
|
|
48
|
-
CALayer *_borderLayer;
|
|
48
|
+
__weak CALayer *_borderLayer;
|
|
49
49
|
BOOL _needsInvalidateLayer;
|
|
50
50
|
BOOL _isJSResponder;
|
|
51
51
|
BOOL _removeClippedSubviews;
|
|
@@ -433,6 +433,9 @@ using namespace facebook::react;
|
|
|
433
433
|
//
|
|
434
434
|
- (void)enableDirectionalFocusGuides
|
|
435
435
|
{
|
|
436
|
+
if (!self.isFocused) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
436
439
|
if (self->_nextFocusUp != nil) {
|
|
437
440
|
if (self.focusGuideUp == nil) {
|
|
438
441
|
self.focusGuideUp = [UIFocusGuide new];
|
|
@@ -942,6 +945,7 @@ using namespace facebook::react;
|
|
|
942
945
|
if (newViewProps.nextFocusUp.has_value()) {
|
|
943
946
|
UIView *rootView = [self containingRootView];
|
|
944
947
|
_nextFocusUp = [rootView viewWithTag:newViewProps.nextFocusUp.value()];
|
|
948
|
+
[self enableDirectionalFocusGuides];
|
|
945
949
|
} else {
|
|
946
950
|
_nextFocusUp = nil;
|
|
947
951
|
}
|
|
@@ -951,6 +955,7 @@ using namespace facebook::react;
|
|
|
951
955
|
if (newViewProps.nextFocusDown.has_value()) {
|
|
952
956
|
UIView *rootView = [self containingRootView];
|
|
953
957
|
_nextFocusDown = [rootView viewWithTag:newViewProps.nextFocusDown.value()];
|
|
958
|
+
[self enableDirectionalFocusGuides];
|
|
954
959
|
} else {
|
|
955
960
|
_nextFocusDown = nil;
|
|
956
961
|
}
|
|
@@ -960,6 +965,7 @@ using namespace facebook::react;
|
|
|
960
965
|
if (newViewProps.nextFocusLeft.has_value()) {
|
|
961
966
|
UIView *rootView = [self containingRootView];
|
|
962
967
|
_nextFocusLeft = [rootView viewWithTag:newViewProps.nextFocusLeft.value()];
|
|
968
|
+
[self enableDirectionalFocusGuides];
|
|
963
969
|
} else {
|
|
964
970
|
_nextFocusLeft = nil;
|
|
965
971
|
}
|
|
@@ -969,6 +975,7 @@ using namespace facebook::react;
|
|
|
969
975
|
if (newViewProps.nextFocusRight.has_value()) {
|
|
970
976
|
UIView *rootView = [self containingRootView];
|
|
971
977
|
_nextFocusRight = [rootView viewWithTag:newViewProps.nextFocusRight.value()];
|
|
978
|
+
[self enableDirectionalFocusGuides];
|
|
972
979
|
} else {
|
|
973
980
|
_nextFocusRight = nil;
|
|
974
981
|
}
|
|
@@ -1013,9 +1020,7 @@ using namespace facebook::react;
|
|
|
1013
1020
|
_layoutMetrics = layoutMetrics;
|
|
1014
1021
|
_needsInvalidateLayer = YES;
|
|
1015
1022
|
|
|
1016
|
-
|
|
1017
|
-
_borderLayer.frame = self.layer.bounds;
|
|
1018
|
-
}
|
|
1023
|
+
_borderLayer.frame = self.layer.bounds;
|
|
1019
1024
|
|
|
1020
1025
|
if (_contentView) {
|
|
1021
1026
|
_contentView.frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
|
@@ -1232,10 +1237,7 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
|
|
|
1232
1237
|
|
|
1233
1238
|
if (useCoreAnimationBorderRendering) {
|
|
1234
1239
|
layer.mask = nil;
|
|
1235
|
-
|
|
1236
|
-
[_borderLayer removeFromSuperlayer];
|
|
1237
|
-
_borderLayer = nil;
|
|
1238
|
-
}
|
|
1240
|
+
[_borderLayer removeFromSuperlayer];
|
|
1239
1241
|
|
|
1240
1242
|
layer.borderWidth = (CGFloat)borderMetrics.borderWidths.left;
|
|
1241
1243
|
CGColorRef borderColor = RCTCreateCGColorRefFromSharedColor(borderMetrics.borderColors.left);
|
|
@@ -1248,11 +1250,12 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
|
|
|
1248
1250
|
layer.backgroundColor = _backgroundColor.CGColor;
|
|
1249
1251
|
} else {
|
|
1250
1252
|
if (!_borderLayer) {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
[layer addSublayer:
|
|
1253
|
+
CALayer *borderLayer = [CALayer new];
|
|
1254
|
+
borderLayer.zPosition = -1024.0f;
|
|
1255
|
+
borderLayer.frame = layer.bounds;
|
|
1256
|
+
borderLayer.magnificationFilter = kCAFilterNearest;
|
|
1257
|
+
[layer addSublayer:borderLayer];
|
|
1258
|
+
_borderLayer = borderLayer;
|
|
1256
1259
|
}
|
|
1257
1260
|
|
|
1258
1261
|
layer.backgroundColor = nil;
|
|
@@ -1293,6 +1296,10 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
|
|
|
1293
1296
|
}
|
|
1294
1297
|
}
|
|
1295
1298
|
|
|
1299
|
+
// If mutations are applied inside of Animation block, it may cause _borderLayer to be animated.
|
|
1300
|
+
// To stop that, imperatively remove all animations from _borderLayer.
|
|
1301
|
+
[_borderLayer removeAllAnimations];
|
|
1302
|
+
|
|
1296
1303
|
// Stage 2.5. Custom Clipping Mask
|
|
1297
1304
|
CAShapeLayer *maskLayer = nil;
|
|
1298
1305
|
CGFloat cornerRadius = 0;
|
|
@@ -20,6 +20,7 @@ folly_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_C
|
|
|
20
20
|
folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32'
|
|
21
21
|
folly_version = '2022.05.16.00'
|
|
22
22
|
boost_compiler_flags = '-Wno-documentation'
|
|
23
|
+
new_arch_flags = ENV['RCT_NEW_ARCH_ENABLED'] == '1' ? ' -DRCT_NEW_ARCH_ENABLED=1' : ''
|
|
23
24
|
|
|
24
25
|
header_search_paths = [
|
|
25
26
|
"\"$(PODS_TARGET_SRCROOT)/ReactCommon\"",
|
|
@@ -56,13 +57,13 @@ Pod::Spec.new do |s|
|
|
|
56
57
|
"Fabric/**/RCTSurfacePointerHandler.mm"
|
|
57
58
|
s.ios.exclude_files = "Fabric/**/RCTSurfaceTouchHandlerTV.mm",
|
|
58
59
|
"Fabric/**/RCTSurfacePointerHandlerTV.mm"
|
|
59
|
-
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
|
|
60
|
+
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags + new_arch_flags
|
|
60
61
|
s.header_dir = header_dir
|
|
61
62
|
s.module_name = module_name
|
|
62
63
|
s.framework = ["JavaScriptCore", "MobileCoreServices"]
|
|
63
64
|
s.pod_target_xcconfig = {
|
|
64
65
|
"HEADER_SEARCH_PATHS" => header_search_paths,
|
|
65
|
-
"OTHER_CFLAGS" => "$(inherited) -DRN_FABRIC_ENABLED" + " " + folly_flags,
|
|
66
|
+
"OTHER_CFLAGS" => "$(inherited) -DRN_FABRIC_ENABLED" + " " + folly_flags + new_arch_flags,
|
|
66
67
|
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20"
|
|
67
68
|
}.merge!(ENV['USE_FRAMEWORKS'] != nil ? {
|
|
68
69
|
"PUBLIC_HEADERS_FOLDER_PATH" => "#{module_name}.framework/Headers/#{header_dir}"
|
package/React/Views/RCTTVView.m
CHANGED
|
@@ -336,6 +336,9 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
336
336
|
//
|
|
337
337
|
- (void)enableDirectionalFocusGuides
|
|
338
338
|
{
|
|
339
|
+
if (!self.isFocused) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
339
342
|
if (self->_nextFocusUp != nil) {
|
|
340
343
|
if (self.focusGuideUp == nil) {
|
|
341
344
|
self.focusGuideUp = [UIFocusGuide new];
|
|
@@ -455,18 +458,22 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
455
458
|
|
|
456
459
|
- (void)setNextFocusUp:(NSNumber *)nextFocusUp {
|
|
457
460
|
self->_nextFocusUp = [self getViewById: nextFocusUp];
|
|
461
|
+
[self enableDirectionalFocusGuides];
|
|
458
462
|
}
|
|
459
463
|
|
|
460
464
|
- (void)setNextFocusDown:(NSNumber *)nextFocusDown {
|
|
461
465
|
self->_nextFocusDown = [self getViewById: nextFocusDown];
|
|
466
|
+
[self enableDirectionalFocusGuides];
|
|
462
467
|
}
|
|
463
468
|
|
|
464
469
|
- (void)setNextFocusLeft:(NSNumber *)nextFocusLeft {
|
|
465
470
|
self->_nextFocusLeft = [self getViewById: nextFocusLeft];
|
|
471
|
+
[self enableDirectionalFocusGuides];
|
|
466
472
|
}
|
|
467
473
|
|
|
468
474
|
- (void)setNextFocusRight:(NSNumber *)nextFocusRight {
|
|
469
475
|
self->_nextFocusRight = [self getViewById: nextFocusRight];
|
|
476
|
+
[self enableDirectionalFocusGuides];
|
|
470
477
|
}
|
|
471
478
|
|
|
472
479
|
- (void)setPreferredFocus:(BOOL)hasTVPreferredFocus
|
|
@@ -17,8 +17,8 @@ namespace facebook::react {
|
|
|
17
17
|
constexpr struct {
|
|
18
18
|
int32_t Major = 0;
|
|
19
19
|
int32_t Minor = 73;
|
|
20
|
-
int32_t Patch =
|
|
21
|
-
std::string_view Prerelease = "
|
|
20
|
+
int32_t Patch = 6;
|
|
21
|
+
std::string_view Prerelease = "0";
|
|
22
22
|
} ReactNativeVersion;
|
|
23
23
|
|
|
24
24
|
} // namespace facebook::react
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tvos",
|
|
3
|
-
"version": "0.73.
|
|
3
|
+
"version": "0.73.6-0",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -94,16 +94,16 @@
|
|
|
94
94
|
},
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"@jest/create-cache-key-function": "^29.6.3",
|
|
97
|
-
"@react-native-community/cli": "12.3.
|
|
98
|
-
"@react-native-community/cli-platform-android": "12.3.
|
|
99
|
-
"@react-native-community/cli-platform-ios": "12.3.
|
|
97
|
+
"@react-native-community/cli": "12.3.6",
|
|
98
|
+
"@react-native-community/cli-platform-android": "12.3.6",
|
|
99
|
+
"@react-native-community/cli-platform-ios": "12.3.6",
|
|
100
100
|
"@react-native/assets-registry": "0.73.1",
|
|
101
|
-
"@react-native/community-cli-plugin": "0.73.
|
|
101
|
+
"@react-native/community-cli-plugin": "0.73.17",
|
|
102
102
|
"@react-native/codegen": "0.73.3",
|
|
103
103
|
"@react-native/gradle-plugin": "0.73.4",
|
|
104
104
|
"@react-native/js-polyfills": "0.73.1",
|
|
105
105
|
"@react-native/normalize-colors": "0.73.2",
|
|
106
|
-
"@react-native-tvos/virtualized-lists": "0.73.
|
|
106
|
+
"@react-native-tvos/virtualized-lists": "0.73.6-0",
|
|
107
107
|
"abort-controller": "^3.0.0",
|
|
108
108
|
"anser": "^1.4.9",
|
|
109
109
|
"ansi-regex": "^5.0.0",
|
|
@@ -151,6 +151,6 @@
|
|
|
151
151
|
]
|
|
152
152
|
},
|
|
153
153
|
"devDependencies": {
|
|
154
|
-
"react-native-core": "npm:react-native@0.73.
|
|
154
|
+
"react-native-core": "npm:react-native@0.73.6"
|
|
155
155
|
}
|
|
156
156
|
}
|
|
@@ -104,6 +104,10 @@ class NewArchitectureHelper
|
|
|
104
104
|
current_config = hash["pod_target_xcconfig"] != nil ? hash["pod_target_xcconfig"] : {}
|
|
105
105
|
current_headers = current_config["HEADER_SEARCH_PATHS"] != nil ? current_config["HEADER_SEARCH_PATHS"] : ""
|
|
106
106
|
|
|
107
|
+
flags_to_add = new_arch_enabled ?
|
|
108
|
+
"#{@@folly_compiler_flags} -DRCT_NEW_ARCH_ENABLED=1" :
|
|
109
|
+
"#{@@folly_compiler_flags}"
|
|
110
|
+
|
|
107
111
|
header_search_paths = ["\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\""]
|
|
108
112
|
if ENV['USE_FRAMEWORKS']
|
|
109
113
|
header_search_paths << "\"$(PODS_ROOT)/DoubleConversion\""
|
|
@@ -123,7 +127,7 @@ class NewArchitectureHelper
|
|
|
123
127
|
}
|
|
124
128
|
end
|
|
125
129
|
header_search_paths_string = header_search_paths.join(" ")
|
|
126
|
-
spec.compiler_flags = compiler_flags.empty? ?
|
|
130
|
+
spec.compiler_flags = compiler_flags.empty? ? "$(inherited) #{flags_to_add}" : "$(inherited) #{compiler_flags} #{flags_to_add}"
|
|
127
131
|
current_config["HEADER_SEARCH_PATHS"] = current_headers.empty? ?
|
|
128
132
|
header_search_paths_string :
|
|
129
133
|
"#{current_headers} #{header_search_paths_string}"
|
|
@@ -86,6 +86,27 @@ class ReactNativePodsUtils
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
def self.fix_flipper_for_xcode_15_3(installer)
|
|
90
|
+
installer.pods_project.targets.each do |target|
|
|
91
|
+
if target.name == 'Flipper'
|
|
92
|
+
file_path = 'Pods/Flipper/xplat/Flipper/FlipperTransportTypes.h'
|
|
93
|
+
if !File.exist?(file_path)
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
contents = File.read(file_path)
|
|
98
|
+
if contents.include?('#include <functional>')
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
mod_content = contents.gsub("#pragma once", "#pragma once\n#include <functional>")
|
|
102
|
+
File.chmod(0755, file_path)
|
|
103
|
+
File.open(file_path, 'w') do |file|
|
|
104
|
+
file.puts(mod_content)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
89
110
|
def self.set_use_hermes_build_setting(installer, hermes_enabled)
|
|
90
111
|
Pod::UI.puts("Setting USE_HERMES build settings")
|
|
91
112
|
projects = self.extract_projects(installer)
|
|
@@ -32,7 +32,13 @@ const REACT_NATIVE_PACKAGE_ROOT_FOLDER = path.join(__dirname, '..', '..');
|
|
|
32
32
|
|
|
33
33
|
const CODEGEN_DEPENDENCY_NAME = '@react-native/codegen';
|
|
34
34
|
const CODEGEN_REPO_PATH = `${REACT_NATIVE_REPOSITORY_ROOT}/packages/react-native-codegen`;
|
|
35
|
-
|
|
35
|
+
// This is a change for 0.73-stable only since this piece of code was replaced:
|
|
36
|
+
// https://github.com/facebook/react-native/commit/9071a3a0b0e11ad711927651bcb2412f553b6fe9
|
|
37
|
+
const CODEGEN_NPM_PATH = path.dirname(
|
|
38
|
+
require.resolve(path.join(CODEGEN_DEPENDENCY_NAME, 'package.json'), {
|
|
39
|
+
paths: [REACT_NATIVE_PACKAGE_ROOT_FOLDER],
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
36
42
|
const CORE_LIBRARIES_WITH_OUTPUT_FOLDER = {
|
|
37
43
|
rncore: path.join(REACT_NATIVE_PACKAGE_ROOT_FOLDER, 'ReactCommon'),
|
|
38
44
|
FBReactNativeSpec: null,
|
|
@@ -189,33 +195,34 @@ function handleThirdPartyLibraries(
|
|
|
189
195
|
codegenConfigKey,
|
|
190
196
|
) {
|
|
191
197
|
// Determine which of these are codegen-enabled libraries
|
|
192
|
-
const configDir =
|
|
193
|
-
baseCodegenConfigFileDir ||
|
|
194
|
-
path.join(REACT_NATIVE_PACKAGE_ROOT_FOLDER, '..');
|
|
198
|
+
const configDir = baseCodegenConfigFileDir || process.cwd();
|
|
195
199
|
console.log(
|
|
196
200
|
`\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${configDir}`,
|
|
197
201
|
);
|
|
198
202
|
|
|
199
203
|
// Handle third-party libraries
|
|
204
|
+
const resolveOptions = {paths: [configDir]};
|
|
200
205
|
Object.keys(dependencies).forEach(dependency => {
|
|
201
206
|
if (dependency === REACT_NATIVE_DEPENDENCY_NAME) {
|
|
202
207
|
// react-native should already be added.
|
|
203
208
|
return;
|
|
204
209
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const configFilePath = require.resolve(
|
|
213
|
+
`${dependency}/${codegenConfigFilename}`,
|
|
214
|
+
resolveOptions,
|
|
215
|
+
);
|
|
211
216
|
const configFile = JSON.parse(fs.readFileSync(configFilePath));
|
|
212
217
|
extractLibrariesFromJSON(
|
|
213
218
|
configFile,
|
|
214
219
|
libraries,
|
|
215
220
|
codegenConfigKey,
|
|
216
221
|
dependency,
|
|
217
|
-
|
|
222
|
+
path.dirname(configFilePath),
|
|
218
223
|
);
|
|
224
|
+
} catch (_) {
|
|
225
|
+
// ignore
|
|
219
226
|
}
|
|
220
227
|
});
|
|
221
228
|
}
|
|
@@ -313,6 +313,7 @@ def react_native_post_install(
|
|
|
313
313
|
ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: fabric_enabled)
|
|
314
314
|
ReactNativePodsUtils.apply_xcode_15_patch(installer)
|
|
315
315
|
ReactNativePodsUtils.updateOSDeploymentTarget(installer)
|
|
316
|
+
ReactNativePodsUtils.fix_flipper_for_xcode_15_3(installer)
|
|
316
317
|
|
|
317
318
|
NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer)
|
|
318
319
|
NewArchitectureHelper.modify_flags_for_new_architecture(installer, NewArchitectureHelper.new_arch_enabled)
|
package/sdks/.hermesversion
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
hermes-2024-01-
|
|
1
|
+
hermes-2024-03-01-RNv0.73.5-5e3ba8a5ff73efc46f4570492176b0605de77ed6
|
|
@@ -7,6 +7,7 @@ require 'net/http'
|
|
|
7
7
|
require 'rexml/document'
|
|
8
8
|
|
|
9
9
|
HERMES_GITHUB_URL = "https://github.com/facebook/hermes.git"
|
|
10
|
+
ENV_BUILD_FROM_SOURCE = "RCT_BUILD_HERMES_FROM_SOURCE"
|
|
10
11
|
|
|
11
12
|
module HermesEngineSourceType
|
|
12
13
|
LOCAL_PREBUILT_TARBALL = :local_prebuilt_tarball
|
|
@@ -30,7 +31,7 @@ end
|
|
|
30
31
|
# - To use a specific tarball, install the dependencies with:
|
|
31
32
|
# `HERMES_ENGINE_TARBALL_PATH=<path_to_tarball> bundle exec pod install`
|
|
32
33
|
# - To force a build from source, install the dependencies with:
|
|
33
|
-
# `
|
|
34
|
+
# `RCT_BUILD_HERMES_FROM_SOURCE=true bundle exec pod install`
|
|
34
35
|
# If none of the two are provided, Cocoapods will check whether there is a tarball for the current version
|
|
35
36
|
# (either release or nightly). If not, it will fall back to building from source (the latest commit on main).
|
|
36
37
|
#
|
|
@@ -85,11 +86,11 @@ def hermes_commit_envvar_defined()
|
|
|
85
86
|
end
|
|
86
87
|
|
|
87
88
|
def force_build_from_tag(react_native_path)
|
|
88
|
-
return ENV[
|
|
89
|
+
return ENV[ENV_BUILD_FROM_SOURCE] === 'true' && File.exist?(hermestag_file(react_native_path))
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
def force_build_from_main(react_native_path)
|
|
92
|
-
return ENV[
|
|
93
|
+
return ENV[ENV_BUILD_FROM_SOURCE] === 'true' && !File.exist?(hermestag_file(react_native_path))
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
def release_artifact_exists(version)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/template/package.json
CHANGED