Skip to content
40 changes: 40 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Installation & Setup

Version >= 12 requires React Native 0.73 / Expo 50 or newer (because of `unstable_enablePackageExports`). Use version 11 if you're on older version of RN / Expo.

Version >= 11 requires React Native 0.71 / Expo 48 or newer. Use version 10 if you're on older version of RN / Expo.

0. In your `tsconfig.json`, make sure you have [`"moduleResolution": "NodeNext"`](https://www.typescriptlang.org/tsconfig#moduleResolution) set. This is required for TS to see the typings exported via [package.json `exports`](https://reactnative.dev/blog/2023/06/21/package-exports-support).

1. add [`unstable_enablePackageExports`](https://metrobundler.dev/docs/configuration/#unstable_enablepackageexports-experimental) to your metro config (in `metro.config.js`). This field will default to `true` in a future version of RN so don't need to worry about it. This allows us to do some bundle size savings.

```js
// if you use Expo:
const config = getDefaultConfig(__dirname);
// unstable_enablePackageExports: true,
config.resolver.unstable_enablePackageExports = true;
module.exports = config;

// if you use bare React Native:
const config = {
resolver: {
unstable_enablePackageExports: true,
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```

2. `yarn add react-navigation-header-buttons`

3. Wrap your root component in a `HeaderButtons` Provider and pass the `stackType` prop (`'native' | 'js'`), as seen in [example's App.tsx](https://github.com/vonovak/react-navigation-header-buttons/blob/master/example/src/App.tsx).

There are 3 providers to choose from. You'll get an actionable warning if you don't use the right one. They are:

- `HeaderButtonsProvider` - the recommended one, which assumes you will use `overflowMenuPressHandlerDropdownMenu` on Android but not iOS (because that's the default behavior that the library ships with). Internally, this translates to `HeaderButtonsProviderDropdownMenu` on Android and `HeaderButtonsProviderPlain` on iOS.
- `HeaderButtonsProviderPlain` - use it if you're not planning to use `overflowMenuPressHandlerDropdownMenu` at all. It will shave a few kB off your bundle and Hermes won't have to parse some code that would not run in the end.
- `HeaderButtonsProviderDropdownMenu` - use it if you're planning to use `overflowMenuPressHandlerDropdownMenu` on all platforms.

Importing: `import { your_chosen_provider } from 'react-navigation-header-buttons/your_chosen_provider'`.

> [!IMPORTANT]
> The Provider must be placed as a descendant of `NavigationContainer`, otherwise this library will not receive the correct theme from React Navigation.
84 changes: 46 additions & 38 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
presets: ['module:@react-native/babel-preset'],
};
4 changes: 4 additions & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@ yarn-error.log
.metro-health-check*

# @end expo-cli

# generated by tests
requires-android.txt
requires-ios.txt
31 changes: 10 additions & 21 deletions example/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
const path = require('path');
const pak = require('../package.json');

module.exports = function (api) {
api.cache(true);

return {
presets: ['babel-preset-expo'],
plugins: [
[
'module-resolver',
{
extensions: ['.tsx', '.ts', '.js', '.json'],
alias: {
// For development, we want to alias the library to the source
[pak.name]: path.join(__dirname, '..', pak.source),
},
},
],
],
};
module.exports = {
presets: ['module:@react-native/babel-preset'],
};

// module.exports = function (api) {
// api.cache(true);
//
// return {
// presets: ['babel-preset-expo'],
// };
// };
17 changes: 12 additions & 5 deletions example/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const modules = Object.keys({

const defaultConfig = getDefaultConfig(__dirname);

module.exports = {
const config = {
...defaultConfig,

projectRoot: __dirname,
Expand All @@ -22,6 +22,7 @@ module.exports = {
// So we block them at the root, and alias them to the versions in example's node_modules
resolver: {
...defaultConfig.resolver,
unstable_enablePackageExports: true,

blockList: exclusionList(
modules.map(
Expand All @@ -30,9 +31,15 @@ module.exports = {
)
),

extraNodeModules: modules.reduce((acc, name) => {
acc[name] = path.join(__dirname, 'node_modules', name);
return acc;
}, {}),
extraNodeModules: modules.reduce(
(acc, name) => {
acc[name] = path.join(__dirname, 'node_modules', name);
return acc;
},
{
[pak.name]: root,
}
),
},
};
module.exports = config;
18 changes: 11 additions & 7 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,39 @@
"name": "example",
"version": "1.0.0",
"scripts": {
"start": "expo start --dev-client",
"start": "EXPO_METRO_UNSTABLE_ERRORS=1 expo start --dev-client -c",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"fix-deps": "npx expo install --check"
"fix-deps": "npx expo install --check",
"requires-ios": "yarn metro get-dependencies --entry-file App.js --platform ios --output requires-ios.txt",
"requires-android": "yarn metro get-dependencies --entry-file App.js --platform android --output requires-android.txt"
},
"dependencies": {
"@expo/react-native-action-sheet": "^4.0.1",
"@react-native-menu/menu": "^0.8.0",
"@react-native-menu/menu": "^0.9.1",
"@react-navigation/bottom-tabs": "^6.5.9",
"@react-navigation/native": "^6.1.6",
"@react-navigation/native-stack": "^6.9.12",
"@react-navigation/stack": "^6.3.16",
"expo": "~50.0.6",
"expo": "~50.0.17",
"expo-splash-screen": "~0.26.4",
"expo-status-bar": "~1.11.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.73.4",
"react-native": "0.73.6",
"react-native-gesture-handler": "~2.14.0",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "~3.29.0",
"react-native-web": "~0.19.6"
},
"resolutions": {
"@types/react": "18.2.79"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@expo/webpack-config": "~19.0.1",
"babel-loader": "^8.1.0",
"babel-plugin-module-resolver": "^4.1.0"
"babel-loader": "^8.1.0"
},
"private": true
}
8 changes: 4 additions & 4 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { useContext } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { HeaderButtonsProvider } from 'react-navigation-header-buttons';
import { HeaderButtonsProvider } from 'react-navigation-header-buttons/HeaderButtonsProvider';
// just for custom overflow menu onPress action
import { ActionSheetProvider } from '@expo/react-native-action-sheet';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import { StatusBar } from 'expo-status-bar';
import { ThemeContext, ThemeProvider } from './ThemeProvider';
import { screens } from './NavTypes';
Expand Down Expand Up @@ -46,7 +45,9 @@ const Tab = createBottomTabNavigator();
function TabbedApp() {
return (
//@ts-ignore
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Navigator
screenOptions={{ headerShown: false, tabBarIcon: () => null }}
>
<Tab.Screen name="Home" component={Body} />
<Tab.Screen
name="Settings"
Expand All @@ -62,7 +63,6 @@ const ThemedApp = () => {
return (
<NavigationContainer theme={theme}>
<StatusBar style="light" backgroundColor="darkgreen" />

<ActionSheetProvider>
<HeaderButtonsProvider stackType={stackType}>
<TabbedApp />
Expand Down
2 changes: 1 addition & 1 deletion example/src/screens/UsageDifferentFontFamilies.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function UsageDifferentFontFamilies({
<Item
title="settings-ion"
IconComponent={Ionicons}
iconName="ios-settings"
iconName="settings"
onPress={() => alert('ionicons settings')}
/>
<Item
Expand Down
2 changes: 1 addition & 1 deletion example/src/screens/UsageDisabled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function UsageDisabled({ navigation }: ScreenProps<'UsageDisabled'>) {
<HeaderButtons HeaderButtonComponent={DisableableHeaderButton}>
<Item
title="search"
iconName="ios-search"
iconName="search"
onPress={() => alert('search')}
disabled
/>
Expand Down
2 changes: 1 addition & 1 deletion example/src/screens/UsageNativeMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function UsageNativeMenu({

return (
<ScreenBody>
<View style={{ height: 500 }} />
<View style={{ height: 250 }} />

<MenuView
title="Menu Title"
Expand Down
2 changes: 1 addition & 1 deletion example/src/screens/UsageWithIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {
Item,
HiddenItem,
OverflowMenu,
Divider,
ItemProps,
HiddenItemProps,
Divider,
} from 'react-navigation-header-buttons';
import type { ScreenProps } from '../NavTypes';
import { MaterialHeaderButton } from '../components/MaterialHeaderButton';
Expand Down
2 changes: 1 addition & 1 deletion example/src/screens/UsageWithOverflowComplex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { View, Text } from 'react-native';
import {
HiddenItem,
OverflowMenu,
Divider,
overflowMenuPressHandlerActionSheet,
overflowMenuPressHandlerPopupMenu,
overflowMenuPressHandlerDropdownMenu,
HiddenItemProps,
OnOverflowMenuPressParams,
useOverflowMenu,
Divider,
} from 'react-navigation-header-buttons';
import type { ScreenProps } from '../NavTypes';
import { Button } from '../components/PaddedButton';
Expand Down
Loading