anoa-react-native-theme
TypeScript icon, indicating that this package has built-in type declarations

0.2.1 • Public • Published

Anoa React Native Theme

Theme and stylesheet manager for ReactNative

Installation

npm i anoa-react-native-theme

Usage

Create Theme(s)

Default Theme

import { createTheme } from 'anoa-react-native-theme'
 
export const BlueTheme = createTheme(
  // define all theme variables here
  // like color, thickness, radius, etc.
  {
    color: {
      primary: 'blue',
      secondary: 'yellow'
    },
    border: {
      thick: 1,
      bold: 10
    }
  },
 
  // define named styles using defined theme variables
  vars => ({
    container: {
      padding: 40,
      backgroundColor: vars.color.primary
    },
    button: {
      borderWidth: vars.border.thick,
      backgroundColor: vars.color.secondary
    }
  })
)

Create another theme from Default Theme / child theme (optional)

export const RedTheme = BlueTheme.extend(
  // override default theme variables
  {
    color: {
      primary: 'red',
      secondary: 'green'
    }
  },
 
  // override default theme style
  vars => ({
    container: {
      padding: 80
    },
    button: {
      borderWidth: vars.border.bold
    }
  })
)

Create Theme Context

import { ThemeContext } from 'anoa-react-native-theme'
 
export const AppTheme = new ThemeContext(BlueTheme, {
  red: RedTheme
 
  // define the rest themes you have, eg:
  // green: GreenTheme,
  // yellow: YellowTheme
  // etc ...
 
  // Notice: all themes defined here must created/extended
  // from default theme or child of default theme.
})

Theme Provider

We are using React Context to provide themes accessibility.

The AppTheme you've created above contains Provider and Consumer property. You have to wrap your root component with Provider to make themes available in every component inside.

export default class App extends Component {
  // ...
  render() {
    return (
      <AppTheme.Provider
        // optional prop to get default theme
        getDefault={async () => {
          // do async operation to get selected theme
          // should returns 'default' or the object key of themes
          // you've defined in the context (eg: 'red' for RedTheme)
          return await MyFancyStorage.getTheme()
        }}
        // optional prop, the event that listen when theme get changed
        onChange={async key => {
          // key returns the 'default' or the object key of themes
          await MyFancyStorage.setTheme(key)
        }}
      >
        <View style={styles.container}>
          <AwesomeComponent />
        </View>
      </AppTheme.Provider>
    )
  }
  // ...
}

Consuming Theme

To consume theme you need to wrap the component with Consumer. Wrapping with Consumer can also be done by using withTheme HOC or withThemeClass class decorator.

Consume theme using AppTheme.Consumer

The Consumer resulting function component with one parameter called theme consists of:

  • vars -- represents current theme variables.

  • styles -- represents current theme named stylesheets.

  • change - a function to change theme.

For more detail, have a look this example:

export class AwesomeComponent extends React.Component {
  // ...
 
  public render() {
    return (
      <AppTheme.Consumer>
        {({ theme: { vars, styles, change } }) => (
          <View style={styles.container}>
            <Button
              style={styles.button}
              color={vars.color.primary}
              title="Switch to Red Theme"
              onPress={async () => {
                change('red')
              }}
            />
 
            <Button
              style={theme.styles.button}
              title="Switch to Default Theme"
              onPress={async () => {
                change('default')
              }}
            />
          </View>
        )}
      </AppTheme.Consumer>
    )
  }
 
  // ...
}

Using withTheme HOC

Use AppTheme.withTheme as HOC (Higher Order Component) that injects theme into your component.

export interface ProfileProps {
  firstName: string
  lastName: string
}
 
export const Profile = AppTheme.withTheme<ProfileProps>(
  ({ theme, firstName, lastName }) => (
    <View style={theme.styles.container}>
      <Text>{firstName}</Text>
      <Text>{lastName}</Text>
    </View>
  )
)

Using withThemeClass Decorator

If you are fans of class decorator, you can use AppTheme.withThemeClass class decorator to inject theme into your component class.

// Theme props injected into AppThemeProps (see explanation bellow).
// We make it Partial as we won't this props to be required when
// using this component in other component.
export interface LoginProps extends Partial<AppThemeProps> {
  // some props owned by Login component
}
 
@AppTheme.withThemeClass()
export class Login extends React.Component<LoginProps> {
  constructor(props: LoginProps) {
    super(props)
  }
 
  public render() {
    // consume theme props, cast it as Required props
    // as it always injected here.
    const { theme } = this.props as Required<LoginProps>
 
    return (
      <View style={theme.styles.button}>
        <Text style={{ color: theme.vars.color.primary }}>Login</Text>
      </View>
    )
  }
}

AppThemeProps

For typing convenience we need AppThemeProps interface that provides app theme props accessibility. Creating this interface is easily done by:

import { ThemeContextProps } from 'anoa-react-native-theme'
 
// Use the default theme type (BlueTheme) to presents props values.
export type AppThemeProps = ThemeContextProps<typeof BlueTheme>

Create local stylesheet

The AppTheme also comes with createStyleSheet function that let you create custom local styles for your component using theme variables.

@AppTheme.withThemeClass()
export class About extends React.Component<AboutProps> {
  constructor(props: AboutProps) {
    super(props)
  }
 
  public render() {
    return (
      <View style={styles.container}>
        <Text>About</Text>
      </View>
    )
  }
}
 
// create stylesheet based on theme variables
const styles = AppTheme.createStyleSheet(vars => ({
  container: {
    backgroundColor: vars.color.primary,
    padding: 25
  }
}))

License

MIT

Readme

Keywords

Package Sidebar

Install

npm i anoa-react-native-theme

Weekly Downloads

1

Version

0.2.1

License

MIT

Unpacked Size

24.6 kB

Total Files

14

Last publish

Collaborators

  • budiadiono