Skip to content

Commit e172686

Browse files
authored
refactor: Remove codegen-related deep imports (#3458)
## Description This PR initiates the migration towards the stable JS APIs introduced in React Native 0.80+, as described in the official post https://reactnative.dev/blog/2025/06/12/moving-towards-a-stable-javascript-api. > [!NOTE] > As RN 0.79 does not export the required codegen bindings, this PR should be merged **only after** #3457 is merged. > [!NOTE] > There is still one remaining deep import (`react-native/Libraries/ReactNative/AppContainer`) used in `DebugContainer`. This relies on private APIs with a complex structure (e.g., Inspector) that do not have a feasible workaround at this point. The further investigation and potential resolution should be handled in a follow-up PR to avoid mixing it with codegen-related changes made in this one. - software-mansion/react-native-screens-labs#703 > > EDIT: After checking, we're following the same approach as Modal implementation in Core, therefore I asked Meta team whether it'd be possible to expose `AppContainer` publicly: react-native-community/discussions-and-proposals#893 (comment) ```js WARN Deep imports from the 'react-native' package are deprecated ('react-native/Libraries/ReactNative/AppContainer'). Source: /Users/tomaszboron/react-native-screens/src/components/DebugContainer.tsx 5:0 ``` Fixes software-mansion/react-native-screens-labs#378 ## Changes - Replaced deep imports for codegen with public RN APIs ## Test code and steps to reproduce Launched FabricExample on both android and iOS. Tested backward compatibility with RN 0.81 test app. Listed all occurencies of `react-native/` ```bash ➜ pwd /Users/tomaszboron/react-native-screens/src ➜ grep -r "react-native/" . ./components/DebugContainer.tsx:import AppContainer from 'react-native/Libraries/ReactNative/AppContainer'; ./components/Screen.tsx:// react-native/Libraries/Components/View/ReactNativeViewViewConfig.js ``` Both are okay: 1. AppContainer, left because lack of the public API 2. Just a comment inside the component, not an import ## Checklist - [x] Included code example that can be used to test this change - [x] Ensured that CI passes
1 parent 2903b79 commit e172686

22 files changed

+235
-302
lines changed

.eslintrc.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ module.exports = {
1818
],
1919
'import/ignore': [
2020
'node_modules/react-native/index\\.js$',
21-
'react-native/Libraries/Utilities/codegenNativeComponent.*',
22-
'react-native/Libraries/Types/CodegenTypes.*',
2321
],
2422
'import/resolver': {
2523
node: {

src/components/SearchBar.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import SearchBarNativeComponent, {
1616
SearchButtonPressedEvent,
1717
ChangeTextEvent,
1818
} from '../fabric/SearchBarNativeComponent';
19-
import { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
19+
import type { CodegenTypes as CT } from 'react-native';
2020

2121
const NativeSearchBar: React.ComponentType<
2222
SearchBarNativeProps & { ref?: React.RefObject<SearchBarCommands> }
@@ -112,15 +112,15 @@ function SearchBar(
112112
hideNavigationBar={parseBooleanToOptionalBooleanNativeProp(
113113
hideNavigationBar,
114114
)}
115-
onSearchFocus={onFocus as DirectEventHandler<SearchBarEvent>}
116-
onSearchBlur={onBlur as DirectEventHandler<SearchBarEvent>}
115+
onSearchFocus={onFocus as CT.DirectEventHandler<SearchBarEvent>}
116+
onSearchBlur={onBlur as CT.DirectEventHandler<SearchBarEvent>}
117117
onSearchButtonPress={
118-
onSearchButtonPress as DirectEventHandler<SearchButtonPressedEvent>
118+
onSearchButtonPress as CT.DirectEventHandler<SearchButtonPressedEvent>
119119
}
120120
onCancelButtonPress={
121-
onCancelButtonPress as DirectEventHandler<SearchBarEvent>
121+
onCancelButtonPress as CT.DirectEventHandler<SearchBarEvent>
122122
}
123-
onChangeText={onChangeText as DirectEventHandler<ChangeTextEvent>}
123+
onChangeText={onChangeText as CT.DirectEventHandler<ChangeTextEvent>}
124124
/>
125125
);
126126
}

src/fabric/FullWindowOverlayNativeComponent.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
'use client';
22

3-
// eslint-disable-next-line @react-native/no-deep-imports
4-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
5-
import type { ViewProps } from 'react-native';
6-
import { WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
3+
import { codegenNativeComponent } from 'react-native';
4+
import type { CodegenTypes as CT, ViewProps } from 'react-native';
75

86
// Internal export, not part of stable library API.
97
export interface NativeProps extends ViewProps {
10-
accessibilityContainerViewIsModal?: WithDefault<boolean, true>;
8+
accessibilityContainerViewIsModal?: CT.WithDefault<boolean, true>;
119
}
1210

1311
export default codegenNativeComponent<NativeProps>('RNSFullWindowOverlay', {

src/fabric/ModalScreenNativeComponent.ts

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
11
'use client';
22

3-
// eslint-disable-next-line @react-native/no-deep-imports
4-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
5-
import type { ViewProps, ColorValue } from 'react-native';
6-
import type {
7-
DirectEventHandler,
8-
WithDefault,
9-
Int32,
10-
Float,
11-
Double,
12-
} from 'react-native/Libraries/Types/CodegenTypes';
3+
import { codegenNativeComponent } from 'react-native';
4+
import type { CodegenTypes as CT, ViewProps, ColorValue } from 'react-native';
135

146
// eslint-disable-next-line @typescript-eslint/ban-types
157
type ScreenEvent = Readonly<{}>;
168

179
type ScreenDismissedEvent = Readonly<{
18-
dismissCount: Int32;
10+
dismissCount: CT.Int32;
1911
}>;
2012

2113
type TransitionProgressEvent = Readonly<{
22-
progress: Double;
23-
closing: Int32;
24-
goingForward: Int32;
14+
progress: CT.Double;
15+
closing: CT.Int32;
16+
goingForward: CT.Int32;
2517
}>;
2618

2719
type HeaderHeightChangeEvent = Readonly<{
28-
headerHeight: Double;
20+
headerHeight: CT.Double;
2921
}>;
3022

3123
type SheetDetentChangedEvent = Readonly<{
32-
index: Int32;
24+
index: CT.Int32;
3325
isStable: boolean;
3426
}>;
3527

3628
type GestureResponseDistanceType = Readonly<{
37-
start: Float;
38-
end: Float;
39-
top: Float;
40-
bottom: Float;
29+
start: CT.Float;
30+
end: CT.Float;
31+
top: CT.Float;
32+
bottom: CT.Float;
4133
}>;
4234

4335
type StackPresentation =
@@ -70,51 +62,51 @@ type ReplaceAnimation = 'pop' | 'push';
7062
type OptionalBoolean = 'undefined' | 'false' | 'true';
7163

7264
export interface NativeProps extends ViewProps {
73-
onAppear?: DirectEventHandler<ScreenEvent>;
74-
onDisappear?: DirectEventHandler<ScreenEvent>;
75-
onDismissed?: DirectEventHandler<ScreenDismissedEvent>;
76-
onNativeDismissCancelled?: DirectEventHandler<ScreenDismissedEvent>;
77-
onWillAppear?: DirectEventHandler<ScreenEvent>;
78-
onWillDisappear?: DirectEventHandler<ScreenEvent>;
79-
onHeaderHeightChange?: DirectEventHandler<HeaderHeightChangeEvent>;
80-
onTransitionProgress?: DirectEventHandler<TransitionProgressEvent>;
81-
onGestureCancel?: DirectEventHandler<ScreenEvent>;
82-
onHeaderBackButtonClicked?: DirectEventHandler<ScreenEvent>;
83-
onSheetDetentChanged?: DirectEventHandler<SheetDetentChangedEvent>;
84-
screenId?: WithDefault<string, ''>;
65+
onAppear?: CT.DirectEventHandler<ScreenEvent>;
66+
onDisappear?: CT.DirectEventHandler<ScreenEvent>;
67+
onDismissed?: CT.DirectEventHandler<ScreenDismissedEvent>;
68+
onNativeDismissCancelled?: CT.DirectEventHandler<ScreenDismissedEvent>;
69+
onWillAppear?: CT.DirectEventHandler<ScreenEvent>;
70+
onWillDisappear?: CT.DirectEventHandler<ScreenEvent>;
71+
onHeaderHeightChange?: CT.DirectEventHandler<HeaderHeightChangeEvent>;
72+
onTransitionProgress?: CT.DirectEventHandler<TransitionProgressEvent>;
73+
onGestureCancel?: CT.DirectEventHandler<ScreenEvent>;
74+
onHeaderBackButtonClicked?: CT.DirectEventHandler<ScreenEvent>;
75+
onSheetDetentChanged?: CT.DirectEventHandler<SheetDetentChangedEvent>;
76+
screenId?: CT.WithDefault<string, ''>;
8577
sheetAllowedDetents?: number[];
86-
sheetLargestUndimmedDetent?: WithDefault<Int32, -1>;
87-
sheetGrabberVisible?: WithDefault<boolean, false>;
88-
sheetCornerRadius?: WithDefault<Float, -1.0>;
89-
sheetExpandsWhenScrolledToEdge?: WithDefault<boolean, false>;
90-
sheetInitialDetent?: WithDefault<Int32, 0>;
91-
sheetElevation?: WithDefault<Int32, 24>;
92-
sheetShouldOverflowTopInset?: WithDefault<boolean, false>;
78+
sheetLargestUndimmedDetent?: CT.WithDefault<CT.Int32, -1>;
79+
sheetGrabberVisible?: CT.WithDefault<boolean, false>;
80+
sheetCornerRadius?: CT.WithDefault<CT.Float, -1.0>;
81+
sheetExpandsWhenScrolledToEdge?: CT.WithDefault<boolean, false>;
82+
sheetInitialDetent?: CT.WithDefault<CT.Int32, 0>;
83+
sheetElevation?: CT.WithDefault<CT.Int32, 24>;
84+
sheetShouldOverflowTopInset?: CT.WithDefault<boolean, false>;
9385
customAnimationOnSwipe?: boolean;
94-
fullScreenSwipeEnabled?: WithDefault<OptionalBoolean, 'undefined'>;
95-
fullScreenSwipeShadowEnabled?: WithDefault<boolean, true>;
86+
fullScreenSwipeEnabled?: CT.WithDefault<OptionalBoolean, 'undefined'>;
87+
fullScreenSwipeShadowEnabled?: CT.WithDefault<boolean, true>;
9688
homeIndicatorHidden?: boolean;
9789
preventNativeDismiss?: boolean;
98-
gestureEnabled?: WithDefault<boolean, true>;
90+
gestureEnabled?: CT.WithDefault<boolean, true>;
9991
statusBarColor?: ColorValue;
10092
statusBarHidden?: boolean;
10193
screenOrientation?: string;
10294
statusBarAnimation?: string;
10395
statusBarStyle?: string;
10496
statusBarTranslucent?: boolean;
10597
gestureResponseDistance?: GestureResponseDistanceType;
106-
stackPresentation?: WithDefault<StackPresentation, 'push'>;
107-
stackAnimation?: WithDefault<StackAnimation, 'default'>;
108-
transitionDuration?: WithDefault<Int32, 500>;
109-
replaceAnimation?: WithDefault<ReplaceAnimation, 'pop'>;
110-
swipeDirection?: WithDefault<SwipeDirection, 'horizontal'>;
98+
stackPresentation?: CT.WithDefault<StackPresentation, 'push'>;
99+
stackAnimation?: CT.WithDefault<StackAnimation, 'default'>;
100+
transitionDuration?: CT.WithDefault<CT.Int32, 500>;
101+
replaceAnimation?: CT.WithDefault<ReplaceAnimation, 'pop'>;
102+
swipeDirection?: CT.WithDefault<SwipeDirection, 'horizontal'>;
111103
hideKeyboardOnSwipe?: boolean;
112-
activityState?: WithDefault<Float, -1.0>;
104+
activityState?: CT.WithDefault<CT.Float, -1.0>;
113105
navigationBarColor?: ColorValue;
114106
navigationBarTranslucent?: boolean;
115107
navigationBarHidden?: boolean;
116108
nativeBackButtonDismissalEnabled?: boolean;
117-
synchronousShadowStateUpdatesEnabled?: WithDefault<boolean, false>;
109+
synchronousShadowStateUpdatesEnabled?: CT.WithDefault<boolean, false>;
118110
}
119111

120112
export default codegenNativeComponent<NativeProps>('RNSModalScreen', {

src/fabric/ScreenContainerNativeComponent.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use client';
22

3-
// eslint-disable-next-line @react-native/no-deep-imports
4-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
3+
import { codegenNativeComponent } from 'react-native';
54
import type { ViewProps } from 'react-native';
65

76
interface NativeProps extends ViewProps {}

src/fabric/ScreenContentWrapperNativeComponent.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// eslint-disable-next-line @react-native/no-deep-imports
2-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
1+
import { codegenNativeComponent } from 'react-native';
32
import type { ViewProps } from 'react-native';
43

54
export interface NativeProps extends ViewProps {}

src/fabric/ScreenFooterNativeComponent.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// eslint-disable-next-line @react-native/no-deep-imports
2-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
1+
import { codegenNativeComponent } from 'react-native';
32
import type { ViewProps } from 'react-native';
43

54
export interface NativeProps extends ViewProps {}

src/fabric/ScreenNativeComponent.ts

Lines changed: 46 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
11
'use client';
22

3-
// eslint-disable-next-line @react-native/no-deep-imports
4-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
5-
import type { ViewProps, ColorValue } from 'react-native';
6-
import type {
7-
DirectEventHandler,
8-
WithDefault,
9-
Int32,
10-
Float,
11-
Double,
12-
} from 'react-native/Libraries/Types/CodegenTypes';
3+
import { codegenNativeComponent } from 'react-native';
4+
import type { CodegenTypes as CT, ViewProps, ColorValue } from 'react-native';
135

146
// eslint-disable-next-line @typescript-eslint/ban-types
157
type ScreenEvent = Readonly<{}>;
168

179
type ScreenDismissedEvent = Readonly<{
18-
dismissCount: Int32;
10+
dismissCount: CT.Int32;
1911
}>;
2012

2113
type TransitionProgressEvent = Readonly<{
22-
progress: Double;
23-
closing: Int32;
24-
goingForward: Int32;
14+
progress: CT.Double;
15+
closing: CT.Int32;
16+
goingForward: CT.Int32;
2517
}>;
2618

2719
type HeaderHeightChangeEvent = Readonly<{
28-
headerHeight: Double;
20+
headerHeight: CT.Double;
2921
}>;
3022

3123
type SheetDetentChangedEvent = Readonly<{
32-
index: Int32;
24+
index: CT.Int32;
3325
isStable: boolean;
3426
}>;
3527

3628
type GestureResponseDistanceType = Readonly<{
37-
start: Float;
38-
end: Float;
39-
top: Float;
40-
bottom: Float;
29+
start: CT.Float;
30+
end: CT.Float;
31+
top: CT.Float;
32+
bottom: CT.Float;
4133
}>;
4234

4335
type StackPresentation =
@@ -72,56 +64,56 @@ type ScrollEdgeEffect = 'automatic' | 'hard' | 'soft' | 'hidden';
7264
type OptionalBoolean = 'undefined' | 'false' | 'true';
7365

7466
export interface NativeProps extends ViewProps {
75-
onAppear?: DirectEventHandler<ScreenEvent>;
76-
onDisappear?: DirectEventHandler<ScreenEvent>;
77-
onDismissed?: DirectEventHandler<ScreenDismissedEvent>;
78-
onNativeDismissCancelled?: DirectEventHandler<ScreenDismissedEvent>;
79-
onWillAppear?: DirectEventHandler<ScreenEvent>;
80-
onWillDisappear?: DirectEventHandler<ScreenEvent>;
81-
onHeaderHeightChange?: DirectEventHandler<HeaderHeightChangeEvent>;
82-
onTransitionProgress?: DirectEventHandler<TransitionProgressEvent>;
83-
onGestureCancel?: DirectEventHandler<ScreenEvent>;
84-
onHeaderBackButtonClicked?: DirectEventHandler<ScreenEvent>;
85-
onSheetDetentChanged?: DirectEventHandler<SheetDetentChangedEvent>;
86-
screenId?: WithDefault<string, ''>;
67+
onAppear?: CT.DirectEventHandler<ScreenEvent>;
68+
onDisappear?: CT.DirectEventHandler<ScreenEvent>;
69+
onDismissed?: CT.DirectEventHandler<ScreenDismissedEvent>;
70+
onNativeDismissCancelled?: CT.DirectEventHandler<ScreenDismissedEvent>;
71+
onWillAppear?: CT.DirectEventHandler<ScreenEvent>;
72+
onWillDisappear?: CT.DirectEventHandler<ScreenEvent>;
73+
onHeaderHeightChange?: CT.DirectEventHandler<HeaderHeightChangeEvent>;
74+
onTransitionProgress?: CT.DirectEventHandler<TransitionProgressEvent>;
75+
onGestureCancel?: CT.DirectEventHandler<ScreenEvent>;
76+
onHeaderBackButtonClicked?: CT.DirectEventHandler<ScreenEvent>;
77+
onSheetDetentChanged?: CT.DirectEventHandler<SheetDetentChangedEvent>;
78+
screenId?: CT.WithDefault<string, ''>;
8779
sheetAllowedDetents?: number[];
88-
sheetLargestUndimmedDetent?: WithDefault<Int32, -1>;
89-
sheetGrabberVisible?: WithDefault<boolean, false>;
90-
sheetCornerRadius?: WithDefault<Float, -1.0>;
91-
sheetExpandsWhenScrolledToEdge?: WithDefault<boolean, false>;
92-
sheetInitialDetent?: WithDefault<Int32, 0>;
93-
sheetElevation?: WithDefault<Int32, 24>;
94-
sheetShouldOverflowTopInset?: WithDefault<boolean, false>;
80+
sheetLargestUndimmedDetent?: CT.WithDefault<CT.Int32, -1>;
81+
sheetGrabberVisible?: CT.WithDefault<boolean, false>;
82+
sheetCornerRadius?: CT.WithDefault<CT.Float, -1.0>;
83+
sheetExpandsWhenScrolledToEdge?: CT.WithDefault<boolean, false>;
84+
sheetInitialDetent?: CT.WithDefault<CT.Int32, 0>;
85+
sheetElevation?: CT.WithDefault<CT.Int32, 24>;
86+
sheetShouldOverflowTopInset?: CT.WithDefault<boolean, false>;
9587
customAnimationOnSwipe?: boolean;
96-
fullScreenSwipeEnabled?: WithDefault<OptionalBoolean, 'undefined'>;
97-
fullScreenSwipeShadowEnabled?: WithDefault<boolean, true>;
88+
fullScreenSwipeEnabled?: CT.WithDefault<OptionalBoolean, 'undefined'>;
89+
fullScreenSwipeShadowEnabled?: CT.WithDefault<boolean, true>;
9890
homeIndicatorHidden?: boolean;
9991
preventNativeDismiss?: boolean;
100-
gestureEnabled?: WithDefault<boolean, true>;
92+
gestureEnabled?: CT.WithDefault<boolean, true>;
10193
statusBarColor?: ColorValue;
10294
statusBarHidden?: boolean;
10395
screenOrientation?: string;
10496
statusBarAnimation?: string;
10597
statusBarStyle?: string;
10698
statusBarTranslucent?: boolean;
10799
gestureResponseDistance?: GestureResponseDistanceType;
108-
stackPresentation?: WithDefault<StackPresentation, 'push'>;
109-
stackAnimation?: WithDefault<StackAnimation, 'default'>;
110-
transitionDuration?: WithDefault<Int32, 500>;
111-
replaceAnimation?: WithDefault<ReplaceAnimation, 'pop'>;
112-
swipeDirection?: WithDefault<SwipeDirection, 'horizontal'>;
100+
stackPresentation?: CT.WithDefault<StackPresentation, 'push'>;
101+
stackAnimation?: CT.WithDefault<StackAnimation, 'default'>;
102+
transitionDuration?: CT.WithDefault<CT.Int32, 500>;
103+
replaceAnimation?: CT.WithDefault<ReplaceAnimation, 'pop'>;
104+
swipeDirection?: CT.WithDefault<SwipeDirection, 'horizontal'>;
113105
hideKeyboardOnSwipe?: boolean;
114-
activityState?: WithDefault<Float, -1.0>;
106+
activityState?: CT.WithDefault<CT.Float, -1.0>;
115107
navigationBarColor?: ColorValue;
116108
navigationBarTranslucent?: boolean;
117109
navigationBarHidden?: boolean;
118110
nativeBackButtonDismissalEnabled?: boolean;
119-
bottomScrollEdgeEffect?: WithDefault<ScrollEdgeEffect, 'automatic'>;
120-
leftScrollEdgeEffect?: WithDefault<ScrollEdgeEffect, 'automatic'>;
121-
rightScrollEdgeEffect?: WithDefault<ScrollEdgeEffect, 'automatic'>;
122-
topScrollEdgeEffect?: WithDefault<ScrollEdgeEffect, 'automatic'>;
123-
synchronousShadowStateUpdatesEnabled?: WithDefault<boolean, false>;
124-
androidResetScreenShadowStateOnOrientationChangeEnabled?: WithDefault<
111+
bottomScrollEdgeEffect?: CT.WithDefault<ScrollEdgeEffect, 'automatic'>;
112+
leftScrollEdgeEffect?: CT.WithDefault<ScrollEdgeEffect, 'automatic'>;
113+
rightScrollEdgeEffect?: CT.WithDefault<ScrollEdgeEffect, 'automatic'>;
114+
topScrollEdgeEffect?: CT.WithDefault<ScrollEdgeEffect, 'automatic'>;
115+
synchronousShadowStateUpdatesEnabled?: CT.WithDefault<boolean, false>;
116+
androidResetScreenShadowStateOnOrientationChangeEnabled?: CT.WithDefault<
125117
boolean,
126118
true
127119
>;

src/fabric/ScreenNavigationContainerNativeComponent.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use client';
22

3-
// eslint-disable-next-line @react-native/no-deep-imports
4-
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
3+
import { codegenNativeComponent } from 'react-native';
54
import type { ViewProps } from 'react-native';
65

76
interface NativeProps extends ViewProps {}

0 commit comments

Comments
 (0)