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(
{
color: {
primary: 'blue',
secondary: 'yellow'
},
border: {
thick: 1,
bold: 10
}
},
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(
{
color: {
primary: 'red',
secondary: 'green'
}
},
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
})
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.
export interface LoginProps extends Partial<AppThemeProps> {
}
@AppTheme.withThemeClass()
export class Login extends React.Component<LoginProps> {
constructor(props: LoginProps) {
super(props)
}
public render() {
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'
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>
)
}
}
const styles = AppTheme.createStyleSheet(vars => ({
container: {
backgroundColor: vars.color.primary,
padding: 25
}
}))
License
MIT