@busfor/react-native-navigation-appearance
TypeScript icon, indicating that this package has built-in type declarations

1.3.1 • Public • Published

react-native-navigation-appearance

npm npm (tag)


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

  1. 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',
  },
})
  1. 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,
    },
  },
}))
  1. Add ThemeProvider to register and init module with defaultOptions 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({ ... })
})
  1. Create screen options using createOptions and defaultOptions 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,
      },
    },
  })
)
  1. 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',
  },
}))
  1. Use useThemedOptions, initialOptions to define screen options and use useStyles 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

  1. 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()
  1. 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`, () => {
    ...
  })
})

Package Sidebar

Install

npm i @busfor/react-native-navigation-appearance

Weekly Downloads

1

Version

1.3.1

License

MIT

Unpacked Size

5.45 MB

Total Files

119

Last publish

Collaborators

  • i.sokolovskii
  • sorokin0andrey