react-native-tvos 0.76.0-0rc1 → 0.76.0-0rc3
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/RCTAppDelegate.h +3 -0
- package/Libraries/AppDelegate/RCTAppDelegate.mm +21 -7
- package/Libraries/Blob/RCTFileReaderModule.mm +4 -3
- package/Libraries/Components/Keyboard/KeyboardAvoidingView.js +17 -0
- package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +1 -0
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/NativeComponent/TVViewConfig.js +4 -0
- package/React/Base/RCTVersion.m +1 -1
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm +22 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +23 -0
- package/React/Views/ScrollView/RCTScrollView.m +20 -0
- package/ReactAndroid/api/ReactAndroid.api +9 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/publish.gradle +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java +5 -0
- package/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java +0 -3
- package/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java +37 -4
- package/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DevMenuModule.kt +46 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/CoreReactPackage.java +5 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +18 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/cli.js +23 -5
- package/package.json +12 -10
- package/scripts/cocoapods/utils.rb +10 -2
- package/scripts/react-native-xcode.sh +2 -0
- package/sdks/hermes-engine/hermes-engine.podspec +1 -1
- package/sdks/hermes-engine/utils/build-ios-framework.sh +21 -4
- 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
|
@@ -64,6 +64,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
64
64
|
@property (nonatomic, strong, nullable) NSDictionary *initialProps;
|
|
65
65
|
@property (nonatomic, strong, nonnull) RCTRootViewFactory *rootViewFactory;
|
|
66
66
|
|
|
67
|
+
/// If `automaticallyLoadReactNativeWindow` is set to `true`, the React Native window will be loaded automatically.
|
|
68
|
+
@property (nonatomic, assign) BOOL automaticallyLoadReactNativeWindow;
|
|
69
|
+
|
|
67
70
|
@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter;
|
|
68
71
|
|
|
69
72
|
/**
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#import <React/RCTSurfacePresenterBridgeAdapter.h>
|
|
13
13
|
#import <React/RCTUtils.h>
|
|
14
14
|
#import <ReactCommon/RCTHost.h>
|
|
15
|
+
#include <UIKit/UIKit.h>
|
|
15
16
|
#import <objc/runtime.h>
|
|
16
17
|
#import <react/featureflags/ReactNativeFeatureFlags.h>
|
|
17
18
|
#import <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
|
|
@@ -38,6 +39,14 @@
|
|
|
38
39
|
|
|
39
40
|
@implementation RCTAppDelegate
|
|
40
41
|
|
|
42
|
+
- (instancetype)init
|
|
43
|
+
{
|
|
44
|
+
if (self = [super init]) {
|
|
45
|
+
_automaticallyLoadReactNativeWindow = YES;
|
|
46
|
+
}
|
|
47
|
+
return self;
|
|
48
|
+
}
|
|
49
|
+
|
|
41
50
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
42
51
|
{
|
|
43
52
|
[self _setUpFeatureFlags];
|
|
@@ -47,15 +56,23 @@
|
|
|
47
56
|
RCTAppSetupPrepareApp(application, self.turboModuleEnabled);
|
|
48
57
|
|
|
49
58
|
self.rootViewFactory = [self createRCTRootViewFactory];
|
|
59
|
+
if (self.newArchEnabled || self.fabricEnabled) {
|
|
60
|
+
[RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self;
|
|
61
|
+
}
|
|
50
62
|
|
|
63
|
+
if (self.automaticallyLoadReactNativeWindow) {
|
|
64
|
+
[self loadReactNativeWindow:launchOptions];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return YES;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
- (void)loadReactNativeWindow:(NSDictionary *)launchOptions
|
|
71
|
+
{
|
|
51
72
|
UIView *rootView = [self.rootViewFactory viewWithModuleName:self.moduleName
|
|
52
73
|
initialProperties:self.initialProps
|
|
53
74
|
launchOptions:launchOptions];
|
|
54
75
|
|
|
55
|
-
if (self.newArchEnabled || self.fabricEnabled) {
|
|
56
|
-
[RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
76
|
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
60
77
|
UIViewController *rootViewController = [self createRootViewController];
|
|
61
78
|
[self setRootView:rootView toRootViewController:rootViewController];
|
|
@@ -68,10 +85,7 @@
|
|
|
68
85
|
rootView.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
|
|
69
86
|
}
|
|
70
87
|
#endif
|
|
71
|
-
self.window.windowScene.delegate = self;
|
|
72
88
|
[self.window makeKeyAndVisible];
|
|
73
|
-
|
|
74
|
-
return YES;
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
- (void)applicationDidEnterBackground:(UIApplication *)application
|
|
@@ -72,9 +72,10 @@ RCT_EXPORT_METHOD(readAsDataURL
|
|
|
72
72
|
nil);
|
|
73
73
|
} else {
|
|
74
74
|
NSString *type = [RCTConvert NSString:blob[@"type"]];
|
|
75
|
-
NSString *text = [NSString
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
NSString *text = [NSString
|
|
76
|
+
stringWithFormat:@"data:%@;base64,%@",
|
|
77
|
+
![type isEqual:[NSNull null]] && [type length] > 0 ? type : @"application/octet-stream",
|
|
78
|
+
[data base64EncodedStringWithOptions:0]];
|
|
78
79
|
|
|
79
80
|
resolve(text);
|
|
80
81
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
|
|
12
|
+
import type {DimensionsPayload} from '../../Utilities/NativeDeviceInfo';
|
|
12
13
|
import type {
|
|
13
14
|
ViewLayout,
|
|
14
15
|
ViewLayoutEvent,
|
|
@@ -18,6 +19,7 @@ import type {KeyboardEvent, KeyboardMetrics} from './Keyboard';
|
|
|
18
19
|
|
|
19
20
|
import LayoutAnimation from '../../LayoutAnimation/LayoutAnimation';
|
|
20
21
|
import StyleSheet from '../../StyleSheet/StyleSheet';
|
|
22
|
+
import Dimensions from '../../Utilities/Dimensions';
|
|
21
23
|
import Platform from '../../Utilities/Platform';
|
|
22
24
|
import {type EventSubscription} from '../../vendor/emitter/EventEmitter';
|
|
23
25
|
import AccessibilityInfo from '../AccessibilityInfo/AccessibilityInfo';
|
|
@@ -66,6 +68,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
|
|
66
68
|
viewRef: {current: React.ElementRef<typeof View> | null, ...};
|
|
67
69
|
_initialFrameHeight: number = 0;
|
|
68
70
|
_bottom: number = 0;
|
|
71
|
+
_windowWidth: number = Dimensions.get('window').width;
|
|
69
72
|
|
|
70
73
|
constructor(props: Props) {
|
|
71
74
|
super(props);
|
|
@@ -130,6 +133,10 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
|
|
130
133
|
}
|
|
131
134
|
};
|
|
132
135
|
|
|
136
|
+
_onDimensionsChange = ({window}: DimensionsPayload) => {
|
|
137
|
+
this._windowWidth = window?.width ?? 0;
|
|
138
|
+
};
|
|
139
|
+
|
|
133
140
|
// Avoid unnecessary renders if the KeyboardAvoidingView is disabled.
|
|
134
141
|
_setBottom = (value: number) => {
|
|
135
142
|
const enabled = this.props.enabled ?? true;
|
|
@@ -145,6 +152,15 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
|
|
145
152
|
return;
|
|
146
153
|
}
|
|
147
154
|
|
|
155
|
+
if (
|
|
156
|
+
Platform.OS === 'ios' &&
|
|
157
|
+
this._windowWidth !== this._keyboardEvent.endCoordinates.width
|
|
158
|
+
) {
|
|
159
|
+
// The keyboard is not the standard bottom-of-the-screen keyboard. For example, floating keyboard on iPadOS.
|
|
160
|
+
this._setBottom(0);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
148
164
|
const {duration, easing, endCoordinates} = this._keyboardEvent;
|
|
149
165
|
const height = await this._relativeKeyboardHeight(endCoordinates);
|
|
150
166
|
|
|
@@ -178,6 +194,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
|
|
178
194
|
if (Platform.OS === 'ios') {
|
|
179
195
|
this._subscriptions = [
|
|
180
196
|
Keyboard.addListener('keyboardWillChangeFrame', this._onKeyboardChange),
|
|
197
|
+
Dimensions.addEventListener('change', this._onDimensionsChange),
|
|
181
198
|
];
|
|
182
199
|
} else {
|
|
183
200
|
this._subscriptions = [
|
package/React/Base/RCTVersion.m
CHANGED
package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm
CHANGED
|
@@ -60,6 +60,11 @@ using namespace facebook::react;
|
|
|
60
60
|
[_refreshControl addTarget:self
|
|
61
61
|
action:@selector(handleUIControlEventValueChanged)
|
|
62
62
|
forControlEvents:UIControlEventValueChanged];
|
|
63
|
+
|
|
64
|
+
const auto &concreteProps = static_cast<const PullToRefreshViewProps &>(*_props);
|
|
65
|
+
|
|
66
|
+
_refreshControl.tintColor = RCTUIColorFromSharedColor(concreteProps.tintColor);
|
|
67
|
+
[self _updateProgressViewOffset:concreteProps.progressViewOffset];
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
#pragma mark - RCTComponentViewProtocol
|
|
@@ -89,6 +94,14 @@ using namespace facebook::react;
|
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
if (newConcreteProps.tintColor != oldConcreteProps.tintColor) {
|
|
98
|
+
_refreshControl.tintColor = RCTUIColorFromSharedColor(newConcreteProps.tintColor);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (newConcreteProps.progressViewOffset != oldConcreteProps.progressViewOffset) {
|
|
102
|
+
[self _updateProgressViewOffset:newConcreteProps.progressViewOffset];
|
|
103
|
+
}
|
|
104
|
+
|
|
92
105
|
BOOL needsUpdateTitle = NO;
|
|
93
106
|
|
|
94
107
|
if (newConcreteProps.title != oldConcreteProps.title) {
|
|
@@ -113,6 +126,15 @@ using namespace facebook::react;
|
|
|
113
126
|
static_cast<const PullToRefreshViewEventEmitter &>(*_eventEmitter).onRefresh({});
|
|
114
127
|
}
|
|
115
128
|
|
|
129
|
+
- (void)_updateProgressViewOffset:(Float)progressViewOffset
|
|
130
|
+
{
|
|
131
|
+
_refreshControl.bounds = CGRectMake(
|
|
132
|
+
_refreshControl.bounds.origin.x,
|
|
133
|
+
-progressViewOffset,
|
|
134
|
+
_refreshControl.bounds.size.width,
|
|
135
|
+
_refreshControl.bounds.size.height);
|
|
136
|
+
}
|
|
137
|
+
|
|
116
138
|
- (void)_updateTitle
|
|
117
139
|
{
|
|
118
140
|
const auto &concreteProps = static_cast<const PullToRefreshViewProps &>(*_props);
|
|
@@ -740,6 +740,29 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
|
|
740
740
|
[self _handleFinishedScrolling:scrollView];
|
|
741
741
|
}
|
|
742
742
|
|
|
743
|
+
- (void)didMoveToWindow
|
|
744
|
+
{
|
|
745
|
+
[super didMoveToWindow];
|
|
746
|
+
|
|
747
|
+
if (!self.window) {
|
|
748
|
+
// The view is being removed, ensure that the scroll end event is dispatched
|
|
749
|
+
[self _handleScrollEndIfNeeded];
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
- (void)_handleScrollEndIfNeeded
|
|
754
|
+
{
|
|
755
|
+
if (_scrollView.isDecelerating || !_scrollView.isTracking) {
|
|
756
|
+
if (!_eventEmitter) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onMomentumScrollEnd([self _scrollViewMetrics]);
|
|
760
|
+
|
|
761
|
+
[self _updateStateWithContentOffset];
|
|
762
|
+
_isUserTriggeredScrolling = NO;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
743
766
|
- (void)_handleFinishedScrolling:(UIScrollView *)scrollView
|
|
744
767
|
{
|
|
745
768
|
[self _forceDispatchNextScrollEvent];
|
|
@@ -896,6 +896,26 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
|
|
896
896
|
RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndZooming : scrollView withView : view atScale : scale);
|
|
897
897
|
}
|
|
898
898
|
|
|
899
|
+
- (void)didMoveToWindow
|
|
900
|
+
{
|
|
901
|
+
[super didMoveToWindow];
|
|
902
|
+
if (self.window == nil) {
|
|
903
|
+
// Check if the ScrollView was in motion
|
|
904
|
+
if (_scrollView.isDecelerating || !_scrollView.isTracking) {
|
|
905
|
+
// Trigger the onMomentumScrollEnd event manually
|
|
906
|
+
RCT_SEND_SCROLL_EVENT(onMomentumScrollEnd, nil);
|
|
907
|
+
// We can't use the RCT_FORWARD_SCROLL_EVENT here beacuse the `_cmd` parameter passed
|
|
908
|
+
// to `respondsToSelector` is the current method - so it will be `didMoveToWindow` - and not
|
|
909
|
+
// `scrollViewDidEndDecelerating` that is passed.
|
|
910
|
+
for (NSObject<UIScrollViewDelegate> *scrollViewListener in _scrollListeners) {
|
|
911
|
+
if ([scrollViewListener respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) {
|
|
912
|
+
[scrollViewListener scrollViewDidEndDecelerating:_scrollView];
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
899
919
|
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
|
|
900
920
|
{
|
|
901
921
|
// Fire a final scroll event
|
|
@@ -3314,6 +3314,15 @@ public final class com/facebook/react/modules/core/TimingModule : com/facebook/f
|
|
|
3314
3314
|
public final class com/facebook/react/modules/core/TimingModule$Companion {
|
|
3315
3315
|
}
|
|
3316
3316
|
|
|
3317
|
+
public final class com/facebook/react/modules/debug/DevMenuModule : com/facebook/fbreact/specs/NativeDevMenuSpec {
|
|
3318
|
+
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V
|
|
3319
|
+
public fun debugRemotely (Z)V
|
|
3320
|
+
public fun reload ()V
|
|
3321
|
+
public fun setHotLoadingEnabled (Z)V
|
|
3322
|
+
public fun setProfilingEnabled (Z)V
|
|
3323
|
+
public fun show ()V
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3317
3326
|
public final class com/facebook/react/modules/debug/DevSettingsModule : com/facebook/fbreact/specs/NativeDevSettingsSpec {
|
|
3318
3327
|
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V
|
|
3319
3328
|
public fun addListener (Ljava/lang/String;)V
|
|
@@ -20,7 +20,7 @@ def sonatypeUsername = findProperty('SONATYPE_USERNAME')
|
|
|
20
20
|
def sonatypePassword = findProperty('SONATYPE_PASSWORD')
|
|
21
21
|
|
|
22
22
|
def reactAndroidProjectDir = project(':packages:react-native:ReactAndroid').projectDir
|
|
23
|
-
def mavenTempLocalUrl = 'file:///
|
|
23
|
+
def mavenTempLocalUrl = 'file:///var/folders/xp/yw_lp59x05d2mp0g0n2f_d240000gn/T/eas-build-workingdir/build/maven_local'
|
|
24
24
|
// Rewritten when copying this to ReactAndroid/publish.gradle
|
|
25
25
|
|
|
26
26
|
publishing {
|
|
@@ -27,6 +27,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
|
27
27
|
import com.facebook.react.modules.core.ExceptionsManagerModule;
|
|
28
28
|
import com.facebook.react.modules.core.HeadlessJsTaskSupportModule;
|
|
29
29
|
import com.facebook.react.modules.core.TimingModule;
|
|
30
|
+
import com.facebook.react.modules.debug.DevMenuModule;
|
|
30
31
|
import com.facebook.react.modules.debug.DevSettingsModule;
|
|
31
32
|
import com.facebook.react.modules.debug.SourceCodeModule;
|
|
32
33
|
import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
|
|
@@ -49,6 +50,7 @@ import java.util.Map;
|
|
|
49
50
|
AndroidInfoModule.class,
|
|
50
51
|
DeviceEventManagerModule.class,
|
|
51
52
|
DeviceInfoModule.class,
|
|
53
|
+
DevMenuModule.class,
|
|
52
54
|
DevSettingsModule.class,
|
|
53
55
|
ExceptionsManagerModule.class,
|
|
54
56
|
LogBoxModule.class,
|
|
@@ -108,6 +110,7 @@ class CoreModulesPackage extends BaseReactPackage implements ReactPackageLogger
|
|
|
108
110
|
AndroidInfoModule.class,
|
|
109
111
|
DeviceEventManagerModule.class,
|
|
110
112
|
DeviceInfoModule.class,
|
|
113
|
+
DevMenuModule.class,
|
|
111
114
|
DevSettingsModule.class,
|
|
112
115
|
ExceptionsManagerModule.class,
|
|
113
116
|
LogBoxModule.class,
|
|
@@ -142,6 +145,8 @@ class CoreModulesPackage extends BaseReactPackage implements ReactPackageLogger
|
|
|
142
145
|
return new AndroidInfoModule(reactContext);
|
|
143
146
|
case DeviceEventManagerModule.NAME:
|
|
144
147
|
return new DeviceEventManagerModule(reactContext, mHardwareBackBtnHandler);
|
|
148
|
+
case DevMenuModule.NAME:
|
|
149
|
+
return new DevMenuModule(reactContext, mReactInstanceManager.getDevSupportManager());
|
|
145
150
|
case DevSettingsModule.NAME:
|
|
146
151
|
return new DevSettingsModule(reactContext, mReactInstanceManager.getDevSupportManager());
|
|
147
152
|
case ExceptionsManagerModule.NAME:
|
|
@@ -289,10 +289,7 @@ public class ReactDelegate {
|
|
|
289
289
|
// With Bridgeless enabled, create and start the surface
|
|
290
290
|
if (ReactFeatureFlags.enableBridgelessArchitecture) {
|
|
291
291
|
if (mReactSurface == null) {
|
|
292
|
-
// Create a ReactSurface
|
|
293
292
|
mReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);
|
|
294
|
-
// Set main Activity's content view
|
|
295
|
-
mActivity.setContentView(mReactSurface.getView());
|
|
296
293
|
}
|
|
297
294
|
mReactSurface.start();
|
|
298
295
|
} else {
|
|
@@ -17,6 +17,7 @@ import android.view.ViewGroup;
|
|
|
17
17
|
import androidx.annotation.NonNull;
|
|
18
18
|
import androidx.annotation.Nullable;
|
|
19
19
|
import androidx.fragment.app.Fragment;
|
|
20
|
+
import com.facebook.react.config.ReactFeatureFlags;
|
|
20
21
|
import com.facebook.react.modules.core.PermissionAwareActivity;
|
|
21
22
|
import com.facebook.react.modules.core.PermissionListener;
|
|
22
23
|
|
|
@@ -69,9 +70,15 @@ public class ReactFragment extends Fragment implements PermissionAwareActivity {
|
|
|
69
70
|
if (mainComponentName == null) {
|
|
70
71
|
throw new IllegalStateException("Cannot loadApp if component name is null");
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
if (ReactFeatureFlags.enableBridgelessArchitecture) {
|
|
74
|
+
mReactDelegate =
|
|
75
|
+
new ReactDelegate(
|
|
76
|
+
getActivity(), getReactHost(), mainComponentName, launchOptions);
|
|
77
|
+
} else {
|
|
78
|
+
mReactDelegate =
|
|
79
|
+
new ReactDelegate(
|
|
80
|
+
getActivity(), getReactNativeHost(), mainComponentName, launchOptions, fabricEnabled);
|
|
81
|
+
}
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
/**
|
|
@@ -81,8 +88,34 @@ public class ReactFragment extends Fragment implements PermissionAwareActivity {
|
|
|
81
88
|
* implement {@code ReactApplication} or you simply have a different mechanism for storing a
|
|
82
89
|
* {@code ReactNativeHost}, e.g. as a static field somewhere.
|
|
83
90
|
*/
|
|
91
|
+
@Nullable
|
|
84
92
|
protected ReactNativeHost getReactNativeHost() {
|
|
85
|
-
|
|
93
|
+
ReactApplication application = ((ReactApplication) getActivity().getApplication());
|
|
94
|
+
if (application != null) {
|
|
95
|
+
return application.getReactNativeHost();
|
|
96
|
+
} else {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the {@link ReactHost} used by this app. By default, assumes {@link
|
|
103
|
+
* Activity#getApplication()} is an instance of {@link ReactApplication} and calls {@link
|
|
104
|
+
* ReactApplication#getReactHost()}. Override this method if your application class does not
|
|
105
|
+
* implement {@code ReactApplication} or you simply have a different mechanism for storing a
|
|
106
|
+
* {@code ReactHost}, e.g. as a static field somewhere.
|
|
107
|
+
*
|
|
108
|
+
* <p>If you're using Old Architecture/Bridge Mode, this method should return null as {@link
|
|
109
|
+
* ReactHost} is a Bridgeless-only concept.
|
|
110
|
+
*/
|
|
111
|
+
@Nullable
|
|
112
|
+
protected ReactHost getReactHost() {
|
|
113
|
+
ReactApplication application = ((ReactApplication) getActivity().getApplication());
|
|
114
|
+
if (application != null) {
|
|
115
|
+
return application.getReactHost();
|
|
116
|
+
} else {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
86
119
|
}
|
|
87
120
|
|
|
88
121
|
protected ReactDelegate getReactDelegate() {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
package com.facebook.react.modules.debug
|
|
9
|
+
|
|
10
|
+
import com.facebook.fbreact.specs.NativeDevMenuSpec
|
|
11
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
12
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
13
|
+
import com.facebook.react.devsupport.interfaces.DevSupportManager
|
|
14
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
15
|
+
|
|
16
|
+
/** Module that exposes the DevMenu to JS so that it can be used to programmatically open it. */
|
|
17
|
+
@ReactModule(name = NativeDevMenuSpec.NAME)
|
|
18
|
+
public class DevMenuModule(
|
|
19
|
+
reactContext: ReactApplicationContext?,
|
|
20
|
+
private val devSupportManager: DevSupportManager
|
|
21
|
+
) : NativeDevMenuSpec(reactContext) {
|
|
22
|
+
|
|
23
|
+
override fun show() {
|
|
24
|
+
if (devSupportManager.devSupportEnabled) {
|
|
25
|
+
devSupportManager.showDevOptionsDialog()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override fun reload() {
|
|
30
|
+
if (devSupportManager.devSupportEnabled) {
|
|
31
|
+
UiThreadUtil.runOnUiThread { devSupportManager.handleReloadJS() }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override fun debugRemotely(enableDebug: Boolean) {
|
|
36
|
+
devSupportManager.setRemoteJSDebugEnabled(enableDebug)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun setProfilingEnabled(enabled: Boolean) {
|
|
40
|
+
// iOS only
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun setHotLoadingEnabled(enabled: Boolean) {
|
|
44
|
+
devSupportManager.setHotModuleReplacementEnabled(enabled)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -23,6 +23,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider;
|
|
|
23
23
|
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
|
24
24
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
25
25
|
import com.facebook.react.modules.core.ExceptionsManagerModule;
|
|
26
|
+
import com.facebook.react.modules.debug.DevMenuModule;
|
|
26
27
|
import com.facebook.react.modules.debug.DevSettingsModule;
|
|
27
28
|
import com.facebook.react.modules.debug.SourceCodeModule;
|
|
28
29
|
import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
|
|
@@ -35,6 +36,7 @@ import java.util.Map;
|
|
|
35
36
|
nativeModules = {
|
|
36
37
|
AndroidInfoModule.class,
|
|
37
38
|
DeviceInfoModule.class,
|
|
39
|
+
DevMenuModule.class,
|
|
38
40
|
DevSettingsModule.class,
|
|
39
41
|
SourceCodeModule.class,
|
|
40
42
|
LogBoxModule.class,
|
|
@@ -61,6 +63,8 @@ class CoreReactPackage extends BaseReactPackage {
|
|
|
61
63
|
return new DeviceInfoModule(reactContext);
|
|
62
64
|
case SourceCodeModule.NAME:
|
|
63
65
|
return new SourceCodeModule(reactContext);
|
|
66
|
+
case DevMenuModule.NAME:
|
|
67
|
+
return new DevMenuModule(reactContext, mDevSupportManager);
|
|
64
68
|
case DevSettingsModule.NAME:
|
|
65
69
|
return new DevSettingsModule(reactContext, mDevSupportManager);
|
|
66
70
|
case DeviceEventManagerModule.NAME:
|
|
@@ -108,6 +112,7 @@ class CoreReactPackage extends BaseReactPackage {
|
|
|
108
112
|
AndroidInfoModule.class,
|
|
109
113
|
DeviceInfoModule.class,
|
|
110
114
|
SourceCodeModule.class,
|
|
115
|
+
DevMenuModule.class,
|
|
111
116
|
DevSettingsModule.class,
|
|
112
117
|
DeviceEventManagerModule.class,
|
|
113
118
|
LogBoxModule.class,
|
|
@@ -446,7 +446,7 @@ public class TextLayoutManager {
|
|
|
446
446
|
? paragraphAttributes.getBoolean(PA_KEY_INCLUDE_FONT_PADDING)
|
|
447
447
|
: DEFAULT_INCLUDE_FONT_PADDING;
|
|
448
448
|
int hyphenationFrequency =
|
|
449
|
-
TextAttributeProps.
|
|
449
|
+
TextAttributeProps.getHyphenationFrequency(
|
|
450
450
|
paragraphAttributes.getString(PA_KEY_HYPHENATION_FREQUENCY));
|
|
451
451
|
boolean adjustFontSizeToFit =
|
|
452
452
|
paragraphAttributes.contains(PA_KEY_ADJUST_FONT_SIZE_TO_FIT)
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react.views.view;
|
|
9
9
|
|
|
10
|
+
import android.content.Context;
|
|
11
|
+
import android.content.pm.PackageManager;
|
|
10
12
|
import android.graphics.Rect;
|
|
11
13
|
import android.util.Log;
|
|
12
14
|
import android.view.View;
|
|
@@ -94,6 +96,14 @@ public class ReactViewManager extends ReactClippingViewManager<ReactViewGroup> {
|
|
|
94
96
|
@ReactProp(name = "accessible")
|
|
95
97
|
public void setAccessible(ReactViewGroup view, boolean accessible) {
|
|
96
98
|
view.setFocusable(accessible);
|
|
99
|
+
// This is required to handle Android TV/ Fire TV Devices that are Touch Enabled as well as LeanBack
|
|
100
|
+
// https://developer.android.com/reference/android/view/View#requestFocus(int,%20android.graphics.Rect)
|
|
101
|
+
// ** A view will not actually take focus if it is not focusable (isFocusable() returns false), **
|
|
102
|
+
// ** or if it is focusable and it is not focusable in touch mode (isFocusableInTouchMode()) **
|
|
103
|
+
// ** while the device is in touch mode. **
|
|
104
|
+
if (hasTouchScreen(view.getContext())) {
|
|
105
|
+
view.setFocusableInTouchMode(accessible);
|
|
106
|
+
}
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
@ReactProp(name = "hasTVPreferredFocus")
|
|
@@ -498,6 +508,14 @@ public class ReactViewManager extends ReactClippingViewManager<ReactViewGroup> {
|
|
|
498
508
|
}
|
|
499
509
|
root.setFocusDestinations(fd);
|
|
500
510
|
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Utility function to help capture Android TV/ Fire TV Devices with Touch Support
|
|
514
|
+
*/
|
|
515
|
+
private boolean hasTouchScreen(Context context) {
|
|
516
|
+
PackageManager pm = context.getPackageManager();
|
|
517
|
+
return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
|
|
518
|
+
}
|
|
501
519
|
|
|
502
520
|
@ReactProp(name = "autoFocus")
|
|
503
521
|
public void setAutoFocusTV(ReactViewGroup view, boolean autoFocus) {
|
package/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ const chalk = require('chalk');
|
|
|
15
15
|
const {get} = require('https');
|
|
16
16
|
const semver = require('semver');
|
|
17
17
|
const {URL} = require('url');
|
|
18
|
+
const {spawn} = require('child_process');
|
|
18
19
|
|
|
19
20
|
const deprecated = () => {
|
|
20
21
|
throw new Error(
|
|
@@ -109,7 +110,7 @@ function warnWithDeprecationSchedule() {
|
|
|
109
110
|
${chalk.yellow('⚠️')} The \`init\` command is deprecated.
|
|
110
111
|
The behavior will be changed on ${chalk.white.bold(CLI_DEPRECATION_DATE.toLocaleDateString())} ${emphasis(`(${daysRemaining} day${daysRemaining > 1 ? 's' : ''})`)}.
|
|
111
112
|
|
|
112
|
-
- Switch to ${chalk.
|
|
113
|
+
- Switch to ${chalk.grey.bold('npx @react-native-community/cli init')} for the identical behavior.
|
|
113
114
|
- Refer to the documentation for information about alternative tools: ${chalk.dim('https://reactnative.dev/docs/getting-started')}`);
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -117,11 +118,10 @@ function warnWithDeprecated() {
|
|
|
117
118
|
if (!isInitCommand) {
|
|
118
119
|
return;
|
|
119
120
|
}
|
|
120
|
-
|
|
121
121
|
console.warn(`
|
|
122
122
|
🚨️ The \`init\` command is deprecated.
|
|
123
123
|
|
|
124
|
-
- Switch to ${chalk.
|
|
124
|
+
- Switch to ${chalk.grey.bold('npx @react-native-community/cli init')} for the identical behavior.
|
|
125
125
|
- Refer to the documentation for information about alternative tools: ${chalk.dim('https://reactnative.dev/docs/getting-started')}`);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -174,7 +174,7 @@ async function main() {
|
|
|
174
174
|
|
|
175
175
|
const isDeprecated =
|
|
176
176
|
CLI_DEPRECATION_DATE.getTime() <= new Date().getTime() ||
|
|
177
|
-
currentVersion.startsWith('0.
|
|
177
|
+
currentVersion.startsWith('0.77');
|
|
178
178
|
|
|
179
179
|
/**
|
|
180
180
|
* This command is now deprecated. We will continue to proxy commands to @react-native-community/cli, but it
|
|
@@ -191,11 +191,29 @@ async function main() {
|
|
|
191
191
|
warnWithDeprecated();
|
|
192
192
|
// We only exit if the user calls `init` and it's deprecated. All other cases should proxy to to @react-native-community/cli.
|
|
193
193
|
// Be careful with this as it can break a lot of users.
|
|
194
|
+
console.warn(`${chalk.green('Exiting...')}`);
|
|
194
195
|
process.exit(1);
|
|
195
|
-
} else if (
|
|
196
|
+
} else if (
|
|
197
|
+
currentVersion.startsWith('0.75') ||
|
|
198
|
+
currentVersion.startsWith('0.76')
|
|
199
|
+
) {
|
|
200
|
+
// We check deprecation schedule only for 0.75 and 0.76 and 0.77 is expected to land in Jan 2025.
|
|
196
201
|
warnWithDeprecationSchedule();
|
|
197
202
|
}
|
|
198
203
|
warnWhenRunningInit();
|
|
204
|
+
|
|
205
|
+
const proc = spawn(
|
|
206
|
+
'npx',
|
|
207
|
+
['@react-native-community/cli', ...process.argv.slice(2)],
|
|
208
|
+
{
|
|
209
|
+
stdio: 'inherit',
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const code = await new Promise(resolve => {
|
|
214
|
+
proc.on('exit', resolve);
|
|
215
|
+
});
|
|
216
|
+
process.exit(code);
|
|
199
217
|
}
|
|
200
218
|
|
|
201
219
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tvos",
|
|
3
|
-
"version": "0.76.0-
|
|
3
|
+
"version": "0.76.0-0rc3",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -110,16 +110,18 @@
|
|
|
110
110
|
},
|
|
111
111
|
"dependencies": {
|
|
112
112
|
"@jest/create-cache-key-function": "^29.6.3",
|
|
113
|
-
"@react-native/assets-registry": "0.76.0-rc.
|
|
114
|
-
"@react-native/codegen": "0.76.0-rc.
|
|
115
|
-
"@react-native/community-cli-plugin": "0.76.0-rc.
|
|
116
|
-
"@react-native/gradle-plugin": "0.76.0-rc.
|
|
117
|
-
"@react-native/js-polyfills": "0.76.0-rc.
|
|
118
|
-
"@react-native/normalize-colors": "0.76.0-rc.
|
|
119
|
-
"@react-native-tvos/virtualized-lists": "0.76.0-
|
|
113
|
+
"@react-native/assets-registry": "0.76.0-rc.3",
|
|
114
|
+
"@react-native/codegen": "0.76.0-rc.3",
|
|
115
|
+
"@react-native/community-cli-plugin": "0.76.0-rc.3",
|
|
116
|
+
"@react-native/gradle-plugin": "0.76.0-rc.3",
|
|
117
|
+
"@react-native/js-polyfills": "0.76.0-rc.3",
|
|
118
|
+
"@react-native/normalize-colors": "0.76.0-rc.3",
|
|
119
|
+
"@react-native-tvos/virtualized-lists": "0.76.0-0rc3",
|
|
120
120
|
"abort-controller": "^3.0.0",
|
|
121
121
|
"anser": "^1.4.9",
|
|
122
122
|
"ansi-regex": "^5.0.0",
|
|
123
|
+
"babel-jest": "^29.7.0",
|
|
124
|
+
"babel-plugin-syntax-hermes-parser": "^0.23.1",
|
|
123
125
|
"base64-js": "^1.5.1",
|
|
124
126
|
"chalk": "^4.0.0",
|
|
125
127
|
"commander": "^12.0.0",
|
|
@@ -130,8 +132,8 @@
|
|
|
130
132
|
"jest-environment-node": "^29.6.3",
|
|
131
133
|
"jsc-android": "^250231.0.0",
|
|
132
134
|
"memoize-one": "^5.0.0",
|
|
133
|
-
"metro-runtime": "^0.81.0-alpha.
|
|
134
|
-
"metro-source-map": "^0.81.0-alpha.
|
|
135
|
+
"metro-runtime": "^0.81.0-alpha.2",
|
|
136
|
+
"metro-source-map": "^0.81.0-alpha.2",
|
|
135
137
|
"mkdirp": "^0.5.1",
|
|
136
138
|
"nullthrows": "^1.1.1",
|
|
137
139
|
"pretty-format": "^29.7.0",
|
|
@@ -700,10 +700,18 @@ class ReactNativePodsUtils
|
|
|
700
700
|
map[field] = "$(inherited)" + flag
|
|
701
701
|
else
|
|
702
702
|
unless map[field].include?(flag)
|
|
703
|
-
|
|
703
|
+
if map[field].instance_of? String
|
|
704
|
+
map[field] = map[field] + flag
|
|
705
|
+
elsif map[field].instance_of? Array
|
|
706
|
+
map[field].push(flag)
|
|
707
|
+
end
|
|
704
708
|
end
|
|
705
709
|
unless map[field].include?("$(inherited)")
|
|
706
|
-
map[field]
|
|
710
|
+
if map[field].instance_of? String
|
|
711
|
+
map[field] = "$(inherited) " + map[field]
|
|
712
|
+
elsif map[field].instance_of? Array
|
|
713
|
+
map[field].unshift("$(inherited)")
|
|
714
|
+
end
|
|
707
715
|
end
|
|
708
716
|
end
|
|
709
717
|
end
|
|
@@ -92,6 +92,8 @@ fi
|
|
|
92
92
|
|
|
93
93
|
[ -z "$CLI_PATH" ] && CLI_PATH="$REACT_NATIVE_DIR/scripts/bundle.js"
|
|
94
94
|
|
|
95
|
+
[ -z "$BUNDLE_COMMAND" ] && BUNDLE_COMMAND="bundle"
|
|
96
|
+
|
|
95
97
|
[ -z "$COMPOSE_SOURCEMAP_PATH" ] && COMPOSE_SOURCEMAP_PATH="$REACT_NATIVE_DIR/scripts/compose-source-maps.js"
|
|
96
98
|
|
|
97
99
|
if [[ -z "$BUNDLE_CONFIG" ]]; then
|
|
@@ -52,10 +52,24 @@ function build_framework {
|
|
|
52
52
|
fi
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
# Allows RNTV CI to optionally build Vision OS framework
|
|
56
|
+
function set_include_vision {
|
|
57
|
+
if [[ "$INCLUDE_VISION_OS" == "0" || "$INCLUDE_VISION_OS" == "false" || "$INCLUDE_VISION_OS" == "FALSE" ]]; then
|
|
58
|
+
include_vision=0
|
|
59
|
+
else
|
|
60
|
+
include_vision=1
|
|
61
|
+
fi
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
# group the frameworks together to create a universal framework
|
|
56
65
|
function build_universal_framework {
|
|
57
66
|
if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then
|
|
58
|
-
|
|
67
|
+
set_include_vision
|
|
68
|
+
if [[ $include_vision == 1 ]]; then
|
|
69
|
+
create_universal_framework "iphoneos" "iphonesimulator" "catalyst" "xros" "xrsimulator" "appletvos" "appletvsimulator"
|
|
70
|
+
else
|
|
71
|
+
create_universal_framework "iphoneos" "iphonesimulator" "catalyst" "appletvos" "appletvsimulator"
|
|
72
|
+
fi
|
|
59
73
|
else
|
|
60
74
|
echo "Skipping; Clean \"destroot\" to rebuild".
|
|
61
75
|
fi
|
|
@@ -65,14 +79,17 @@ function build_universal_framework {
|
|
|
65
79
|
# this is used to preserve backward compatibility
|
|
66
80
|
function create_framework {
|
|
67
81
|
if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then
|
|
82
|
+
set_include_vision
|
|
83
|
+
|
|
68
84
|
build_framework "iphoneos"
|
|
69
85
|
build_framework "iphonesimulator"
|
|
70
86
|
build_framework "appletvos"
|
|
71
87
|
build_framework "appletvsimulator"
|
|
72
88
|
build_framework "catalyst"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
if [[ $include_vision == 1 ]]; then
|
|
90
|
+
build_framework "xros"
|
|
91
|
+
build_framework "xrsimulator"
|
|
92
|
+
fi
|
|
76
93
|
build_universal_framework
|
|
77
94
|
else
|
|
78
95
|
echo "Skipping; Clean \"destroot\" to rebuild".
|
|
Binary file
|
|
Binary file
|
|
Binary file
|