@busfor/react-native-navigation-appearance
v1.3.1
Published
Appearance Module built on top of wix/react-native-navigation
Downloads
24
Readme
react-native-navigation-appearance
Dependecies
Make sure that your are using supported versions of react-native-navigation and react-native:
| 1.x | | ------------------------------------------------------ | | react-native-navigation >= 6.4.0; react-native: >=0.62 |
Installation
Android
1 Install dependencies
Make sure that you have installed @react-native-community/async-storage
dependency or install it using:
$ yarn add @react-native-community/async-storage
Install this module using:
$ yarn add @busfor/react-native-navigation-appearance
2 Update MainActivity.java
This file is located in android/app/src/main/java/com/<yourproject>/MainActivity.java
.
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+import com.busfor.rnnappearance.RNNAppearanceModuleKt;
public class MainActivity extends NavigationActivity {
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ RNNAppearanceModuleKt.setThemeResId(R.style.AppTheme);
+ }
}
3 Configure android styles.xml
This file is located in android/app/src/main/res/values/styles.xml
.
<resources>
+
+ <style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat.Light" />
<!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
+ <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:textColor">#000000</item>
</style>
</resources>
4 Create android night styles.xml
This file should be located in android/app/src/main/res/values-night/styles.xml
.
<resources>
<style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat" />
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:textColor">#FFFFFF</item>
</style>
</resources>
IOS
Make sure you don't have UIUserInterfaceStyle
in Info.plist
Usage
- Create a theme with dark and light appearances using
createTheme
function:
import { createTheme } from '@busfor/react-native-navigation-appearance'
export const theme = createTheme({
dark: {
backgroundColor: '#121212',
textColor: '#fff',
primaryColor: 'blue',
},
light: {
backgroundColor: '#fff',
textColor: '#121212',
primaryColor: 'red',
},
})
- Create default options using
createDefaultOptions
function:
import { createDefaultOptions, Appearance } from '@busfor/react-native-navigation-appearance'
import { theme } from './theme'
export const defaultOptions = createDefaultOptions(({ appearance }) => ({
statusBar: {
style: appearance === Appearance.dark ? 'light' : 'dark',
backgroundColor: theme[appearance].backgroundColor,
},
navigationBar: {
backgroundColor: theme[appearance].backgroundColor,
},
topBar: {
background: {
color: theme[appearance].backgroundColor,
},
title: {
color: theme[appearance].textColor,
},
},
}))
- Add
ThemeProvider
to register and init module withdefaultOptions
that we have created:
NOTE: Make sure that you are running initAppearanceModule
inside Navigation.events().registerAppLaunchedListener
callback and before Navigation.setRoot
function!
import { ThemeProvider, initAppearanceModule } from '@busfor/react-native-navigation-appearance'
Navigation.registerComponent(
'AppScreen',
() => (props) => (
<ThemeProvider>
<AppScreen {...props} />
</ThemeProvider>
),
() => AppScreen
)
Navigation.events().registerAppLaunchedListener(async () => {
await initAppearanceModule(defaultOptions)
Navigation.setRoot({ ... })
})
- Create screen options using
createOptions
anddefaultOptions
functions:
This file should be located in /AppScreen/options.js
import { createOptions } from '@busfor/react-native-navigation-appearance'
import { defaultOptions } from '../defaultOptions'
export default createOptions((props) =>
defaultOptions(props, {
// props contains the current appearance and passed props to the screen
topBar: {
title: {
text: props.appearance,
},
},
})
)
- Create styles using
createStyles
function:
This file should be located in /AppScreen/styles.js
import { createStyles } from '@busfor/react-native-navigation-appearance'
import { theme } from '../theme'
export default createStyles(({ appearance }) => ({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme[appearance].backgroundColor,
},
text: {
color: theme[appearance].textColor,
paddingVertical: 8,
textAlign: 'center',
},
}))
- Use
useThemedOptions
,initialOptions
to define screen options and useuseStyles
hook to provide styles:
This file should be located in /AppScreen/index.js
import React from 'react'
import { Text, SafeAreaView } from 'react-native'
import { useStyles, initialOptions, useThemedOptions } from '@busfor/react-native-navigation-appearance'
import stylesCreator from './styles'
import options from './options'
const AppScreen = ({ componentId }) => {
useThemedOptions({}, options, componentId)
const styles = useStyles(stylesCreator)
return (
<SafeAreaView style={styles.container}>
<Text>Hello world!</Text>
</SafeAreaView>
)
}
AppScreen.options = initialOptions(options)
export default AppScreen
Also you can open the example project to see how it works in the real case.
Manual appearance
You can set appearance manually using useThemeControls
hook:
import { useThemeControls, AppearanceMode } from '@busfor/react-native-navigation-appearance'
const App = () => {
const { currentApearanceMode, setAppearanceMode } = useThemeControls()
return (
<>
<Text>Current mode: {currentApearanceMode}</Text>
<Button title='Dark' onPress={() => setAppearanceMode(AppearanceMode.dark)} />
<Button title='Light' onPress={() => setAppearanceMode(AppearanceMode.light)} />
<Button title='System' onPress={() => setAppearanceMode(AppearanceMode.system)} />
</>
)
}
Other hooks
useAppearance
You can get current appearance using useAppearance
hook:
import { useAppearance, Appearance } from '@busfor/react-native-navigation-appearance'
const App = () => {
const appearance = useAppearance()
return <Text>Current appearance: {appearance}</Text>
}
useThemedValue
You can get any value for current appearance using useThemedValue
hook:
import { useThemedValue } from '@busfor/react-native-navigation-appearance'
const lightLogoSource = require('./lightLogo.png')
const darkLogoSource = require('./darkLogo.png')
const App = () => {
const logoSource = useThemedValue({ light: lightLogoSource, dark: darkLogoSource })
return <Image source={logoSource} />
}
Utils
appearanceSelect
With this function, you can select specific unique styles and options per appearance (like Platform.select
)
import { createOptions, appearanceSelect } from '@busfor/react-native-navigation-appearance'
import { defaultOptions } from '../defaultOptions'
export default createOptions((props) =>
defaultOptions(props, {
topBar: {
title: {
text: appearanceSelect(props.appearance, {
light: 'This is text for the light appearance',
dark: 'This is text for the dark appearance',
}),
},
},
})
)
Jest integration
- Update your Jest setup file:
import mockAsyncStorage from '@react-native-community/async-storage/jest/async-storage-mock'
import '@busfor/react-native-navigation-appearance/jest/rnn-appearance-mock'
jest.mock('@react-native-community/async-storage', () => mockAsyncStorage)
jest.useFakeTimers()
- Use
setDarkModeMock
in your test cases:
import { setDarkModeMock } from '@busfor/react-native-navigation-appearance'
describe('Theming', () => {
afterEach(() => {
setDarkModeMock(false)
})
it(`dark theme`, () => {
setDarkModeMock(true)
...
})s
it(`light theme`, () => {
...
})
})