Skip to content

Commit 4f1a798

Browse files
authored
Add preserveEdgeToEdge prop (#765)
## 📜 Description Currently, even when `react-native-edge-to-edge` is installed, RNKC is able to disable `edge-to-edge`. For example, if we set `enable={false}` on `KeyboardProvider`, `disable` will be called on `EdgeToEdgeReactViewGroup`, and `WindowCompat.setDecorFitsSystemWindows` too. This change detect if `react-native-edge-to-edge` is installed. If it is, edge-to-edge is forced and cannot be disabled. ## 💡 Motivation and Context It fixes an issue that breaks edge-to-edge (not only when enabled with `react-native-edge-to-edge`, but in general). Fixes #592 (_Toggle enabled to false, observe that the NavigationBar reappears and lifts the content._) ## 📢 Changelog ### Android - Fixes issue with edge-to-edge when `KeyboardProvider` is used with `enabled={false}`. ## 🤔 How Has This Been Tested? - Using the example app (`react-native-edge-to-edge` installed). Before, when switching on the "14. Enable / disable" screen, we were able to disable edge-to-edge too, not only keyboard management. Now it stays edge-to-edge. ## 📸 Screenshots (if appropriate): ![Screenshot 2025-01-19 at 22 59 31](https://github.com/user-attachments/assets/de7b9b9d-2b57-45ad-a960-f57ea3e0f43b) ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent db0d0cc commit 4f1a798

File tree

9 files changed

+59
-2
lines changed

9 files changed

+59
-2
lines changed

android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ class KeyboardControllerViewManager(
3636
value: Boolean,
3737
) = manager.setNavigationBarTranslucent(view as EdgeToEdgeReactViewGroup, value)
3838

39+
@ReactProp(name = "preserveEdgeToEdge")
40+
override fun setPreserveEdgeToEdge(
41+
view: ReactViewGroup,
42+
value: Boolean,
43+
) = manager.setPreserveEdgeToEdge(view as EdgeToEdgeReactViewGroup, value)
44+
3945
@ReactProp(name = "enabled")
4046
override fun setEnabled(
4147
view: ReactViewGroup,

android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ class KeyboardControllerViewManagerImpl(
3737
view.setNavigationBarTranslucent(isNavigationBarTranslucent)
3838
}
3939

40+
fun setPreserveEdgeToEdge(
41+
view: EdgeToEdgeReactViewGroup,
42+
isPreservingEdgeToEdge: Boolean,
43+
) {
44+
view.setPreserveEdgeToEdge(isPreservingEdgeToEdge)
45+
}
46+
4047
fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
4148
val map: MutableMap<String, Any> =
4249
MapBuilder.of(

android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class EdgeToEdgeReactViewGroup(
3131
// props
3232
private var isStatusBarTranslucent = false
3333
private var isNavigationBarTranslucent = false
34+
private var isPreservingEdgeToEdge = false
3435
private var active = false
3536

3637
// internal class members
@@ -188,7 +189,10 @@ class EdgeToEdgeReactViewGroup(
188189
}
189190

190191
private fun disable() {
191-
this.goToEdgeToEdge(false)
192+
if (!isPreservingEdgeToEdge) {
193+
this.goToEdgeToEdge(false)
194+
}
195+
192196
this.setupWindowInsets()
193197
this.removeKeyboardCallbacks()
194198
modalAttachedWatcher.disable()
@@ -208,6 +212,10 @@ class EdgeToEdgeReactViewGroup(
208212
this.isNavigationBarTranslucent = isNavigationBarTranslucent
209213
}
210214

215+
fun setPreserveEdgeToEdge(isPreservingEdgeToEdge: Boolean) {
216+
this.isPreservingEdgeToEdge = isPreservingEdgeToEdge
217+
}
218+
211219
fun setActive(active: Boolean) {
212220
this.active = active
213221

android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ class KeyboardControllerViewManager(
4141
manager.setNavigationBarTranslucent(view, isNavigationBarTranslucent)
4242
}
4343

44+
@ReactProp(name = "preserveEdgeToEdge")
45+
fun setPreserveEdgeToEdge(
46+
view: EdgeToEdgeReactViewGroup,
47+
isPreservingEdgeToEdge: Boolean,
48+
) {
49+
manager.setPreserveEdgeToEdge(view, isPreservingEdgeToEdge)
50+
}
51+
4452
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =
4553
manager.getExportedCustomDirectEventTypeConstants()
4654
}

docs/docs/api/keyboard-controller-view.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ A boolean prop to indicate whether `StatusBar` should be translucent on `Android
4545

4646
A boolean prop to indicate whether [NavigationBar](https://m2.material.io/design/platform-guidance/android-bars.html#android-navigation-bar) should be translucent on `Android` or not.
4747

48+
### `preserveEdgeToEdge` <div className="label android"></div>
49+
50+
A boolean property indicating whether to keep [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) mode always enabled (even when you disable the module). This is useful if you are using an external library to enable it and don't want this library to disable it.
51+
4852
### `enabled`
4953

5054
A boolean prop indicating whether the view is active or not. If it's `true` then it moves application to [edge-to-edge](https://developer.android.com/training/gestures/edge-to-edge) mode on Android and setup keyboard callbacks. When `false` - moves app away from [edge-to-edge](https://developer.android.com/training/gestures/edge-to-edge) and removes keyboard listeners.

docs/docs/api/keyboard-provider.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ By default this library stretches to full screen (`edge-to-edge` mode) and statu
2121

2222
A boolean prop to indicate whether [NavigationBar](https://m2.material.io/design/platform-guidance/android-bars.html#android-navigation-bar) should be translucent on `Android` or not.
2323

24+
### `preserveEdgeToEdge` <div className="label android"></div>
25+
26+
A boolean property indicating whether to keep [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) mode always enabled (even when you disable the module). This is useful if you are using an external library to enable it and don't want this library to disable it.
27+
28+
:::info Good to know
29+
If you use [react-native-edge-to-edge](https://github.com/zoontek/react-native-edge-to-edge), then `statusBarTranslucent`, `navigationBarTranslucent` and `preserveEdgeToEdge` are automatically set to `true`, so you don't need to worry about them.
30+
:::
31+
2432
### `enabled`
2533

2634
A boolean prop indicating whether the module is enabled. It indicate only initial state, i. e. if you try to change this prop after component mount it will not have any effect. To change the property in runtime use [useKeyboardController](./hooks/module/use-keyboard-controller.md) hook and `setEnabled` method. Defaults to `true`.

src/animated.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ type KeyboardProviderProps = {
6868
* @platform android
6969
*/
7070
navigationBarTranslucent?: boolean;
71+
/**
72+
* A boolean property indicating whether to keep edge-to-edge mode always enabled (even when you disable the module).
73+
* Defaults to `false`.
74+
*
75+
* @see https://github.com/kirillzyusko/react-native-keyboard-controller/issues/592
76+
* @platform android
77+
*/
78+
preserveEdgeToEdge?: boolean;
7179
/**
7280
* A boolean prop indicating whether the module is enabled. It indicate only initial state,
7381
* i. e. if you try to change this prop after component mount it will not have any effect.
@@ -85,6 +93,7 @@ export const KeyboardProvider = ({
8593
children,
8694
statusBarTranslucent,
8795
navigationBarTranslucent,
96+
preserveEdgeToEdge,
8897
enabled: initiallyEnabled = true,
8998
}: KeyboardProviderProps) => {
9099
// ref
@@ -202,7 +211,11 @@ export const KeyboardProvider = ({
202211
}, [enabled]);
203212

204213
if (__DEV__) {
205-
controlEdgeToEdgeValues({ statusBarTranslucent, navigationBarTranslucent });
214+
controlEdgeToEdgeValues({
215+
statusBarTranslucent,
216+
navigationBarTranslucent,
217+
preserveEdgeToEdge,
218+
});
206219
}
207220

208221
return (
@@ -212,6 +225,7 @@ export const KeyboardProvider = ({
212225
enabled={enabled}
213226
navigationBarTranslucent={IS_EDGE_TO_EDGE || navigationBarTranslucent}
214227
statusBarTranslucent={IS_EDGE_TO_EDGE || statusBarTranslucent}
228+
preserveEdgeToEdge={IS_EDGE_TO_EDGE || preserveEdgeToEdge}
215229
style={styles.container}
216230
// on*Reanimated prop must precede animated handlers to work correctly
217231
onKeyboardMoveReanimated={keyboardHandler}

src/specs/KeyboardControllerViewNativeComponent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface NativeProps extends ViewProps {
5353
enabled?: boolean;
5454
statusBarTranslucent?: boolean;
5555
navigationBarTranslucent?: boolean;
56+
preserveEdgeToEdge?: boolean;
5657
// callbacks
5758
/// keyboard
5859
onKeyboardMoveStart?: DirectEventHandler<KeyboardMoveEvent>;

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export type KeyboardControllerProps = {
8989
// props
9090
statusBarTranslucent?: boolean;
9191
navigationBarTranslucent?: boolean;
92+
preserveEdgeToEdge?: boolean;
9293
enabled?: boolean;
9394
} & ViewProps;
9495

0 commit comments

Comments
 (0)