react-native-edge-to-edge 1.1.3 → 1.3.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.
Files changed (33) hide show
  1. package/README.md +75 -73
  2. package/android/src/main/java/com/zoontek/rnedgetoedge/EdgeToEdgeModuleImpl.kt +59 -15
  3. package/android/src/main/java/com/zoontek/rnedgetoedge/EdgeToEdgePackage.kt +9 -12
  4. package/android/src/main/res/values/attrs.xml +5 -0
  5. package/android/src/main/res/values/public.xml +6 -0
  6. package/android/src/main/res/values/styles.xml +52 -6
  7. package/android/src/main/res/values-v27/colors.xml +1 -2
  8. package/android/src/main/res/values-v27/styles.xml +18 -3
  9. package/android/src/main/res/values-v29/styles.xml +27 -6
  10. package/android/src/main/res/values-v30/styles.xml +27 -6
  11. package/dist/commonjs/SystemBars.js +18 -7
  12. package/dist/commonjs/SystemBars.js.map +1 -1
  13. package/dist/commonjs/expo.js +17 -4
  14. package/dist/commonjs/expo.js.map +1 -1
  15. package/dist/commonjs/specs/NativeEdgeToEdgeModule.js.map +1 -1
  16. package/dist/module/SystemBars.js +18 -7
  17. package/dist/module/SystemBars.js.map +1 -1
  18. package/dist/module/expo.js +17 -4
  19. package/dist/module/expo.js.map +1 -1
  20. package/dist/module/specs/NativeEdgeToEdgeModule.js.map +1 -1
  21. package/dist/typescript/SystemBars.d.ts.map +1 -1
  22. package/dist/typescript/expo.d.ts +6 -4
  23. package/dist/typescript/expo.d.ts.map +1 -1
  24. package/dist/typescript/specs/NativeEdgeToEdgeModule.d.ts +1 -0
  25. package/dist/typescript/specs/NativeEdgeToEdgeModule.d.ts.map +1 -1
  26. package/dist/typescript/types.d.ts +8 -5
  27. package/dist/typescript/types.d.ts.map +1 -1
  28. package/package.json +6 -6
  29. package/src/SystemBars.ts +27 -6
  30. package/src/expo.ts +33 -8
  31. package/src/specs/NativeEdgeToEdgeModule.ts +1 -0
  32. package/src/types.ts +5 -2
  33. package/android/src/main/res/values-v29/colors.xml +0 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # react-native-edge-to-edge
2
2
 
3
- Effortlessly enable [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) display in React Native, allowing your Android app content to flow seamlessly beneath the system bars.
3
+ Effortlessly enable [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) display in React Native, allowing your Android (v6 and above) app content to flow seamlessly beneath the system bars.
4
4
 
5
5
  [![mit licence](https://img.shields.io/dub/l/vibe-d.svg?style=for-the-badge)](https://github.com/zoontek/react-native-edge-to-edge/blob/main/LICENSE)
6
6
  [![npm version](https://img.shields.io/npm/v/react-native-edge-to-edge?style=for-the-badge)](https://www.npmjs.org/package/react-native-edge-to-edge)
@@ -27,16 +27,14 @@ It is supporting the **latest version**, and the **two previous minor series**.
27
27
 
28
28
  Recently, Google introduced a significant change: apps targeting SDK 35 will have edge-to-edge display [enforced by default](https://developer.android.com/about/versions/15/behavior-changes-15#edge-to-edge) on Android 15+. Google is _likely_ to mandate that app updates on the Play Store target SDK 35 starting on August 31, 2025. This assumption is based on the [previous years' requirements following a similar timeline](https://support.google.com/googleplay/android-developer/answer/11926878?sjid=11853000253346477363-EU#zippy=%2Care-there-any-exceptions-for-existing-apps-targeting-api-or-below:~:text=App%20update%20requirements).
29
29
 
30
- Currently, new React Native projects target SDK 34.
30
+ ### Consistency
31
+
32
+ iOS has long used edge-to-edge displays, so adopting this design across all platforms ensures a consistent user experience. It also simplifies managing safe areas, eliminating the need for special cases specific to Android.
31
33
 
32
34
  ### Immersive mode
33
35
 
34
36
  [Immersive mode](https://developer.android.com/develop/ui/views/layout/immersive) allows you to hide the status and navigation bars, making it ideal for full-screen experiences. Currently, the built-in [`StatusBar`](https://reactnative.dev/docs/statusbar) component uses [`FLAG_FULLSCREEN`](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#FLAG_FULLSCREEN), a flag that has been deprecated since Android 11.
35
37
 
36
- ### Consistency
37
-
38
- iOS has long used edge-to-edge displays, so adopting this design across all platforms ensures a consistent user experience. It also simplifies managing safe areas, eliminating the need for special cases specific to Android.
39
-
40
38
  ## Installation
41
39
 
42
40
  ```bash
@@ -45,14 +43,37 @@ $ npm i -S react-native-edge-to-edge
45
43
  $ yarn add react-native-edge-to-edge
46
44
  ```
47
45
 
46
+ ### Pick a parent theme
47
+
48
+ This library requires you to update the parent of your Android `AppTheme` to an edge-to-edge version. Don't worry, it's very easy to understand! You just need to choose a theme based on the current value:
49
+
50
+ | If you currently have… | …you should use |
51
+ | :---------------------------------------------- | :--------------------------------- |
52
+ | `Theme.AppCompat.DayNight.NoActionBar` | `Theme.EdgeToEdge` |
53
+ | `Theme.MaterialComponents.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material2` |
54
+ | `Theme.Material3.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3` |
55
+ | `Theme.AppCompat.Light.NoActionBar` | `Theme.EdgeToEdge.Light` |
56
+ | `Theme.MaterialComponents.Light.NoActionBar` | `Theme.EdgeToEdge.Material2.Light` |
57
+ | `Theme.Material3.Light.NoActionBar` | `Theme.EdgeToEdge.Material3.Light` |
58
+
48
59
  ### Expo
49
60
 
50
- Add the library plugin in your `app.json` config file and [create a new build](https://docs.expo.dev/develop/development-builds/create-a-build/):
61
+ Add the library plugin in your `app.json` config file and [create a new build](https://docs.expo.dev/develop/development-builds/create-a-build) 👷:
51
62
 
52
- ```diff
63
+ ```json
53
64
  {
54
65
  "expo": {
55
- + "plugins": ["react-native-edge-to-edge"]
66
+ "plugins": [
67
+ [
68
+ "react-native-edge-to-edge",
69
+ {
70
+ "android": {
71
+ "parentTheme": "Light",
72
+ "enforceNavigationBarContrast": false
73
+ }
74
+ }
75
+ ]
76
+ ]
56
77
  }
57
78
  }
58
79
  ```
@@ -60,10 +81,20 @@ Add the library plugin in your `app.json` config file and [create a new build](h
60
81
  _📌 The available plugins options are:_
61
82
 
62
83
  ```ts
84
+ type ParentTheme =
85
+ | "Default" // uses `Theme.EdgeToEdge`
86
+ | "Material2" // uses `Theme.EdgeToEdge.Material2`
87
+ | "Material3" // uses `Theme.EdgeToEdge.Material3`
88
+ | "Light" // uses `Theme.EdgeToEdge.Light`
89
+ | "Material2.Light" // uses `Theme.EdgeToEdge.Material2.Light`
90
+ | "Material3.Light"; // uses `Theme.EdgeToEdge.Material3.Light`
91
+
63
92
  type Options = {
64
93
  android?: {
65
- // use an edge-to-edge version of `Theme.{MaterialComponents,Material3}.DayNight.NoActionBar`
66
- parentTheme?: "Material2" | "Material3"; // optional, default is `undefined` (`Theme.EdgeToEdge`)
94
+ // see the "Pick a parent theme" section
95
+ parentTheme?: ParentTheme; // optional (default: `Default`)
96
+ // see the "Transparent navigation bar" section
97
+ enforceNavigationBarContrast?: boolean; // optional (default: `true`)
67
98
  };
68
99
  };
69
100
  ```
@@ -75,74 +106,27 @@ type Options = {
75
106
 
76
107
  Edit your `android/app/src/main/res/values/styles.xml` file to inherit from one of the provided themes:
77
108
 
78
- ```diff
109
+ ```xml
79
110
  <resources>
80
- <!-- inherit from Theme.EdgeToEdge / Theme.EdgeToEdge.Material2 / Theme.EdgeToEdge.Material3 -->
81
- - <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
82
- + <style name="AppTheme" parent="Theme.EdgeToEdge">
111
+ <!-- update your AppTheme parent (see the "Pick a parent theme" section) -->
112
+ <style name="AppTheme" parent="Theme.EdgeToEdge">
83
113
  <!-- … -->
114
+ <!-- disable the contrasting background of the navigation bar (optional) -->
115
+ <item name="enforceNavigationBarContrast">false</item>
84
116
  </style>
85
117
  </resources>
86
118
  ```
87
119
 
88
120
  ## Considerations
89
121
 
90
- ### Third-party libraries
91
-
92
- Many libraries expose options that you can set to account for the transparency of status and navigation bars. For example, the [`useHideAnimation`](https://github.com/zoontek/react-native-bootsplash?tab=readme-ov-file#usehideanimation) hook in `react-native-bootsplash` has `statusBarTranslucent` and `navigationBarTranslucent` options, the [`useAnimatedKeyboard`](https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedKeyboard) in `react-native-reanimated` has an `isStatusBarTranslucentAndroid` option, etc.
122
+ ### Transparent navigation bar
93
123
 
94
- > [!IMPORTANT]
95
- > Until third-party libraries officially add support for `react-native-edge-to-edge` to set these options automatically, you may need to adjust these options to prevent interference with the library.
96
-
97
- For library authors, we provide a lightweight package called `react-native-is-edge-to-edge` (note the `-is-`!), which checks whether `react-native-edge-to-edge` is installed, making it easy to update your library accordingly:
98
-
99
- ```ts
100
- import {
101
- controlEdgeToEdgeValues,
102
- isEdgeToEdge,
103
- } from "react-native-is-edge-to-edge";
104
-
105
- const EDGE_TO_EDGE = isEdgeToEdge();
106
-
107
- function MyAwesomeLibraryComponent({
108
- statusBarTranslucent,
109
- navigationBarTranslucent,
110
- }) {
111
- if (__DEV__) {
112
- // warn the user once about unnecessary defined values
113
- controlEdgeToEdgeValues({
114
- statusBarTranslucent,
115
- navigationBarTranslucent,
116
- });
117
- }
118
-
119
- return (
120
- <MyAwesomeLibraryNativeComponent
121
- statusBarTranslucent={EDGE_TO_EDGE || statusBarTranslucent}
122
- navigationBarTranslucent={EDGE_TO_EDGE || navigationBarTranslucent}
123
- // …
124
- />
125
- );
126
- }
127
- ```
128
-
129
- If you want to check for the library's presence on the native side to bypass certain parts of your code, consider using this small utility:
130
-
131
- ```kotlin
132
- object EdgeToEdge {
133
- // we cannot detect edge-to-edge, but we can detect react-native-edge-to-edge install
134
- val ENABLED: Boolean = try {
135
- Class.forName("com.zoontek.rnedgetoedge.EdgeToEdgePackage")
136
- true
137
- } catch (exception: ClassNotFoundException) {
138
- false
139
- }
140
- }
141
- ```
124
+ By default, this library adopts [Android 15 defaults](https://developer.android.com/about/versions/15/behavior-changes-15#ux): a fully transparent status bar, a fully transparent gesture navigation bar, and a semi-opaque button navigation bar. To enforce full transparency in all cases, set the `enforceNavigationBarContrast` option to `false`.<br/>
125
+ Note that by doing so, you will need to manage the navigation bar style (using `SystemBars`) in the same way you handle the status bar.
142
126
 
143
127
  ### Keyboard management
144
128
 
145
- Enabling edge-to-edge display disrupts basic Android keyboard management (`android:windowSoftInputMode="adjustResize"`), requiring an alternative solution. While [`KeyboardAvoidingView`](https://reactnative.dev/docs/keyboardavoidingview) is a viable option, we recommend using [react-native-keyboard-controller](https://github.com/kirillzyusko/react-native-keyboard-controller) for its enhanced capabilities.
129
+ Enabling edge-to-edge display disrupts Android keyboard management (`android:windowSoftInputMode="adjustResize"`), requiring an alternative solution. While [`KeyboardAvoidingView`](https://reactnative.dev/docs/keyboardavoidingview) is a viable option, we recommend using [react-native-keyboard-controller](https://github.com/kirillzyusko/react-native-keyboard-controller) for its enhanced capabilities.
146
130
 
147
131
  ### Safe area management
148
132
 
@@ -150,22 +134,24 @@ Effective safe area management is essential to prevent content from being displa
150
134
 
151
135
  ### Modal component quirks
152
136
 
153
- Status bar management has never worked effectively with the built-in [`Modal`](https://reactnative.dev/docs/modal) component (as it creates a `Dialog` with a `Window` instance distinct from `MainActivity`). A `statusBarTranslucent` prop was introduced, but it is insufficient because there is no equivalent for the navigation bar. Instead, we recommend using the [react-navigation modals](https://reactnavigation.org/docs/modal), which do not suffer from this issue, as they utilize [react-native-screens](https://docs.swmansion.com/react-native-screens) and `Fragment` behind the scenes.
137
+ Edge-to-edge support for the built-in [`Modal`](https://reactnative.dev/docs/modal) component will be available in [React Native 0.77](https://github.com/facebook/react-native/pull/47254). Meanwhile, we recommend using the [react-navigation modals](https://reactnavigation.org/docs/modal) or the [`expo-router` modal screens](https://docs.expo.dev/router/advanced/modals/#modal-screen-using-expo-router).
154
138
 
155
139
  ## API
156
140
 
157
141
  ### `<SystemBars />`
158
142
 
159
- A component for managing your app's system bars. This replace [`StatusBar`](https://reactnative.dev/docs/statusbar), [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar) and [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) (that uses a lot of now [deprecated APIs](https://developer.android.com/about/versions/15/behavior-changes-15#deprecated-apis)).
143
+ A component for managing your app's system bars. Replace all occurrences of [`StatusBar`](https://reactnative.dev/docs/statusbar), [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar) and [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) with it (they uses a lot of now [deprecated APIs](https://developer.android.com/about/versions/15/behavior-changes-15#deprecated-apis) and interfere with edge-to-edge).
160
144
 
161
145
  ```tsx
162
146
  import { SystemBars } from "react-native-edge-to-edge";
163
147
 
148
+ // "auto" is based on current color scheme (light -> dark content, dark -> light content)
149
+ type Style = "auto" | "light" | "dark";
150
+
164
151
  type SystemBarsProps = {
165
- // Sets the color of the status bar content (navigation bar adjusts itself automatically)
166
- // "auto" is based on current color scheme (light -> dark content, dark -> light content)
167
- style?: "auto" | "light" | "dark";
168
- // Hide system bars (the navigation bar cannot be hidden on iOS)
152
+ // set the color of the system bar content (as no effect on semi-opaque navigation bar)
153
+ style?: Style | { statusBar?: Style; navigationBar?: Style };
154
+ // hide system bars (the navigation bar cannot be hidden on iOS)
169
155
  hidden?: boolean | { statusBar?: boolean; navigationBar?: boolean };
170
156
  };
171
157
 
@@ -199,3 +185,19 @@ const entry: SystemBarsEntry = SystemBars.replaceStackEntry(
199
185
  props /*: SystemBarsProps */,
200
186
  );
201
187
  ```
188
+
189
+ ## Third-party libraries 🧩
190
+
191
+ If you're an author and your package interferes with edge-to-edge, refer to the [`react-native-is-edge-to-edge` `README.md`](./react-native-is-edge-to-edge) for compatibility instructions.
192
+
193
+ ## Troubleshooting 🤔
194
+
195
+ #### The system bars stays opaque
196
+
197
+ Until third-party libraries officially add support for `react-native-edge-to-edge` to set these options automatically, you may need to adjust them manually to prevent interference with the library.
198
+
199
+ For example, make sure to set `react-native-reanimated` `useAnimatedKeyboard` `isStatusBarTranslucentAndroid` and `isNavigationBarTranslucentAndroid` to `true` (until [this PR](https://github.com/software-mansion/react-native-reanimated/pull/6732) is merged), or to replace all occurrences of the built-in `StatusBar`, [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar) and [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) with `SystemBars`.
200
+
201
+ #### The navigation bar style is erratic
202
+
203
+ There's currently [an open issue](https://issuetracker.google.com/issues/346386744) with the Android 15 emulator image regarding the navigation bar style when it is is fully transparent. This issue does not occur on physical devices.
@@ -1,11 +1,14 @@
1
1
  package com.zoontek.rnedgetoedge
2
2
 
3
+ import android.os.Build.VERSION
4
+ import android.os.Build.VERSION_CODES
5
+
6
+ import android.app.Activity
3
7
  import android.content.res.Configuration
4
8
  import android.graphics.Color
5
- import android.os.Build
9
+ import android.util.TypedValue
6
10
  import android.view.WindowManager
7
11
 
8
- import androidx.core.content.ContextCompat
9
12
  import androidx.core.view.WindowCompat
10
13
  import androidx.core.view.WindowInsetsCompat
11
14
  import androidx.core.view.WindowInsetsControllerCompat
@@ -15,9 +18,28 @@ import com.facebook.react.bridge.ReactApplicationContext
15
18
  import com.facebook.react.bridge.ReadableMap
16
19
  import com.facebook.react.common.ReactConstants
17
20
 
21
+ internal val LightNavigationBarColor = Color.argb(0xe6, 0xFF, 0xFF, 0xFF)
22
+ internal val DarkNavigationBarColor = Color.argb(0x80, 0x1b, 0x1b, 0x1b)
23
+
18
24
  object EdgeToEdgeModuleImpl {
19
25
  const val NAME = "RNEdgeToEdge"
20
26
 
27
+ private val boolAttributes = mutableMapOf<Int, Boolean>()
28
+
29
+ private fun resolveBoolAttribute(activity: Activity, resId: Int): Boolean =
30
+ boolAttributes.getOrPut(resId) {
31
+ val value = TypedValue()
32
+ activity.theme.resolveAttribute(resId, value, true) && value.data != 0
33
+ }
34
+
35
+ private fun isNavigationBarLight(activity: Activity): Boolean =
36
+ resolveBoolAttribute(activity, R.attr.enforceNavigationBarLightTheme) ||
37
+ activity.window.decorView.resources.configuration.uiMode and
38
+ Configuration.UI_MODE_NIGHT_MASK != Configuration.UI_MODE_NIGHT_YES
39
+
40
+ private fun isNavigationBarTransparent(activity: Activity): Boolean =
41
+ !resolveBoolAttribute(activity, R.attr.enforceNavigationBarContrast)
42
+
21
43
  @Suppress("DEPRECATION")
22
44
  fun applyEdgeToEdge(reactContext: ReactApplicationContext) {
23
45
  val activity = reactContext.currentActivity
@@ -26,29 +48,43 @@ object EdgeToEdgeModuleImpl {
26
48
  activity.runOnUiThread {
27
49
  val window = activity.window
28
50
  val view = window.decorView
29
- val context = view.context
30
51
 
31
52
  WindowCompat.setDecorFitsSystemWindows(window, false)
32
53
 
33
54
  window.statusBarColor = Color.TRANSPARENT
34
- window.navigationBarColor = ContextCompat.getColor(context, R.color.navigationBarColor)
35
55
 
36
- val isDarkMode =
37
- view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
38
- Configuration.UI_MODE_NIGHT_YES
56
+ if (VERSION.SDK_INT >= VERSION_CODES.O_MR1 && isNavigationBarTransparent(activity)) {
57
+ window.navigationBarColor = Color.TRANSPARENT
39
58
 
40
- WindowInsetsControllerCompat(window, view).run {
41
- isAppearanceLightNavigationBars = !isDarkMode
42
- }
59
+ if (VERSION.SDK_INT >= VERSION_CODES.Q) {
60
+ window.isStatusBarContrastEnforced = false
61
+ window.isNavigationBarContrastEnforced = false
62
+ }
63
+ } else {
64
+ val isLight = isNavigationBarLight(activity)
43
65
 
44
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
45
- window.isStatusBarContrastEnforced = false
46
- window.isNavigationBarContrastEnforced = true
66
+ window.navigationBarColor = when {
67
+ VERSION.SDK_INT >= VERSION_CODES.Q -> Color.TRANSPARENT
68
+ VERSION.SDK_INT >= VERSION_CODES.O_MR1 && isLight -> LightNavigationBarColor
69
+ else -> DarkNavigationBarColor
70
+ }
71
+
72
+ WindowInsetsControllerCompat(window, view).run {
73
+ isAppearanceLightNavigationBars = when {
74
+ VERSION.SDK_INT >= VERSION_CODES.O_MR1 -> isLight
75
+ else -> false
76
+ }
77
+ }
78
+
79
+ if (VERSION.SDK_INT >= VERSION_CODES.Q) {
80
+ window.isStatusBarContrastEnforced = false
81
+ window.isNavigationBarContrastEnforced = true
82
+ }
47
83
  }
48
84
 
49
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
85
+ if (VERSION.SDK_INT >= VERSION_CODES.P) {
50
86
  window.attributes.layoutInDisplayCutoutMode = when {
51
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
87
+ VERSION.SDK_INT >= VERSION_CODES.R -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
52
88
  else -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
53
89
  }
54
90
  }
@@ -65,6 +101,8 @@ object EdgeToEdgeModuleImpl {
65
101
  config.takeIf { it.hasKey("statusBarStyle") }?.getString("statusBarStyle")
66
102
  val navigationBarHidden =
67
103
  config.takeIf { it.hasKey("navigationBarHidden") }?.getBoolean("navigationBarHidden")
104
+ val navigationBarStyle =
105
+ config.takeIf { it.hasKey("navigationBarStyle") }?.getString("navigationBarStyle")
68
106
 
69
107
  activity.runOnUiThread {
70
108
  val window = activity.window
@@ -74,6 +112,12 @@ object EdgeToEdgeModuleImpl {
74
112
  insetsController.isAppearanceLightStatusBars = it == "dark"
75
113
  }
76
114
 
115
+ if (VERSION.SDK_INT >= VERSION_CODES.O_MR1 && isNavigationBarTransparent(activity)) {
116
+ navigationBarStyle?.let {
117
+ insetsController.isAppearanceLightNavigationBars = it == "dark"
118
+ }
119
+ }
120
+
77
121
  if (statusBarHidden != null || navigationBarHidden != null) {
78
122
  insetsController.systemBarsBehavior =
79
123
  WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
@@ -1,12 +1,12 @@
1
1
  package com.zoontek.rnedgetoedge
2
2
 
3
- import com.facebook.react.TurboReactPackage
3
+ import com.facebook.react.BaseReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.module.model.ReactModuleInfo
7
7
  import com.facebook.react.module.model.ReactModuleInfoProvider
8
8
 
9
- class EdgeToEdgePackage : TurboReactPackage() {
9
+ class EdgeToEdgePackage : BaseReactPackage() {
10
10
  override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
11
11
  return when (name) {
12
12
  EdgeToEdgeModuleImpl.NAME -> EdgeToEdgeModule(reactContext)
@@ -16,21 +16,18 @@ class EdgeToEdgePackage : TurboReactPackage() {
16
16
 
17
17
  override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
18
18
  return ReactModuleInfoProvider {
19
- val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
20
- val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
21
-
22
19
  val moduleInfo = ReactModuleInfo(
23
20
  EdgeToEdgeModuleImpl.NAME,
24
21
  EdgeToEdgeModuleImpl.NAME,
25
- false,
26
- true,
27
- true,
28
- false,
29
- isTurboModule
22
+ canOverrideExistingModule = false,
23
+ needsEagerInit = true,
24
+ isCxxModule = false,
25
+ isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
30
26
  )
31
27
 
32
- moduleInfos[EdgeToEdgeModuleImpl.NAME] = moduleInfo
33
- moduleInfos
28
+ mapOf(
29
+ EdgeToEdgeModuleImpl.NAME to moduleInfo
30
+ )
34
31
  }
35
32
  }
36
33
  }
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <attr name="enforceNavigationBarContrast" format="boolean" />
4
+ <attr name="enforceNavigationBarLightTheme" format="boolean" />
5
+ </resources>
@@ -1,6 +1,12 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
+ <public name="enforceNavigationBarContrast" type="attr" />
4
+
3
5
  <public name="Theme.EdgeToEdge" type="style" />
4
6
  <public name="Theme.EdgeToEdge.Material2" type="style" />
5
7
  <public name="Theme.EdgeToEdge.Material3" type="style" />
8
+
9
+ <public name="Theme.EdgeToEdge.Light" type="style" />
10
+ <public name="Theme.EdgeToEdge.Material2.Light" type="style" />
11
+ <public name="Theme.EdgeToEdge.Material3.Light" type="style" />
6
12
  </resources>
@@ -1,6 +1,9 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
- <style name="Theme.EdgeToEdge.Common" parent="Theme.AppCompat.DayNight.NoActionBar">
3
+ <style name="Theme.EdgeToEdge.DayNight.Common" parent="Theme.AppCompat.DayNight.NoActionBar">
4
+ <item name="enforceNavigationBarContrast">true</item>
5
+ <item name="enforceNavigationBarLightTheme">false</item>
6
+
4
7
  <item name="android:windowDrawsSystemBarBackgrounds">true</item>
5
8
  <item name="android:fitsSystemWindows">false</item>
6
9
  <item name="android:navigationBarColor">@color/navigationBarColor</item>
@@ -8,7 +11,10 @@
8
11
  <item name="android:windowLightStatusBar">@bool/windowLightSystemBars</item>
9
12
  </style>
10
13
 
11
- <style name="Theme.EdgeToEdge.Material2.Common" parent="Theme.MaterialComponents.DayNight.NoActionBar">
14
+ <style name="Theme.EdgeToEdge.Material2.DayNight.Common" parent="Theme.MaterialComponents.DayNight.NoActionBar">
15
+ <item name="enforceNavigationBarContrast">true</item>
16
+ <item name="enforceNavigationBarLightTheme">false</item>
17
+
12
18
  <item name="android:windowDrawsSystemBarBackgrounds">true</item>
13
19
  <item name="android:fitsSystemWindows">false</item>
14
20
  <item name="android:navigationBarColor">@color/navigationBarColor</item>
@@ -16,7 +22,10 @@
16
22
  <item name="android:windowLightStatusBar">@bool/windowLightSystemBars</item>
17
23
  </style>
18
24
 
19
- <style name="Theme.EdgeToEdge.Material3.Common" parent="Theme.Material3.DayNight.NoActionBar">
25
+ <style name="Theme.EdgeToEdge.Material3.DayNight.Common" parent="Theme.Material3.DayNight.NoActionBar">
26
+ <item name="enforceNavigationBarContrast">true</item>
27
+ <item name="enforceNavigationBarLightTheme">false</item>
28
+
20
29
  <item name="android:windowDrawsSystemBarBackgrounds">true</item>
21
30
  <item name="android:fitsSystemWindows">false</item>
22
31
  <item name="android:navigationBarColor">@color/navigationBarColor</item>
@@ -24,7 +33,44 @@
24
33
  <item name="android:windowLightStatusBar">@bool/windowLightSystemBars</item>
25
34
  </style>
26
35
 
27
- <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.Common" />
28
- <style name="Theme.EdgeToEdge.Material2" parent="Theme.EdgeToEdge.Material2.Common" />
29
- <style name="Theme.EdgeToEdge.Material3" parent="Theme.EdgeToEdge.Material3.Common" />
36
+ <style name="Theme.EdgeToEdge.Light.Common" parent="Theme.AppCompat.Light.NoActionBar">
37
+ <item name="enforceNavigationBarContrast">true</item>
38
+ <item name="enforceNavigationBarLightTheme">true</item>
39
+
40
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
41
+ <item name="android:fitsSystemWindows">false</item>
42
+ <item name="android:navigationBarColor">@color/navigationBarColor</item>
43
+ <item name="android:statusBarColor">@android:color/transparent</item>
44
+ <item name="android:windowLightStatusBar">true</item>
45
+ </style>
46
+
47
+ <style name="Theme.EdgeToEdge.Material2.Light.Common" parent="Theme.MaterialComponents.Light.NoActionBar">
48
+ <item name="enforceNavigationBarContrast">true</item>
49
+ <item name="enforceNavigationBarLightTheme">true</item>
50
+
51
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
52
+ <item name="android:fitsSystemWindows">false</item>
53
+ <item name="android:navigationBarColor">@color/navigationBarColor</item>
54
+ <item name="android:statusBarColor">@android:color/transparent</item>
55
+ <item name="android:windowLightStatusBar">true</item>
56
+ </style>
57
+
58
+ <style name="Theme.EdgeToEdge.Material3.Light.Common" parent="Theme.Material3.Light.NoActionBar">
59
+ <item name="enforceNavigationBarContrast">true</item>
60
+ <item name="enforceNavigationBarLightTheme">true</item>
61
+
62
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
63
+ <item name="android:fitsSystemWindows">false</item>
64
+ <item name="android:navigationBarColor">@color/navigationBarColor</item>
65
+ <item name="android:statusBarColor">@android:color/transparent</item>
66
+ <item name="android:windowLightStatusBar">true</item>
67
+ </style>
68
+
69
+ <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.DayNight.Common" />
70
+ <style name="Theme.EdgeToEdge.Material2" parent="Theme.EdgeToEdge.Material2.DayNight.Common" />
71
+ <style name="Theme.EdgeToEdge.Material3" parent="Theme.EdgeToEdge.Material3.DayNight.Common" />
72
+
73
+ <style name="Theme.EdgeToEdge.Light" parent="Theme.EdgeToEdge.Light.Common" />
74
+ <style name="Theme.EdgeToEdge.Material2.Light" parent="Theme.EdgeToEdge.Material2.Light.Common" />
75
+ <style name="Theme.EdgeToEdge.Material3.Light" parent="Theme.EdgeToEdge.Material3.Light.Common" />
30
76
  </resources>
@@ -1,5 +1,4 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
- <!-- https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/policy/DecorView.java;l=142 -->
4
- <color name="navigationBarColor">#e6ffffff</color>
3
+ <color name="navigationBarColor">@android:color/transparent</color>
5
4
  </resources>
@@ -1,17 +1,32 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
- <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.Common">
3
+ <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.DayNight.Common">
4
4
  <item name="android:windowLightNavigationBar">@bool/windowLightSystemBars</item>
5
5
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
6
6
  </style>
7
7
 
8
- <style name="Theme.EdgeToEdge.Material2" parent="Theme.EdgeToEdge.Material2.Common">
8
+ <style name="Theme.EdgeToEdge.Material2" parent="Theme.EdgeToEdge.Material2.DayNight.Common">
9
9
  <item name="android:windowLightNavigationBar">@bool/windowLightSystemBars</item>
10
10
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
11
11
  </style>
12
12
 
13
- <style name="Theme.EdgeToEdge.Material3" parent="Theme.EdgeToEdge.Material3.Common">
13
+ <style name="Theme.EdgeToEdge.Material3" parent="Theme.EdgeToEdge.Material3.DayNight.Common">
14
14
  <item name="android:windowLightNavigationBar">@bool/windowLightSystemBars</item>
15
15
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
16
16
  </style>
17
+
18
+ <style name="Theme.EdgeToEdge.Light" parent="Theme.EdgeToEdge.Light.Common">
19
+ <item name="android:windowLightNavigationBar">true</item>
20
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
21
+ </style>
22
+
23
+ <style name="Theme.EdgeToEdge.Material2.Light" parent="Theme.EdgeToEdge.Material2.Light.Common">
24
+ <item name="android:windowLightNavigationBar">true</item>
25
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
26
+ </style>
27
+
28
+ <style name="Theme.EdgeToEdge.Material3.Light" parent="Theme.EdgeToEdge.Material3.Light.Common">
29
+ <item name="android:windowLightNavigationBar">true</item>
30
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
31
+ </style>
17
32
  </resources>
@@ -1,23 +1,44 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
- <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.Common">
3
+ <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.DayNight.Common">
4
4
  <item name="android:windowLightNavigationBar">@bool/windowLightSystemBars</item>
5
5
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
6
6
  <item name="android:enforceStatusBarContrast">false</item>
7
- <item name="android:enforceNavigationBarContrast">true</item>
7
+ <item name="android:enforceNavigationBarContrast">?enforceNavigationBarContrast</item>
8
8
  </style>
9
9
 
10
- <style name="Theme.EdgeToEdge.Material2" parent="Theme.EdgeToEdge.Material2.Common">
10
+ <style name="Theme.EdgeToEdge.Material2" parent="Theme.EdgeToEdge.Material2.DayNight.Common">
11
11
  <item name="android:windowLightNavigationBar">@bool/windowLightSystemBars</item>
12
12
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
13
13
  <item name="android:enforceStatusBarContrast">false</item>
14
- <item name="android:enforceNavigationBarContrast">true</item>
14
+ <item name="android:enforceNavigationBarContrast">?enforceNavigationBarContrast</item>
15
15
  </style>
16
16
 
17
- <style name="Theme.EdgeToEdge.Material3" parent="Theme.EdgeToEdge.Material3.Common">
17
+ <style name="Theme.EdgeToEdge.Material3" parent="Theme.EdgeToEdge.Material3.DayNight.Common">
18
18
  <item name="android:windowLightNavigationBar">@bool/windowLightSystemBars</item>
19
19
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
20
20
  <item name="android:enforceStatusBarContrast">false</item>
21
- <item name="android:enforceNavigationBarContrast">true</item>
21
+ <item name="android:enforceNavigationBarContrast">?enforceNavigationBarContrast</item>
22
+ </style>
23
+
24
+ <style name="Theme.EdgeToEdge.Light" parent="Theme.EdgeToEdge.Light.Common">
25
+ <item name="android:windowLightNavigationBar">true</item>
26
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
27
+ <item name="android:enforceStatusBarContrast">false</item>
28
+ <item name="android:enforceNavigationBarContrast">?enforceNavigationBarContrast</item>
29
+ </style>
30
+
31
+ <style name="Theme.EdgeToEdge.Material2.Light" parent="Theme.EdgeToEdge.Material2.Light.Common">
32
+ <item name="android:windowLightNavigationBar">true</item>
33
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
34
+ <item name="android:enforceStatusBarContrast">false</item>
35
+ <item name="android:enforceNavigationBarContrast">?enforceNavigationBarContrast</item>
36
+ </style>
37
+
38
+ <style name="Theme.EdgeToEdge.Material3.Light" parent="Theme.EdgeToEdge.Material3.Light.Common">
39
+ <item name="android:windowLightNavigationBar">true</item>
40
+ <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
41
+ <item name="android:enforceStatusBarContrast">false</item>
42
+ <item name="android:enforceNavigationBarContrast">?enforceNavigationBarContrast</item>
22
43
  </style>
23
44
  </resources>