react-native-navigation-mode 1.1.0 → 1.1.1
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.
- package/README.md +210 -128
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,58 +32,12 @@
|
|
|
32
32
|
</table>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
## 🤔 Why This Library?
|
|
38
|
-
|
|
39
|
-
Android devices can use different navigation modes, but detecting which one is active has been a major pain point for React Native developers. Most existing solutions rely on unreliable workarounds:
|
|
40
|
-
|
|
41
|
-
### ❌ Common Bad Approaches
|
|
42
|
-
|
|
43
|
-
- **Screen dimension calculations** - Breaks on different screen sizes and orientations
|
|
44
|
-
- **Safe area inset guessing** - Inconsistent across devices and Android versions
|
|
45
|
-
- **Margin-based detection** - Fragile and depends on UI layout changes
|
|
46
|
-
- **Manual device databases** - Impossible to maintain for all Android devices
|
|
47
|
-
|
|
48
|
-
### ✅ This Library's Solution
|
|
49
|
-
|
|
50
|
-
This library uses **official Android APIs** to directly query the system's navigation configuration:
|
|
51
|
-
|
|
52
|
-
- **`config_navBarInteractionMode`** - The actual system resource Android uses internally
|
|
53
|
-
- **Settings.Secure provider** - Fallback method for reliable detection
|
|
54
|
-
- **Zero guesswork** - No calculations, no assumptions, just direct system queries
|
|
55
|
-
|
|
56
|
-
### 🚀 Critical for Edge-to-Edge Mode
|
|
57
|
-
|
|
58
|
-
With Android 15 enforcing edge-to-edge display for apps targeting API 35 and Google mandating this for Play Store updates starting August 31, 2025, proper navigation detection is now **essential**:
|
|
35
|
+
------
|
|
59
36
|
|
|
60
|
-
|
|
61
|
-
- **Expo SDK 53+** - New projects use edge-to-edge by default
|
|
62
|
-
- **React Native 0.79+** - Built-in support for 16KB page size and edge-to-edge
|
|
63
|
-
- **Safe area management** - Critical for preventing content overlap with system bars (especially noticeable in 3-button navigation mode).
|
|
64
|
-
|
|
65
|
-
### Real-World Impact
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
// Before: Unreliable dimension-based guessing
|
|
69
|
-
const isGesture = screenHeight === windowHeight; // 😢 Breaks easily
|
|
70
|
-
|
|
71
|
-
// After: Direct system detection
|
|
72
|
-
const isGesture = await isGestureNavigation(); // 🎯 Always accurate
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
**Perfect for:**
|
|
76
|
-
|
|
77
|
-
- 🎨 Adaptive UI layouts based on navigation type
|
|
78
|
-
- 📱 Bottom sheet positioning and safe areas
|
|
79
|
-
- 🧭 Navigation-aware component design
|
|
80
|
-
- 🔄 Edge-to-edge layout compatibility
|
|
81
|
-
- 📊 Analytics and user experience tracking
|
|
82
|
-
|
|
83
|
-
## ✨ Features
|
|
37
|
+
## ✨ Key Features
|
|
84
38
|
|
|
85
39
|
- 🎯 **Direct Native Detection** - No hacky workarounds or dimension-based guessing
|
|
86
|
-
- ⚡ **Turbo Module** - Built
|
|
40
|
+
- ⚡ **Turbo Module** - Built for React Native New Architecture
|
|
87
41
|
- 🔄 **Real-time Detection** - Accurate navigation mode identification
|
|
88
42
|
- 📏 **Navigation Bar Height** - Get exact navigation bar height in dp for precise UI calculations
|
|
89
43
|
- 📱 **Cross Platform** - Android detection + iOS compatibility
|
|
@@ -92,7 +46,9 @@ const isGesture = await isGestureNavigation(); // 🎯 Always accurate
|
|
|
92
46
|
- 🛡️ **TypeScript** - Full type safety out of the box
|
|
93
47
|
- ↕️ **Edge To Edge Support** - Full support for `react-native-edge-to-edge`
|
|
94
48
|
|
|
95
|
-
##
|
|
49
|
+
## 🚀 Quick Start
|
|
50
|
+
|
|
51
|
+
### Installation
|
|
96
52
|
|
|
97
53
|
Using yarn:
|
|
98
54
|
|
|
@@ -106,124 +62,250 @@ Using npm:
|
|
|
106
62
|
npm install react-native-navigation-mode
|
|
107
63
|
```
|
|
108
64
|
|
|
109
|
-
|
|
65
|
+
> **Note:** Auto-linking should handle setup automatically for all newer RN versions.
|
|
110
66
|
|
|
111
|
-
|
|
67
|
+
---
|
|
112
68
|
|
|
113
|
-
|
|
69
|
+
### Basic Usage
|
|
114
70
|
|
|
115
|
-
|
|
71
|
+
```tsx
|
|
72
|
+
import { useNavigationMode } from 'react-native-navigation-mode';
|
|
116
73
|
|
|
117
|
-
|
|
118
|
-
|
|
74
|
+
export default function App() {
|
|
75
|
+
const { navigationMode, loading, error } = useNavigationMode();
|
|
119
76
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
77
|
+
if (loading) return (<Text>Detecting navigation mode...</Text>);
|
|
78
|
+
if (error) return (<Text>Error: {error.message}</Text>);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<View>
|
|
82
|
+
<Text>Navigation Type: {navigationMode?.type}</Text>
|
|
83
|
+
<Text>Gesture Navigation: {navigationMode?.isGestureNavigation ? 'Yes' : 'No'}</Text>
|
|
84
|
+
<Text>Navigation Bar Height: {navigationMode?.navigationBarHeight}dp</Text>
|
|
85
|
+
</View>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
123
88
|
```
|
|
124
89
|
|
|
125
|
-
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 🔧 API Reference
|
|
93
|
+
|
|
94
|
+
### React Hook (Recommended)
|
|
95
|
+
|
|
96
|
+
#### `useNavigationMode(): { navigationMode, loading, error }`
|
|
97
|
+
|
|
98
|
+
- Returned property types:
|
|
99
|
+
|
|
100
|
+
| Property | Type | Description |
|
|
101
|
+
| ------------- | ------------------------------ | ------------------------------------------------------------ |
|
|
102
|
+
| navigatioMode | `NavigationModeInfo` or `null` | All properties mentioned in [NavigationModeInfo](#navigationmodeinfo). |
|
|
103
|
+
| loading | `boolean` | Indicates if navigation mode info is being fetched. |
|
|
104
|
+
| error | `Error` | Typescript error object containing the cause of the error. |
|
|
105
|
+
|
|
106
|
+
The easiest way to detect navigation mode with loading and error states.
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { useNavigationMode } from 'react-native-navigation-mode';
|
|
110
|
+
|
|
111
|
+
function MyComponent() {
|
|
112
|
+
const { navigationMode, loading, error } = useNavigationMode();
|
|
113
|
+
|
|
114
|
+
if (loading) return <Text>Loading...</Text>;
|
|
115
|
+
if (error) return <Text>Error: {error.message}</Text>;
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<View>
|
|
119
|
+
<Text>Navigation Type: {navigationMode?.type}</Text>
|
|
120
|
+
<Text>Is Gesture: {navigationMode?.isGestureNavigation ? 'Yes' : 'No'}</Text>
|
|
121
|
+
<Text>Bar Height: {navigationMode?.navigationBarHeight}dp</Text>
|
|
122
|
+
</View>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Functions
|
|
128
|
+
|
|
129
|
+
#### `getNavigationMode(): Promise<`[NavigationModeInfo](#navigationmodeinfo)`>`
|
|
130
|
+
|
|
131
|
+
Returns comprehensive navigation mode information.
|
|
126
132
|
|
|
127
133
|
```typescript
|
|
128
134
|
import { getNavigationMode } from 'react-native-navigation-mode';
|
|
129
135
|
|
|
130
|
-
// Get comprehensive navigation info
|
|
131
136
|
const navInfo = await getNavigationMode();
|
|
132
137
|
console.log('Navigation type:', navInfo.type); // '3_button', '2_button', 'gesture', or 'unknown'
|
|
133
138
|
```
|
|
134
139
|
|
|
135
|
-
|
|
140
|
+
#### `isGestureNavigation(): Promise<boolean>`
|
|
141
|
+
|
|
142
|
+
Quick check if device is using gesture navigation.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { isGestureNavigation } from 'react-native-navigation-mode';
|
|
146
|
+
|
|
147
|
+
const isGesture = await isGestureNavigation();
|
|
148
|
+
console.log('Gesture navigation:', isGesture); // true/false
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### `getNavigationBarHeight(): Promise<number>`
|
|
152
|
+
|
|
153
|
+
Returns the navigation bar height in density-independent pixels (dp).
|
|
136
154
|
|
|
137
155
|
```typescript
|
|
138
156
|
import { getNavigationBarHeight } from 'react-native-navigation-mode';
|
|
139
157
|
|
|
140
|
-
// Get navigation bar height in dp
|
|
141
158
|
const height = await getNavigationBarHeight();
|
|
142
159
|
console.log('Navigation bar height:', height); // number (dp)
|
|
143
160
|
```
|
|
144
161
|
|
|
145
|
-
###
|
|
162
|
+
### Types
|
|
146
163
|
|
|
147
|
-
|
|
148
|
-
import React from 'react';
|
|
149
|
-
import { View, Text } from 'react-native';
|
|
150
|
-
import { useNavigationMode } from 'react-native-navigation-mode';
|
|
164
|
+
#### `NavigationModeInfo`
|
|
151
165
|
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
| Property | Type | Description |
|
|
167
|
+
| ------------------- | ----------------------------------------------------------- | --------------------------------------------------------- |
|
|
168
|
+
| type | `'3_button'` or `'2_button'` or `'gesture'` or `'unknown'` | 4 possible Android navigation modes that can be detected. |
|
|
169
|
+
| isGestureNavigation | `boolean` | Whether gesture navigation is active. |
|
|
170
|
+
| interactionMode | `number` or `undefined` | See [Navigation Mode Values](#navigation-mode-values) |
|
|
171
|
+
| navigationBarHeight | `number` or `undefined` | Navigation bar height in density-independent pixels (dp). |
|
|
154
172
|
|
|
155
|
-
|
|
156
|
-
|
|
173
|
+
### Navigation Mode Values
|
|
174
|
+
|
|
175
|
+
| Android Mode | Type | Description |
|
|
176
|
+
| ------------ | ---------- | --------------------------------------------------- |
|
|
177
|
+
| 0 | `3_button` | Traditional Android navigation (Back, Home, Recent) |
|
|
178
|
+
| 1 | `2_button` | Two-button navigation (Back, Home) |
|
|
179
|
+
| 2 | `gesture` | Full gesture navigation |
|
|
180
|
+
| -1 | `unknown` | Could not determine navigation mode |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 💡 Usage Examples
|
|
185
|
+
|
|
186
|
+
### Adaptive UI Layout
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { useNavigationMode } from 'react-native-navigation-mode';
|
|
190
|
+
|
|
191
|
+
export default function AdaptiveUI() {
|
|
192
|
+
const { navigationMode } = useNavigationMode();
|
|
157
193
|
|
|
158
194
|
return (
|
|
159
|
-
<View
|
|
160
|
-
|
|
161
|
-
|
|
195
|
+
<View
|
|
196
|
+
style={{
|
|
197
|
+
// paddingBottom using real navigation bar height
|
|
198
|
+
paddingBottom: navigationMode?.navigationBarHeight || 0,
|
|
199
|
+
}}>
|
|
200
|
+
{/* Your content */}
|
|
162
201
|
</View>
|
|
163
202
|
);
|
|
164
203
|
}
|
|
165
204
|
```
|
|
166
205
|
|
|
167
|
-
### Conditional
|
|
206
|
+
### Conditional Rendering
|
|
168
207
|
|
|
169
|
-
```
|
|
170
|
-
import React from 'react';
|
|
171
|
-
import { View } from 'react-native';
|
|
208
|
+
```tsx
|
|
172
209
|
import { useNavigationMode } from 'react-native-navigation-mode';
|
|
173
210
|
|
|
174
|
-
export default function
|
|
211
|
+
export default function ConditionalUI() {
|
|
175
212
|
const { navigationMode } = useNavigationMode();
|
|
176
213
|
|
|
177
214
|
return (
|
|
178
|
-
<View
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
{
|
|
215
|
+
<View>
|
|
216
|
+
{navigationMode?.isGestureNavigation && (
|
|
217
|
+
<Text>Swipe gestures are available!</Text>
|
|
218
|
+
)}
|
|
219
|
+
|
|
220
|
+
{navigationMode?.type === '3_button' && (
|
|
221
|
+
<Text>Traditional navigation buttons detected</Text>
|
|
222
|
+
)}
|
|
184
223
|
</View>
|
|
185
224
|
);
|
|
186
225
|
}
|
|
187
226
|
```
|
|
188
227
|
|
|
189
|
-
|
|
228
|
+
### Manual Detection
|
|
190
229
|
|
|
191
|
-
|
|
230
|
+
```typescript
|
|
231
|
+
import {
|
|
232
|
+
getNavigationMode,
|
|
233
|
+
isGestureNavigation,
|
|
234
|
+
getNavigationBarHeight
|
|
235
|
+
} from 'react-native-navigation-mode';
|
|
236
|
+
|
|
237
|
+
const checkNavigation = async () => {
|
|
238
|
+
// Get all info at once
|
|
239
|
+
const navInfo = await getNavigationMode();
|
|
240
|
+
|
|
241
|
+
// Or get specific info
|
|
242
|
+
const isGesture = await isGestureNavigation();
|
|
243
|
+
const barHeight = await getNavigationBarHeight();
|
|
244
|
+
|
|
245
|
+
console.log('Navigation info:', navInfo);
|
|
246
|
+
console.log('Is gesture:', isGesture);
|
|
247
|
+
console.log('Bar height:', barHeight);
|
|
248
|
+
};
|
|
249
|
+
```
|
|
192
250
|
|
|
193
|
-
|
|
251
|
+
---
|
|
194
252
|
|
|
195
|
-
|
|
253
|
+
## 🤔 Why This Library?
|
|
196
254
|
|
|
197
|
-
|
|
255
|
+
Android devices can use different navigation modes, but detecting which one is active has been a major pain point for React Native developers. Most existing solutions rely on unreliable workarounds:
|
|
198
256
|
|
|
199
|
-
|
|
257
|
+
### ❌ Common Bad Approaches
|
|
200
258
|
|
|
201
|
-
|
|
259
|
+
- **Screen dimension calculations** - Breaks on different screen sizes and orientations
|
|
260
|
+
- **Safe area inset guessing** - Inconsistent across devices and Android versions
|
|
261
|
+
- **Margin-based detection** - Fragile and depends on UI layout changes
|
|
262
|
+
- **Manual device databases** - Impossible to maintain for all Android devices
|
|
202
263
|
|
|
203
|
-
|
|
264
|
+
### ✅ This Library's Solution
|
|
204
265
|
|
|
205
|
-
|
|
266
|
+
This library uses **official Android APIs** to directly query the system's navigation configuration:
|
|
206
267
|
|
|
207
|
-
|
|
268
|
+
- **`config_navBarInteractionMode`** - The actual system resource Android uses internally
|
|
269
|
+
- **Settings.Secure provider** - Fallback method for reliable detection
|
|
270
|
+
- **WindowInsets API** - Accurate navigation bar height detection
|
|
271
|
+
- **Zero guesswork** - No calculations, no assumptions, just direct system queries
|
|
208
272
|
|
|
209
|
-
|
|
273
|
+
### 🚀 Critical for Edge-to-Edge Mode
|
|
210
274
|
|
|
211
|
-
|
|
275
|
+
With Android 15 enforcing edge-to-edge display for apps targeting API 35 and Google mandating this for Play Store updates starting August 31, 2025, proper navigation detection is now **essential**:
|
|
212
276
|
|
|
213
|
-
|
|
277
|
+
- **Edge-to-edge enforcement** - Android 16 will remove the opt-out entirely
|
|
278
|
+
- **Expo SDK 53+** - New projects use edge-to-edge by default
|
|
279
|
+
- **React Native 0.79+** - Built-in support for 16KB page size and edge-to-edge
|
|
280
|
+
- **Safe area management** - Critical for preventing content overlap with system bars
|
|
214
281
|
|
|
215
|
-
|
|
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 |
|
|
282
|
+
### Real-World Impact
|
|
221
283
|
|
|
222
|
-
|
|
284
|
+
```typescript
|
|
285
|
+
// Before: Unreliable dimension-based guessing
|
|
286
|
+
const isGesture = screenHeight === windowHeight; // 😢 Breaks easily
|
|
223
287
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
288
|
+
// After: Direct system detection
|
|
289
|
+
const isGesture = await isGestureNavigation(); // 🎯 Always accurate
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Perfect for:**
|
|
293
|
+
|
|
294
|
+
- 🎨 Adaptive UI layouts based on navigation type
|
|
295
|
+
- 📱 Bottom sheet positioning and safe areas
|
|
296
|
+
- 🧭 Navigation-aware component design
|
|
297
|
+
- 🔄 Edge-to-edge layout compatibility
|
|
298
|
+
- 📊 Analytics and user experience tracking
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 🛠️ Technical Details
|
|
303
|
+
|
|
304
|
+
### Platform Support
|
|
305
|
+
|
|
306
|
+
| Platform | Support | Notes |
|
|
307
|
+
| -------- | ------------ | ------------------------------------------------------------ |
|
|
308
|
+
| Android | ✅ Full | Detects all navigation modes and navigation bar height via native Android APIs |
|
|
227
309
|
| iOS | ✅ Compatible | Always returns `gesture` and `navigationBarHeight: 0` (iOS uses gesture navigation) |
|
|
228
310
|
|
|
229
311
|
### Android Compatibility
|
|
@@ -234,51 +316,51 @@ React hook for navigation mode detection with loading and error states.
|
|
|
234
316
|
- **API 30+** - WindowInsets-based navigation bar height detection
|
|
235
317
|
- **API 24-29** - Resource-based navigation bar height fallback
|
|
236
318
|
|
|
237
|
-
|
|
319
|
+
### How It Works
|
|
238
320
|
|
|
239
321
|
The library uses multiple detection methods for maximum accuracy:
|
|
240
322
|
|
|
241
323
|
1. **`config_navBarInteractionMode`** - Official Android configuration (API 29+)
|
|
242
324
|
2. **Settings Provider** - Checks `navigation_mode` system setting
|
|
243
|
-
3. **
|
|
244
|
-
4. **
|
|
245
|
-
|
|
246
|
-
### Navigation Mode Values
|
|
247
|
-
|
|
248
|
-
| Android Mode | Type | Description |
|
|
249
|
-
|--------------|------|-------------|
|
|
250
|
-
| 0 | `3_button` | Traditional Android navigation (Back, Home, Recent) |
|
|
251
|
-
| 1 | `2_button` | Two-button navigation (Back, Home) |
|
|
252
|
-
| 2 | `gesture` | Full gesture navigation |
|
|
253
|
-
| -1 | `unknown` | Could not determine navigation mode |
|
|
325
|
+
3. **WindowInsets API** - Accurate navigation bar height detection (API 30+)
|
|
326
|
+
4. **Resource-based fallback** - Navigation bar height for older devices
|
|
254
327
|
|
|
255
|
-
|
|
328
|
+
### Performance Notes
|
|
256
329
|
|
|
257
|
-
1.
|
|
330
|
+
1. 🍎 **iOS Behavior** - iOS always returns `isGestureNavigation: true` and `navigationBarHeight: 0` since iOS doesn't have Android-style navigation bars
|
|
258
331
|
2. ⚡ **Performance** - Turbo module ensures minimal performance impact
|
|
259
332
|
3. 🔄 **Real-time** - Navigation mode is detected at call time, reflecting current device settings
|
|
260
333
|
|
|
261
|
-
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 🐛 Troubleshooting
|
|
262
337
|
|
|
263
338
|
### Common Issues
|
|
264
339
|
|
|
265
340
|
**"TurboModuleRegistry.getEnforcing(...) is not a function"**
|
|
341
|
+
|
|
266
342
|
- Ensure you're using React Native 0.68+ with new architecture enabled
|
|
267
343
|
- For older RN versions, the module will fallback gracefully
|
|
268
344
|
|
|
269
|
-
**Always returns 'unknown' on Android**
|
|
345
|
+
**Always returns `'unknown'` on Android**
|
|
346
|
+
|
|
270
347
|
- Check if your device/emulator supports the navigation mode APIs
|
|
271
348
|
- Some custom ROMs may not expose standard Android navigation settings
|
|
272
349
|
|
|
273
|
-
|
|
350
|
+
**Navigation bar height returns `0`**
|
|
351
|
+
|
|
352
|
+
- This is normal on devices without navigation bars (some tablets)
|
|
353
|
+
- On older Android versions, fallback detection may not work on all devices
|
|
354
|
+
|
|
355
|
+
## 🤝 Contributing
|
|
274
356
|
|
|
275
357
|
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
276
358
|
|
|
277
|
-
## License
|
|
359
|
+
## 📄 License
|
|
278
360
|
|
|
279
361
|
MIT
|
|
280
362
|
|
|
281
|
-
## Support the
|
|
363
|
+
## 💖 Support the Project
|
|
282
364
|
|
|
283
365
|
<p align="center" valign="center">
|
|
284
366
|
<a href="https://liberapay.com/FutureJJ/donate">
|
package/package.json
CHANGED