react-native-navigation-mode 1.0.3 → 1.1.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.
@@ -13,7 +13,8 @@ Pod::Spec.new do |s|
13
13
  s.platforms = { :ios => "11.0" }
14
14
  s.source = { :git => package["repository"]["url"], :tag => "#{s.version}" }
15
15
 
16
- s.source_files = "ios/**/*.{h,m,mm}"
17
-
16
+ # No source files needed for iOS since we handle everything in JS
17
+ s.source_files = "ios/NavigationMode.h"
18
+
18
19
  install_modules_dependencies(s)
19
20
  end
package/README.md CHANGED
@@ -85,6 +85,7 @@ const isGesture = await isGestureNavigation(); // 🎯 Always accurate
85
85
  - 🎯 **Direct Native Detection** - No hacky workarounds or dimension-based guessing
86
86
  - ⚡ **Turbo Module** - Built with the latest React Native architecture
87
87
  - 🔄 **Real-time Detection** - Accurate navigation mode identification
88
+ - 📏 **Navigation Bar Height** - Get exact navigation bar height in dp for precise UI calculations
88
89
  - 📱 **Cross Platform** - Android detection + iOS compatibility
89
90
  - 🎣 **React Hooks** - Easy integration with `useNavigationMode()`
90
91
  - 📦 **Zero Dependencies** - Lightweight and performant
@@ -131,6 +132,16 @@ const navInfo = await getNavigationMode();
131
132
  console.log('Navigation type:', navInfo.type); // '3_button', '2_button', 'gesture', or 'unknown'
132
133
  ```
133
134
 
135
+ ### Navigation Bar Height
136
+
137
+ ```typescript
138
+ import { getNavigationBarHeight } from 'react-native-navigation-mode';
139
+
140
+ // Get navigation bar height in dp
141
+ const height = await getNavigationBarHeight();
142
+ console.log('Navigation bar height:', height); // number (dp)
143
+ ```
144
+
134
145
  ### React Hook (Recommended)
135
146
 
136
147
  ```typescript
@@ -166,7 +177,7 @@ export default function AdaptiveUI() {
166
177
  return (
167
178
  <View
168
179
  style={{
169
- paddingBottom: navigationMode?.isGestureNavigation ? 34 : 48 // Adjust for gesture nav
180
+ paddingBottom: navigationMode?.navigationBarHeight
170
181
  }}
171
182
  >
172
183
  {/* Your content */}
@@ -187,6 +198,10 @@ Returns comprehensive navigation mode information.
187
198
 
188
199
  Quick check if device is using gesture navigation.
189
200
 
201
+ #### `getNavigationBarHeight(): Promise<number>`
202
+
203
+ Returns the navigation bar height in density-independent pixels (dp).
204
+
190
205
  ### Hooks
191
206
 
192
207
  #### `useNavigationMode(): { navigationMode, loading, error }`
@@ -197,24 +212,27 @@ React hook for navigation mode detection with loading and error states.
197
212
 
198
213
  #### `NavigationModeInfo`
199
214
 
200
- | Property | Type | Description |
201
- | ------------------- | ---------------------------------------------- | ------------------------------------------------ |
202
- | type | `'3_button' \| '2_button' \| 'gesture' \| 'unknown'` | Navigation mode type |
203
- | isGestureNavigation | `boolean` | Whether gesture navigation is active |
204
- | interactionMode | `number \| undefined` | Raw Android interaction mode (0, 1, 2, or -1) |
215
+ | Property | Type | Description |
216
+ | ------------------- | ------------------------------------------------- | --------------------------------------------- |
217
+ | type | `'3_button' | '2_button' | 'gesture' | 'unknown'` | Navigation mode type |
218
+ | isGestureNavigation | `boolean` | Whether gesture navigation is active |
219
+ | interactionMode | `number | undefined` | Raw Android interaction mode (0, 1, 2, or -1) |
220
+ | navigationBarHeight | `number | undefined` | Navigation bar height in dp |
205
221
 
206
222
  ## Platform Support
207
223
 
208
224
  | Platform | Support | Notes |
209
225
  |----------|---------|-------|
210
- | Android | ✅ Full | Detects all navigation modes via native Android APIs |
211
- | iOS | ✅ Compatible | Always returns `gesture` (iOS uses gesture navigation) |
226
+ | Android | ✅ Full | Detects all navigation modes and navigation bar height via native Android APIs |
227
+ | iOS | ✅ Compatible | Always returns `gesture` and `navigationBarHeight: 0` (iOS uses gesture navigation) |
212
228
 
213
229
  ### Android Compatibility
214
230
 
215
231
  - **API 21+** - Basic navigation bar detection
216
232
  - **API 29+** - Full navigation mode detection (`config_navBarInteractionMode`)
217
233
  - **All versions** - Fallback detection methods included
234
+ - **API 30+** - WindowInsets-based navigation bar height detection
235
+ - **API 24-29** - Resource-based navigation bar height fallback
218
236
 
219
237
  ## How It Works
220
238
 
@@ -236,7 +254,7 @@ The library uses multiple detection methods for maximum accuracy:
236
254
 
237
255
  ## Notes
238
256
 
239
- 1. 🍎 **iOS Behavior** - iOS always returns `isGestureNavigation: true` since iOS doesn't have 3-button navigation
257
+ 1. 1. 🍎 **iOS Behavior** - iOS always returns `isGestureNavigation: true` and `navigationBarHeight: 0` since iOS doesn't have Android-style navigation bars
240
258
  2. ⚡ **Performance** - Turbo module ensures minimal performance impact
241
259
  3. 🔄 **Real-time** - Navigation mode is detected at call time, reflecting current device settings
242
260
 
@@ -1,14 +1,15 @@
1
1
  package com.navigationmode
2
2
 
3
+ import android.app.Activity
3
4
  import android.content.Context
4
5
  import android.content.res.Resources
5
6
  import android.os.Build
6
7
  import android.provider.Settings
7
- import android.view.ViewConfiguration
8
+ import android.view.WindowInsets
9
+ import com.facebook.react.bridge.Arguments
8
10
  import com.facebook.react.bridge.Promise
9
11
  import com.facebook.react.bridge.ReactApplicationContext
10
12
  import com.facebook.react.bridge.WritableMap
11
- import com.facebook.react.bridge.Arguments
12
13
  import com.facebook.react.module.annotations.ReactModule
13
14
 
14
15
  @ReactModule(name = NavigationModeModule.NAME)
@@ -21,11 +22,49 @@ class NavigationModeModule(reactContext: ReactApplicationContext) :
21
22
 
22
23
  override fun getName(): String = NAME
23
24
 
25
+ private fun getNavigationBarHeight(context: Context): Int {
26
+ // Try to get Activity for WindowInsets
27
+ val activity = if (context is Activity) context else reactApplicationContext.currentActivity
28
+ val density = context.resources.displayMetrics.density // Get device density
29
+
30
+ if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
31
+ val insets = activity.window.decorView.rootWindowInsets
32
+ if (insets != null) {
33
+ val navBar = insets.getInsets(WindowInsets.Type.navigationBars())
34
+ return (navBar.bottom / density).toInt() // Convert pixels to dp
35
+ }
36
+ }
37
+
38
+ // Fallback to resource-based approach for API < 30
39
+ val resources = context.resources
40
+ val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
41
+ return if (resourceId > 0) {
42
+ // getDimensionPixelSize returns pixels, convert to dp
43
+ (resources.getDimensionPixelSize(resourceId) / density).toInt()
44
+ } else {
45
+ 0 // Fallback for devices without a navigation bar
46
+ }
47
+ }
48
+
49
+ override fun getNavigationBarHeight(promise: Promise) {
50
+ try {
51
+ val context = reactApplicationContext
52
+ val navBarHeight = getNavigationBarHeight(context)
53
+ promise.resolve(navBarHeight)
54
+ } catch (e: Exception) {
55
+ promise.reject("NAV_BAR_HEIGHT_ERROR", "Failed to get navigation bar height: ${e.message}", e)
56
+ }
57
+ }
58
+
24
59
  override fun getNavigationMode(promise: Promise) {
25
60
  try {
26
61
  val result = Arguments.createMap()
27
62
  val context = reactApplicationContext
28
63
 
64
+ // Use reactApplicationContext for navigation bar height
65
+ val navBarHeight = getNavigationBarHeight(context)
66
+ result.putInt("navigationBarHeight", navBarHeight)
67
+
29
68
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
30
69
  val navBarInteractionMode = getNavBarInteractionMode(context)
31
70
  result.putInt("interactionMode", navBarInteractionMode)
@@ -1,9 +1,9 @@
1
- #import <NavigationModeSpec/NavigationModeSpec.h>
1
+ // Placeholder header for iOS - actual functionality handled in JavaScript
2
+ // This library only provides native functionality on Android
2
3
 
3
- NS_ASSUME_NONNULL_BEGIN
4
+ #ifndef NavigationMode_h
5
+ #define NavigationMode_h
4
6
 
5
- @interface NavigationMode : NSObject <NativeNavigationModeSpec>
7
+ // Empty placeholder - no native iOS implementation needed
6
8
 
7
- @end
8
-
9
- NS_ASSUME_NONNULL_END
9
+ #endif /* NavigationMode_h */
@@ -1,5 +1,8 @@
1
1
  "use strict";
2
2
 
3
- import { TurboModuleRegistry } from 'react-native';
4
- export default TurboModuleRegistry.getEnforcing('NavigationMode');
3
+ import { TurboModuleRegistry, Platform } from 'react-native';
4
+ // Only get the native module on Android
5
+ // On iOS, we'll handle everything in JavaScript
6
+ const NativeModule = Platform.OS === 'android' ? TurboModuleRegistry.getEnforcing('NavigationMode') : null;
7
+ export default NativeModule;
5
8
  //# sourceMappingURL=NativeNavigationMode.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeNavigationMode.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAalD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,gBAAgB,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","Platform","NativeModule","OS","getEnforcing"],"sourceRoot":"../../src","sources":["NativeNavigationMode.ts"],"mappings":";;AACA,SAASA,mBAAmB,EAAEC,QAAQ,QAAQ,cAAc;AAe5D;AACA;AACA,MAAMC,YAAY,GAChBD,QAAQ,CAACE,EAAE,KAAK,SAAS,GACrBH,mBAAmB,CAACI,YAAY,CAAO,gBAAgB,CAAC,GACxD,IAAI;AAEV,eAAeF,YAAY","ignoreList":[]}
@@ -8,13 +8,17 @@ import NavigationModeModule from "./NativeNavigationMode.js";
8
8
  * Returns navigation type, interaction mode, and device info
9
9
  */
10
10
  export function getNavigationMode() {
11
- if (Platform.OS === 'ios') {
11
+ // null check is redundant as it's always null for iOS but it's there to satisfy TypeScript
12
+ if (Platform.OS === 'ios' || NavigationModeModule === null) {
12
13
  // iOS always uses gesture navigation (no 3-button navigation exists)
13
14
  return Promise.resolve({
14
15
  type: 'gesture',
15
- isGestureNavigation: true
16
+ isGestureNavigation: true,
17
+ navigationBarHeight: 0 // iOS doesn't have a navigation bar like Android
16
18
  });
17
19
  }
20
+
21
+ // Only call native module on Android
18
22
  return NavigationModeModule.getNavigationMode();
19
23
  }
20
24
 
@@ -23,13 +27,31 @@ export function getNavigationMode() {
23
27
  * @returns Promise<boolean> - true if gesture navigation is active
24
28
  */
25
29
  export function isGestureNavigation() {
26
- if (Platform.OS === 'ios') {
30
+ // null check is redundant as it's always null for iOS but it's there to satisfy TypeScript
31
+ if (Platform.OS === 'ios' || NavigationModeModule === null) {
27
32
  // iOS always uses gesture navigation
28
33
  return Promise.resolve(true);
29
34
  }
35
+
36
+ // Only call native module on Android
30
37
  return NavigationModeModule.isGestureNavigation();
31
38
  }
32
39
 
40
+ /**
41
+ * Get the navigation bar height in dp
42
+ * @returns Promise<number> - navigation bar height in dp
43
+ */
44
+ export function getNavigationBarHeight() {
45
+ // null check is redundant as it's always null for iOS but it's there to satisfy TypeScript
46
+ if (Platform.OS === 'ios' || NavigationModeModule === null) {
47
+ // iOS doesn't have a navigation bar like Android
48
+ return Promise.resolve(0);
49
+ }
50
+
51
+ // Only call native module on Android
52
+ return NavigationModeModule.getNavigationBarHeight();
53
+ }
54
+
33
55
  /**
34
56
  * Hook for React components to get navigation mode
35
57
  */
@@ -70,6 +92,7 @@ export function useNavigationMode() {
70
92
  export default {
71
93
  getNavigationMode,
72
94
  isGestureNavigation,
95
+ getNavigationBarHeight,
73
96
  useNavigationMode
74
97
  };
75
98
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["Platform","React","NavigationModeModule","getNavigationMode","OS","Promise","resolve","type","isGestureNavigation","useNavigationMode","navigationMode","setNavigationMode","useState","loading","setLoading","error","setError","useEffect","mounted","fetchNavigationMode","mode","err","Error"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,OAAOC,KAAK,MAAM,OAAO;AACzB,OAAOC,oBAAoB,MAEpB,2BAAwB;AAI/B;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAgC;EAC/D,IAAIH,QAAQ,CAACI,EAAE,KAAK,KAAK,EAAE;IACzB;IACA,OAAOC,OAAO,CAACC,OAAO,CAAC;MACrBC,IAAI,EAAE,SAAS;MACfC,mBAAmB,EAAE;IACvB,CAAC,CAAC;EACJ;EAEA,OAAON,oBAAoB,CAACC,iBAAiB,CAAC,CAAC;AACjD;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASK,mBAAmBA,CAAA,EAAqB;EACtD,IAAIR,QAAQ,CAACI,EAAE,KAAK,KAAK,EAAE;IACzB;IACA,OAAOC,OAAO,CAACC,OAAO,CAAC,IAAI,CAAC;EAC9B;EAEA,OAAOJ,oBAAoB,CAACM,mBAAmB,CAAC,CAAC;AACnD;;AAEA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAG;EAClC,MAAM,CAACC,cAAc,EAAEC,iBAAiB,CAAC,GACvCV,KAAK,CAACW,QAAQ,CAA4B,IAAI,CAAC;EACjD,MAAM,CAACC,OAAO,EAAEC,UAAU,CAAC,GAAGb,KAAK,CAACW,QAAQ,CAAC,IAAI,CAAC;EAClD,MAAM,CAACG,KAAK,EAAEC,QAAQ,CAAC,GAAGf,KAAK,CAACW,QAAQ,CAAe,IAAI,CAAC;EAE5DX,KAAK,CAACgB,SAAS,CAAC,MAAM;IACpB,IAAIC,OAAO,GAAG,IAAI;IAElB,eAAeC,mBAAmBA,CAAA,EAAG;MACnC,IAAI;QACF,MAAMC,IAAI,GAAG,MAAMjB,iBAAiB,CAAC,CAAC;QACtC,IAAIe,OAAO,EAAE;UACXP,iBAAiB,CAACS,IAAI,CAAC;UACvBJ,QAAQ,CAAC,IAAI,CAAC;QAChB;MACF,CAAC,CAAC,OAAOK,GAAG,EAAE;QACZ,IAAIH,OAAO,EAAE;UACXF,QAAQ,CAACK,GAAG,YAAYC,KAAK,GAAGD,GAAG,GAAG,IAAIC,KAAK,CAAC,eAAe,CAAC,CAAC;QACnE;MACF,CAAC,SAAS;QACR,IAAIJ,OAAO,EAAE;UACXJ,UAAU,CAAC,KAAK,CAAC;QACnB;MACF;IACF;IAEAK,mBAAmB,CAAC,CAAC;IAErB,OAAO,MAAM;MACXD,OAAO,GAAG,KAAK;IACjB,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO;IAAER,cAAc;IAAEG,OAAO;IAAEE;EAAM,CAAC;AAC3C;AAEA,eAAe;EACbZ,iBAAiB;EACjBK,mBAAmB;EACnBC;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["Platform","React","NavigationModeModule","getNavigationMode","OS","Promise","resolve","type","isGestureNavigation","navigationBarHeight","getNavigationBarHeight","useNavigationMode","navigationMode","setNavigationMode","useState","loading","setLoading","error","setError","useEffect","mounted","fetchNavigationMode","mode","err","Error"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,OAAOC,KAAK,MAAM,OAAO;AACzB,OAAOC,oBAAoB,MAEpB,2BAAwB;AAI/B;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAgC;EAC/D;EACA,IAAIH,QAAQ,CAACI,EAAE,KAAK,KAAK,IAAIF,oBAAoB,KAAK,IAAI,EAAE;IAC1D;IACA,OAAOG,OAAO,CAACC,OAAO,CAAC;MACrBC,IAAI,EAAE,SAAS;MACfC,mBAAmB,EAAE,IAAI;MACzBC,mBAAmB,EAAE,CAAC,CAAE;IAC1B,CAAC,CAAC;EACJ;;EAEA;EACA,OAAOP,oBAAoB,CAACC,iBAAiB,CAAC,CAAC;AACjD;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASK,mBAAmBA,CAAA,EAAqB;EACtD;EACA,IAAIR,QAAQ,CAACI,EAAE,KAAK,KAAK,IAAIF,oBAAoB,KAAK,IAAI,EAAE;IAC1D;IACA,OAAOG,OAAO,CAACC,OAAO,CAAC,IAAI,CAAC;EAC9B;;EAEA;EACA,OAAOJ,oBAAoB,CAACM,mBAAmB,CAAC,CAAC;AACnD;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASE,sBAAsBA,CAAA,EAAoB;EACxD;EACA,IAAIV,QAAQ,CAACI,EAAE,KAAK,KAAK,IAAIF,oBAAoB,KAAK,IAAI,EAAE;IAC1D;IACA,OAAOG,OAAO,CAACC,OAAO,CAAC,CAAC,CAAC;EAC3B;;EAEA;EACA,OAAOJ,oBAAoB,CAACQ,sBAAsB,CAAC,CAAC;AACtD;;AAEA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAG;EAClC,MAAM,CAACC,cAAc,EAAEC,iBAAiB,CAAC,GACvCZ,KAAK,CAACa,QAAQ,CAA4B,IAAI,CAAC;EACjD,MAAM,CAACC,OAAO,EAAEC,UAAU,CAAC,GAAGf,KAAK,CAACa,QAAQ,CAAC,IAAI,CAAC;EAClD,MAAM,CAACG,KAAK,EAAEC,QAAQ,CAAC,GAAGjB,KAAK,CAACa,QAAQ,CAAe,IAAI,CAAC;EAE5Db,KAAK,CAACkB,SAAS,CAAC,MAAM;IACpB,IAAIC,OAAO,GAAG,IAAI;IAElB,eAAeC,mBAAmBA,CAAA,EAAG;MACnC,IAAI;QACF,MAAMC,IAAI,GAAG,MAAMnB,iBAAiB,CAAC,CAAC;QACtC,IAAIiB,OAAO,EAAE;UACXP,iBAAiB,CAACS,IAAI,CAAC;UACvBJ,QAAQ,CAAC,IAAI,CAAC;QAChB;MACF,CAAC,CAAC,OAAOK,GAAG,EAAE;QACZ,IAAIH,OAAO,EAAE;UACXF,QAAQ,CAACK,GAAG,YAAYC,KAAK,GAAGD,GAAG,GAAG,IAAIC,KAAK,CAAC,eAAe,CAAC,CAAC;QACnE;MACF,CAAC,SAAS;QACR,IAAIJ,OAAO,EAAE;UACXJ,UAAU,CAAC,KAAK,CAAC;QACnB;MACF;IACF;IAEAK,mBAAmB,CAAC,CAAC;IAErB,OAAO,MAAM;MACXD,OAAO,GAAG,KAAK;IACjB,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO;IAAER,cAAc;IAAEG,OAAO;IAAEE;EAAM,CAAC;AAC3C;AAEA,eAAe;EACbd,iBAAiB;EACjBK,mBAAmB;EACnBE,sBAAsB;EACtBC;AACF,CAAC","ignoreList":[]}
@@ -3,11 +3,13 @@ export interface NavigationModeInfo {
3
3
  type: '3_button' | '2_button' | 'gesture' | 'unknown';
4
4
  isGestureNavigation: boolean;
5
5
  interactionMode?: number;
6
+ navigationBarHeight?: number;
6
7
  }
7
8
  export interface Spec extends TurboModule {
8
9
  getNavigationMode(): Promise<NavigationModeInfo>;
9
10
  isGestureNavigation(): Promise<boolean>;
11
+ getNavigationBarHeight(): Promise<number>;
10
12
  }
11
- declare const _default: Spec;
12
- export default _default;
13
+ declare const NativeModule: Spec | null;
14
+ export default NativeModule;
13
15
  //# sourceMappingURL=NativeNavigationMode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeNavigationMode.d.ts","sourceRoot":"","sources":["../../../src/NativeNavigationMode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IACtD,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACzC;;AAED,wBAAwE"}
1
+ {"version":3,"file":"NativeNavigationMode.d.ts","sourceRoot":"","sources":["../../../src/NativeNavigationMode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IACtD,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAID,QAAA,MAAM,YAAY,aAGR,CAAC;AAEX,eAAe,YAAY,CAAC"}
@@ -10,6 +10,11 @@ export declare function getNavigationMode(): Promise<NavigationModeInfo>;
10
10
  * @returns Promise<boolean> - true if gesture navigation is active
11
11
  */
12
12
  export declare function isGestureNavigation(): Promise<boolean>;
13
+ /**
14
+ * Get the navigation bar height in dp
15
+ * @returns Promise<number> - navigation bar height in dp
16
+ */
17
+ export declare function getNavigationBarHeight(): Promise<number>;
13
18
  /**
14
19
  * Hook for React components to get navigation mode
15
20
  */
@@ -21,6 +26,7 @@ export declare function useNavigationMode(): {
21
26
  declare const _default: {
22
27
  readonly getNavigationMode: typeof getNavigationMode;
23
28
  readonly isGestureNavigation: typeof isGestureNavigation;
29
+ readonly getNavigationBarHeight: typeof getNavigationBarHeight;
24
30
  readonly useNavigationMode: typeof useNavigationMode;
25
31
  };
26
32
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,OAA6B,EAC3B,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAEnC;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAU/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOtD;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;EAmChC;;;;;;AAED,wBAIW"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,OAA6B,EAC3B,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAEnC;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAa/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAStD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CASxD;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;EAmChC;;;;;;;AAED,wBAKW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-navigation-mode",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Detect Android navigation mode (3-button, 2-button, or gesture)",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -74,8 +74,8 @@
74
74
  "@eslint/js": "^9.22.0",
75
75
  "@evilmartians/lefthook": "^1.5.0",
76
76
  "@react-native-community/cli": "15.0.0-alpha.2",
77
- "@react-native/babel-preset": "0.79.2",
78
- "@react-native/eslint-config": "^0.78.0",
77
+ "@react-native/babel-preset": "0.79.5",
78
+ "@react-native/eslint-config": "0.79.5",
79
79
  "@release-it/conventional-changelog": "^9.0.2",
80
80
  "@semantic-release/changelog": "^6.0.3",
81
81
  "@semantic-release/git": "^10.0.1",
@@ -91,7 +91,7 @@
91
91
  "jest": "^29.7.0",
92
92
  "prettier": "^3.0.3",
93
93
  "react": "19.0.0",
94
- "react-native": "0.79.3",
94
+ "react-native": "0.79.5",
95
95
  "react-native-builder-bob": "^0.40.11",
96
96
  "release-it": "^17.10.0",
97
97
  "semantic-release": "^24.1.0",
@@ -1,15 +1,24 @@
1
1
  import type { TurboModule } from 'react-native';
2
- import { TurboModuleRegistry } from 'react-native';
2
+ import { TurboModuleRegistry, Platform } from 'react-native';
3
3
 
4
4
  export interface NavigationModeInfo {
5
5
  type: '3_button' | '2_button' | 'gesture' | 'unknown';
6
6
  isGestureNavigation: boolean;
7
7
  interactionMode?: number;
8
+ navigationBarHeight?: number;
8
9
  }
9
10
 
10
11
  export interface Spec extends TurboModule {
11
12
  getNavigationMode(): Promise<NavigationModeInfo>;
12
13
  isGestureNavigation(): Promise<boolean>;
14
+ getNavigationBarHeight(): Promise<number>;
13
15
  }
14
16
 
15
- export default TurboModuleRegistry.getEnforcing<Spec>('NavigationMode');
17
+ // Only get the native module on Android
18
+ // On iOS, we'll handle everything in JavaScript
19
+ const NativeModule =
20
+ Platform.OS === 'android'
21
+ ? TurboModuleRegistry.getEnforcing<Spec>('NavigationMode')
22
+ : null;
23
+
24
+ export default NativeModule;
package/src/index.tsx CHANGED
@@ -11,14 +11,17 @@ export type { NavigationModeInfo };
11
11
  * Returns navigation type, interaction mode, and device info
12
12
  */
13
13
  export function getNavigationMode(): Promise<NavigationModeInfo> {
14
- if (Platform.OS === 'ios') {
14
+ // null check is redundant as it's always null for iOS but it's there to satisfy TypeScript
15
+ if (Platform.OS === 'ios' || NavigationModeModule === null) {
15
16
  // iOS always uses gesture navigation (no 3-button navigation exists)
16
17
  return Promise.resolve({
17
18
  type: 'gesture',
18
19
  isGestureNavigation: true,
20
+ navigationBarHeight: 0, // iOS doesn't have a navigation bar like Android
19
21
  });
20
22
  }
21
23
 
24
+ // Only call native module on Android
22
25
  return NavigationModeModule.getNavigationMode();
23
26
  }
24
27
 
@@ -27,14 +30,31 @@ export function getNavigationMode(): Promise<NavigationModeInfo> {
27
30
  * @returns Promise<boolean> - true if gesture navigation is active
28
31
  */
29
32
  export function isGestureNavigation(): Promise<boolean> {
30
- if (Platform.OS === 'ios') {
33
+ // null check is redundant as it's always null for iOS but it's there to satisfy TypeScript
34
+ if (Platform.OS === 'ios' || NavigationModeModule === null) {
31
35
  // iOS always uses gesture navigation
32
36
  return Promise.resolve(true);
33
37
  }
34
38
 
39
+ // Only call native module on Android
35
40
  return NavigationModeModule.isGestureNavigation();
36
41
  }
37
42
 
43
+ /**
44
+ * Get the navigation bar height in dp
45
+ * @returns Promise<number> - navigation bar height in dp
46
+ */
47
+ export function getNavigationBarHeight(): Promise<number> {
48
+ // null check is redundant as it's always null for iOS but it's there to satisfy TypeScript
49
+ if (Platform.OS === 'ios' || NavigationModeModule === null) {
50
+ // iOS doesn't have a navigation bar like Android
51
+ return Promise.resolve(0);
52
+ }
53
+
54
+ // Only call native module on Android
55
+ return NavigationModeModule.getNavigationBarHeight();
56
+ }
57
+
38
58
  /**
39
59
  * Hook for React components to get navigation mode
40
60
  */
@@ -78,5 +98,6 @@ export function useNavigationMode() {
78
98
  export default {
79
99
  getNavigationMode,
80
100
  isGestureNavigation,
101
+ getNavigationBarHeight,
81
102
  useNavigationMode,
82
103
  } as const;
@@ -1,28 +0,0 @@
1
- #import "NavigationMode.h"
2
-
3
- @implementation NavigationMode
4
-
5
- RCT_EXPORT_MODULE()
6
-
7
- - (void)getNavigationMode:(RCTPromiseResolveBlock)resolve
8
- reject:(RCTPromiseRejectBlock)reject {
9
- // iOS always uses gesture navigation - handled in TypeScript
10
- NSDictionary *result = @{
11
- @"type": @"gesture",
12
- @"isGestureNavigation": @YES
13
- };
14
- resolve(result);
15
- }
16
-
17
- - (void)isGestureNavigation:(RCTPromiseResolveBlock)resolve
18
- reject:(RCTPromiseRejectBlock)reject {
19
- // iOS always uses gesture navigation - handled in TypeScript
20
- resolve(@YES);
21
- }
22
-
23
- - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
24
- (const facebook::react::ObjCTurboModule::InitParams &)params {
25
- return std::make_shared<facebook::react::NativeNavigationModeSpecJSI>(params);
26
- }
27
-
28
- @end