UNPKG

react-native-navigation-mode

Version:

Detect Android navigation mode (3-button, 2-button, or gesture)

285 lines (204 loc) • 10.7 kB
# react-native-navigation-mode 🧭 Detect Android navigation mode (3-button, 2-button, or gesture navigation) with native precision using Turbo modules. [![npm version](https://img.shields.io/npm/v/react-native-navigation-mode)](https://badge.fury.io/js/react-native-navigation-mode) [![License](https://img.shields.io/github/license/JairajJangle/react-native-navigation-mode)](https://github.com/JairajJangle/react-native-navigation-mode/blob/main/LICENSE) [![Workflow Status](https://github.com/JairajJangle/react-native-navigation-mode/actions/workflows/ci.yml/badge.svg)](https://github.com/JairajJangle/react-native-navigation-mode/actions/workflows/ci.yml) ![Android](https://img.shields.io/badge/-Android-555555?logo=android&logoColor=3DDC84) ![iOS](https://img.shields.io/badge/-iOS-555555?logo=apple&logoColor=white) [![GitHub issues](https://img.shields.io/github/issues/JairajJangle/react-native-navigation-mode)](https://github.com/JairajJangle/react-native-navigation-mode/issues?q=is%3Aopen+is%3Aissue) ![TS](https://img.shields.io/badge/TypeScript-strict_šŸ’Ŗ-blue) ![Turbo Module](https://img.shields.io/badge/Turbo%20Module-⚔-orange) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/react-native-navigation-mode) <table align="center"> <tr> <td align="center"><img src=".github/assets/buttons.png" alt="Visibility Sensor demo" height="600"></td> <td align="center"><img src=".github/assets/gesture.png" alt="Visibility Sensor demo" height="600"></td> </tr> </table> <div align="center"> <table> <tr> <td align="center"> <img src="https://img.shields.io/badge/3--Button-Navigation-blue?style=for-the-badge" alt="3-Button Navigation" /> <br /> <small>Traditional Android navigation</small> </td> <td align="center"> <img src="https://img.shields.io/badge/2--Button-Navigation-green?style=for-the-badge" alt="2-Button Navigation" /> <br /> <small>Home + Back buttons</small> </td> <td align="center"> <img src="https://img.shields.io/badge/Gesture-Navigation-purple?style=for-the-badge" alt="Gesture Navigation" /> <br /> <small>Swipe-based navigation</small> </td> </tr> </table> </div> --- ## šŸ¤” Why This Library? 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: ### āŒ Common Bad Approaches - **Screen dimension calculations** - Breaks on different screen sizes and orientations - **Safe area inset guessing** - Inconsistent across devices and Android versions - **Margin-based detection** - Fragile and depends on UI layout changes - **Manual device databases** - Impossible to maintain for all Android devices ### āœ… This Library's Solution This library uses **official Android APIs** to directly query the system's navigation configuration: - **`config_navBarInteractionMode`** - The actual system resource Android uses internally - **Settings.Secure provider** - Fallback method for reliable detection - **Zero guesswork** - No calculations, no assumptions, just direct system queries ### šŸš€ Critical for Edge-to-Edge Mode 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**: - **Edge-to-edge enforcement** - Android 16 will remove the opt-out entirely - **Expo SDK 53+** - New projects use edge-to-edge by default - **React Native 0.79+** - Built-in support for 16KB page size and edge-to-edge - **Safe area management** - Critical for preventing content overlap with system bars (especially noticeable in 3-button navigation mode). ### Real-World Impact ```typescript // Before: Unreliable dimension-based guessing const isGesture = screenHeight === windowHeight; // 😢 Breaks easily // After: Direct system detection const isGesture = await isGestureNavigation(); // šŸŽÆ Always accurate ``` **Perfect for:** - šŸŽØ Adaptive UI layouts based on navigation type - šŸ“± Bottom sheet positioning and safe areas - 🧭 Navigation-aware component design - šŸ”„ Edge-to-edge layout compatibility - šŸ“Š Analytics and user experience tracking ## ✨ Features - šŸŽÆ **Direct Native Detection** - No hacky workarounds or dimension-based guessing - ⚔ **Turbo Module** - Built with the latest React Native architecture - šŸ”„ **Real-time Detection** - Accurate navigation mode identification - šŸ“± **Cross Platform** - Android detection + iOS compatibility - šŸŽ£ **React Hooks** - Easy integration with `useNavigationMode()` - šŸ“¦ **Zero Dependencies** - Lightweight and performant - šŸ›”ļø **TypeScript** - Full type safety out of the box - ā†•ļø **Edge To Edge Support** - Full support for `react-native-edge-to-edge` ## Installation Using yarn: ```sh yarn add react-native-navigation-mode ``` Using npm: ```sh npm install react-native-navigation-mode ``` ### For React Native CLI Auto-linking handles setup automatically for React Native 0.60+. ## Usage ### Quick Check ```typescript import { isGestureNavigation } from 'react-native-navigation-mode'; // Simple boolean check const isGesture = await isGestureNavigation(); console.log('Gesture navigation:', isGesture); // true/false ``` ### Detailed Information ```typescript import { getNavigationMode } from 'react-native-navigation-mode'; // Get comprehensive navigation info const navInfo = await getNavigationMode(); console.log('Navigation type:', navInfo.type); // '3_button', '2_button', 'gesture', or 'unknown' ``` ### React Hook (Recommended) ```typescript import React from 'react'; import { View, Text } from 'react-native'; import { useNavigationMode } from 'react-native-navigation-mode'; export default function NavigationInfo() { const { navigationMode, loading, error } = useNavigationMode(); if (loading) return <Text>Detecting navigation mode...</Text>; if (error) return <Text>Error: {error.message}</Text>; return ( <View> <Text>Navigation Type: {navigationMode?.type}</Text> <Text>Gesture Navigation: {navigationMode?.isGestureNavigation ? 'Yes' : 'No'}</Text> </View> ); } ``` ### Conditional UI Rendering ```typescript import React from 'react'; import { View } from 'react-native'; import { useNavigationMode } from 'react-native-navigation-mode'; export default function AdaptiveUI() { const { navigationMode } = useNavigationMode(); return ( <View style={{ paddingBottom: navigationMode?.isGestureNavigation ? 34 : 48 // Adjust for gesture nav }} > {/* Your content */} </View> ); } ``` ## API Reference ### Functions #### `getNavigationMode(): Promise<NavigationModeInfo>` Returns comprehensive navigation mode information. #### `isGestureNavigation(): Promise<boolean>` Quick check if device is using gesture navigation. ### Hooks #### `useNavigationMode(): { navigationMode, loading, error }` React hook for navigation mode detection with loading and error states. ### Types #### `NavigationModeInfo` | Property | Type | Description | | ------------------- | ---------------------------------------------- | ------------------------------------------------ | | type | `'3_button' \| '2_button' \| 'gesture' \| 'unknown'` | Navigation mode type | | isGestureNavigation | `boolean` | Whether gesture navigation is active | | interactionMode | `number \| undefined` | Raw Android interaction mode (0, 1, 2, or -1) | ## Platform Support | Platform | Support | Notes | |----------|---------|-------| | Android | āœ… Full | Detects all navigation modes via native Android APIs | | iOS | āœ… Compatible | Always returns `gesture` (iOS uses gesture navigation) | ### Android Compatibility - **API 21+** - Basic navigation bar detection - **API 29+** - Full navigation mode detection (`config_navBarInteractionMode`) - **All versions** - Fallback detection methods included ## How It Works The library uses multiple detection methods for maximum accuracy: 1. **`config_navBarInteractionMode`** - Official Android configuration (API 29+) 2. **Settings Provider** - Checks `navigation_mode` system setting 3. **Navigation Bar Detection** - Validates navigation bar presence 4. **Hardware Key Detection** - Fallback for older devices ### Navigation Mode Values | Android Mode | Type | Description | |--------------|------|-------------| | 0 | `3_button` | Traditional Android navigation (Back, Home, Recent) | | 1 | `2_button` | Two-button navigation (Back, Home) | | 2 | `gesture` | Full gesture navigation | | -1 | `unknown` | Could not determine navigation mode | ## Notes 1. šŸŽ **iOS Behavior** - iOS always returns `isGestureNavigation: true` since iOS doesn't have 3-button navigation 2. ⚔ **Performance** - Turbo module ensures minimal performance impact 3. šŸ”„ **Real-time** - Navigation mode is detected at call time, reflecting current device settings ## Troubleshooting ### Common Issues **"TurboModuleRegistry.getEnforcing(...) is not a function"** - Ensure you're using React Native 0.68+ with new architecture enabled - For older RN versions, the module will fallback gracefully **Always returns 'unknown' on Android** - Check if your device/emulator supports the navigation mode APIs - Some custom ROMs may not expose standard Android navigation settings ## Contributing See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. ## License MIT ## Support the project <p align="center" valign="center"> <a href="https://liberapay.com/FutureJJ/donate"> <img src="https://liberapay.com/assets/widgets/donate.svg" alt="LiberPay_Donation_Button" height="50" > </a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href=".github/assets/Jairaj_Jangle_Google_Pay_UPI_QR_Code.jpg"> <img src=".github/assets/upi.png" alt="UPI_Donation_Button" height="50" > </a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://www.paypal.com/paypalme/jairajjangle001/usd"> <img src=".github/assets/paypal_donate.png" alt="Paypal_Donation_Button" height="50" > </a> </p> ## ā¤ļø Thanks to - Module built using [create-react-native-library](https://github.com/callstack/react-native-builder-bob) - Readme is edited using [Typora](https://typora.io/) ---