Skip to content

Commit a0b7709

Browse files
committed
Revert "Update Modal implementation"
1 parent 8686c28 commit a0b7709

7 files changed

Lines changed: 111 additions & 55 deletions

File tree

packages/react-native/Libraries/Modal/Modal.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,7 @@ export type ModalPropsAndroid = {
187187
hardwareAccelerated?: ?boolean,
188188

189189
/**
190-
* Whether the modal should go under the system status bar. Must be set
191-
* together with `navigationBarTranslucent` to draw the modal edge-to-edge.
190+
* Whether the modal should go under the system statusbar.
192191
*
193192
* @deprecated Has no effect on its own on API level 35+ (Android 15+) due to
194193
* edge-to-edge enforcement.
@@ -200,8 +199,8 @@ export type ModalPropsAndroid = {
200199
statusBarTranslucent?: ?boolean,
201200

202201
/**
203-
* Whether the modal should go under the system navigation bar. Must be set
204-
* together with `statusBarTranslucent` to draw the modal edge-to-edge.
202+
* Whether the modal should go under the system navigation bar.
203+
* `statusBarTranslucent` also needs to be `true`.
205204
*
206205
* @deprecated Has no effect on its own on API level 35+ (Android 15+) due to
207206
* edge-to-edge enforcement.
@@ -232,11 +231,11 @@ function confirmProps(props: ModalProps) {
232231
);
233232
}
234233
if (
235-
(props.statusBarTranslucent === true) !==
236-
(props.navigationBarTranslucent === true)
234+
props.navigationBarTranslucent === true &&
235+
props.statusBarTranslucent !== true
237236
) {
238237
console.warn(
239-
'`statusBarTranslucent` and `navigationBarTranslucent` must both be enabled to draw the Modal edge-to-edge. Enabling only one of them has no effect.',
238+
'Modal with translucent navigation bar and without translucent status bar is not supported.',
240239
);
241240
}
242241

@@ -385,10 +384,8 @@ class Modal extends React.Component<ModalProps, ModalState> {
385384
onDismiss={onDismiss}
386385
ref={this.props.modalRef}
387386
visible={this.props.visible}
388-
edgeToEdge={
389-
this.props.statusBarTranslucent === true &&
390-
this.props.navigationBarTranslucent === true
391-
}
387+
statusBarTranslucent={this.props.statusBarTranslucent}
388+
navigationBarTranslucent={this.props.navigationBarTranslucent}
392389
identifier={this._identifier}
393390
style={styles.modal}
394391
// $FlowFixMe[method-unbinding] added when improving typing for this parameters

packages/react-native/Libraries/Modal/__tests__/Modal-itest.js

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -149,63 +149,73 @@ describe('<Modal>', () => {
149149
);
150150
});
151151
});
152-
describe('edgeToEdge', () => {
153-
it('sets edgeToEdge="true" when both statusBarTranslucent and navigationBarTranslucent are true', () => {
152+
describe('statusBarTranslucent', () => {
153+
it('renders a Modal with statusBarTranslucent="true"', () => {
154154
Fantom.runTask(() => {
155-
root.render(
156-
<Modal
157-
statusBarTranslucent={true}
158-
navigationBarTranslucent={true}
159-
/>,
160-
);
155+
root.render(<Modal statusBarTranslucent={true} />);
161156
});
162157

163-
expect(root.getRenderedOutput({props: ['edgeToEdge']}).toJSX()).toEqual(
164-
<rn-modalHostView edgeToEdge="true">
158+
expect(
159+
root.getRenderedOutput({props: ['statusBarTranslucent']}).toJSX(),
160+
).toEqual(
161+
<rn-modalHostView statusBarTranslucent="true">
165162
<rn-view />
166163
</rn-modalHostView>,
167164
);
168165
});
169-
it('does not set edgeToEdge when only statusBarTranslucent is true', () => {
170-
// Enabling only one of statusBarTranslucent / navigationBarTranslucent
171-
// has no effect and emits a warning.
172-
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
173-
166+
it('renders a Modal with statusBarTranslucent="false"', () => {
174167
Fantom.runTask(() => {
175-
root.render(<Modal statusBarTranslucent={true} />);
168+
root.render(<Modal statusBarTranslucent={false} />);
176169
});
177170

178-
expect(root.getRenderedOutput({props: ['edgeToEdge']}).toJSX()).toEqual(
171+
expect(
172+
root.getRenderedOutput({props: ['statusBarTranslucent']}).toJSX(),
173+
).toEqual(
179174
<rn-modalHostView>
180175
<rn-view />
181176
</rn-modalHostView>,
182177
);
183-
expect(warn).toHaveBeenCalled();
184-
warn.mockRestore();
185178
});
186-
it('does not set edgeToEdge when only navigationBarTranslucent is true', () => {
187-
// Enabling only one of statusBarTranslucent / navigationBarTranslucent
188-
// has no effect and emits a warning.
189-
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
190-
179+
});
180+
describe('navigationBarTranslucent', () => {
181+
it('renders a Modal with navigationBarTranslucent="true" and statusBarTranslucent="true"', () => {
191182
Fantom.runTask(() => {
192-
root.render(<Modal navigationBarTranslucent={true} />);
183+
// navigationBarTranslucent=true with statusBarTranslucent=false is not supported
184+
// and it emits a warning.
185+
root.render(
186+
<Modal
187+
navigationBarTranslucent={true}
188+
statusBarTranslucent={true}
189+
/>,
190+
);
193191
});
194192

195-
expect(root.getRenderedOutput({props: ['edgeToEdge']}).toJSX()).toEqual(
196-
<rn-modalHostView>
193+
expect(
194+
root
195+
.getRenderedOutput({
196+
props: ['navigationBarTranslucent', 'statusBarTranslucent'],
197+
})
198+
.toJSX(),
199+
).toEqual(
200+
<rn-modalHostView
201+
navigationBarTranslucent="true"
202+
statusBarTranslucent="true">
197203
<rn-view />
198204
</rn-modalHostView>,
199205
);
200-
expect(warn).toHaveBeenCalled();
201-
warn.mockRestore();
202206
});
203-
it('does not set edgeToEdge when neither is true', () => {
207+
it('renders a Modal with navigationBarTranslucent="false"', () => {
204208
Fantom.runTask(() => {
205-
root.render(<Modal />);
209+
root.render(<Modal navigationBarTranslucent={false} />);
206210
});
207211

208-
expect(root.getRenderedOutput({props: ['edgeToEdge']}).toJSX()).toEqual(
212+
expect(
213+
root
214+
.getRenderedOutput({
215+
props: ['navigationBarTranslucent', 'statusBarTranslucent'],
216+
})
217+
.toJSX(),
218+
).toEqual(
209219
<rn-modalHostView>
210220
<rn-view />
211221
</rn-modalHostView>,

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5098,10 +5098,11 @@ public abstract interface class com/facebook/react/viewmanagers/ModalHostViewMan
50985098
public abstract fun setAllowSwipeDismissal (Landroid/view/View;Z)V
50995099
public abstract fun setAnimated (Landroid/view/View;Z)V
51005100
public abstract fun setAnimationType (Landroid/view/View;Ljava/lang/String;)V
5101-
public abstract fun setEdgeToEdge (Landroid/view/View;Z)V
51025101
public abstract fun setHardwareAccelerated (Landroid/view/View;Z)V
51035102
public abstract fun setIdentifier (Landroid/view/View;I)V
5103+
public abstract fun setNavigationBarTranslucent (Landroid/view/View;Z)V
51045104
public abstract fun setPresentationStyle (Landroid/view/View;Ljava/lang/String;)V
5105+
public abstract fun setStatusBarTranslucent (Landroid/view/View;Z)V
51055106
public abstract fun setSupportedOrientations (Landroid/view/View;Lcom/facebook/react/bridge/ReadableArray;)V
51065107
public abstract fun setTransparent (Landroid/view/View;Z)V
51075108
public abstract fun setVisible (Landroid/view/View;Z)V
@@ -5378,12 +5379,13 @@ public final class com/facebook/react/views/modal/ReactModalHostView : android/v
53785379
public final fun getAnimationType ()Ljava/lang/String;
53795380
public fun getChildAt (I)Landroid/view/View;
53805381
public fun getChildCount ()I
5381-
public final fun getEdgeToEdge ()Z
53825382
public final fun getEventDispatcher ()Lcom/facebook/react/uimanager/events/EventDispatcher;
53835383
public final fun getHardwareAccelerated ()Z
5384+
public final fun getNavigationBarTranslucent ()Z
53845385
public final fun getOnRequestCloseListener ()Lcom/facebook/react/views/modal/ReactModalHostView$OnRequestCloseListener;
53855386
public final fun getOnShowListener ()Landroid/content/DialogInterface$OnShowListener;
53865387
public final fun getStateWrapper ()Lcom/facebook/react/uimanager/StateWrapper;
5388+
public final fun getStatusBarTranslucent ()Z
53875389
public final fun getTransparent ()Z
53885390
public final fun onDropInstance ()V
53895391
public fun onHostDestroy ()V
@@ -5393,13 +5395,14 @@ public final class com/facebook/react/views/modal/ReactModalHostView : android/v
53935395
public fun removeViewAt (I)V
53945396
public final fun setAnimationType (Ljava/lang/String;)V
53955397
public final fun setDialogRootViewGroupTestId (Ljava/lang/String;)V
5396-
public final fun setEdgeToEdge (Z)V
53975398
public final fun setEventDispatcher (Lcom/facebook/react/uimanager/events/EventDispatcher;)V
53985399
public final fun setHardwareAccelerated (Z)V
53995400
public fun setId (I)V
5401+
public final fun setNavigationBarTranslucent (Z)V
54005402
public final fun setOnRequestCloseListener (Lcom/facebook/react/views/modal/ReactModalHostView$OnRequestCloseListener;)V
54015403
public final fun setOnShowListener (Landroid/content/DialogInterface$OnShowListener;)V
54025404
public final fun setStateWrapper (Lcom/facebook/react/uimanager/StateWrapper;)V
5405+
public final fun setStatusBarTranslucent (Z)V
54035406
public final fun setTransparent (Z)V
54045407
public fun shouldDelayChildPressedState ()Z
54055408
public final fun showOrUpdate ()V

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,14 @@ internal class ReactModalHostManager :
4949
view.transparent = value
5050
}
5151

52-
@ReactProp(name = "edgeToEdge")
53-
override fun setEdgeToEdge(view: ReactModalHostView, value: Boolean) {
54-
view.edgeToEdge = value
52+
@ReactProp(name = "statusBarTranslucent")
53+
override fun setStatusBarTranslucent(view: ReactModalHostView, value: Boolean) {
54+
view.statusBarTranslucent = value
55+
}
56+
57+
@ReactProp(name = "navigationBarTranslucent")
58+
override fun setNavigationBarTranslucent(view: ReactModalHostView, value: Boolean) {
59+
view.navigationBarTranslucent = value
5560
}
5661

5762
@ReactProp(name = "hardwareAccelerated")

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import com.facebook.react.views.view.ReactViewGroup
5454
import com.facebook.react.views.view.disableEdgeToEdge
5555
import com.facebook.react.views.view.enableEdgeToEdge
5656
import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn
57+
import com.facebook.react.views.view.setStatusBarTranslucency
5758

5859
/**
5960
* ReactModalHostView is a view that sits in the view hierarchy representing a Modal view.
@@ -79,7 +80,14 @@ public class ReactModalHostView(context: ThemedReactContext) :
7980
public var onShowListener: DialogInterface.OnShowListener? = null
8081
public var onRequestCloseListener: OnRequestCloseListener? = null
8182

82-
public var edgeToEdge: Boolean = false
83+
public var statusBarTranslucent: Boolean = false
84+
get() = field || isEdgeToEdgeFeatureFlagOn
85+
set(value) {
86+
field = value
87+
createNewDialog = createNewDialog || !isEdgeToEdgeFeatureFlagOn
88+
}
89+
90+
public var navigationBarTranslucent: Boolean = false
8391
get() = field || isEdgeToEdgeFeatureFlagOn
8492
set(value) {
8593
field = value
@@ -352,7 +360,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
352360
get() =
353361
FrameLayout(context).apply {
354362
addView(dialogRootViewGroup)
355-
if (!edgeToEdge) {
363+
if (!statusBarTranslucent) {
356364
// this is needed to prevent content hiding behind systems bars < API 30
357365
this.fitsSystemWindows = true
358366
}
@@ -384,10 +392,12 @@ public class ReactModalHostView(context: ThemedReactContext) :
384392
}
385393
}
386394

387-
if (edgeToEdge) {
395+
// Navigation bar cannot be translucent without status bar being translucent too
396+
if (navigationBarTranslucent) {
388397
dialogWindow.enableEdgeToEdge()
389398
} else {
390399
dialogWindow.disableEdgeToEdge()
400+
dialogWindow.setStatusBarTranslucency(statusBarTranslucent)
391401
}
392402

393403
if (transparent) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import android.view.Window
1515
import android.view.WindowInsetsController
1616
import android.view.WindowManager
1717
import androidx.annotation.VisibleForTesting
18+
import androidx.core.view.ViewCompat
1819
import androidx.core.view.WindowCompat
1920
import androidx.core.view.WindowInsetsCompat
2021
import androidx.core.view.WindowInsetsControllerCompat
@@ -67,6 +68,26 @@ internal fun updateEdgeToEdgeFeatureFlag(activity: Activity) {
6768
}
6869
}
6970

71+
@Suppress("DEPRECATION")
72+
internal fun Window.setStatusBarTranslucency(isTranslucent: Boolean) {
73+
// If the status bar is translucent hook into the window insets calculations
74+
// and consume all the top insets so no padding will be added under the status bar.
75+
if (isTranslucent) {
76+
decorView.setOnApplyWindowInsetsListener { v, insets ->
77+
val defaultInsets = v.onApplyWindowInsets(insets)
78+
defaultInsets.replaceSystemWindowInsets(
79+
defaultInsets.systemWindowInsetLeft,
80+
0,
81+
defaultInsets.systemWindowInsetRight,
82+
defaultInsets.systemWindowInsetBottom,
83+
)
84+
}
85+
} else {
86+
decorView.setOnApplyWindowInsetsListener(null)
87+
}
88+
ViewCompat.requestApplyInsets(decorView)
89+
}
90+
7091
internal fun Window.setStatusBarVisibility(isHidden: Boolean) {
7192
if (isHidden) {
7293
this.statusBarHide()

packages/react-native/src/private/specs_DEPRECATED/components/RCTModalHostViewNativeComponent.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,20 @@ type RCTModalHostViewNativeProps = Readonly<{
5151
transparent?: WithDefault<boolean, false>,
5252

5353
/**
54-
* The `edgeToEdge` prop determines whether your modal should go under the
55-
* system bars (status bar and navigation bar).
54+
* The `statusBarTranslucent` prop determines whether your modal should go under
55+
* the system statusbar.
56+
*
57+
* See https://reactnative.dev/docs/modal#statusBarTranslucent
58+
*/
59+
statusBarTranslucent?: WithDefault<boolean, false>,
60+
61+
/**
62+
* The `navigationBarTranslucent` prop determines whether your modal should go under
63+
* the system navigationbar.
64+
*
65+
* See https://reactnative.dev/docs/modal#navigationBarTranslucent
5666
*/
57-
edgeToEdge?: WithDefault<boolean, false>,
67+
navigationBarTranslucent?: WithDefault<boolean, false>,
5868

5969
/**
6070
* The `hardwareAccelerated` prop controls whether to force hardware

0 commit comments

Comments
 (0)