A theme abstraction over React Native StyleSheet. Thanks to @brankeye for great work this package forked from react-native-paint
Nested Theme Support
Install react-native-theme-provider
using yarn or npm.
yarn add @material-native-ui/theme-provider
npm install @material-native-ui/theme-provider
Wrap your App with a theme provider.
import React from "react";
import { ThemeProvider } from "@material-native-ui/theme-provider";
const defaultTheme = {
spacing: (spacing) => 8 * spacing,
}
const themes = {
light: {
...defaultTheme,
name: "light",
// some light theme properties
palette: {
default: 'rgba(100, 100, 100, .5)',
primary: '#40A3D0',
secondary: '#F5FF62',
}
},
dark: {
...defaultTheme,
name: "dark",
// some dark theme properties
palette: {
default: 'rgba(200, 200, 200, .5)',
primary: '#ffbb00',
secondary: '#ff6501',
}
}
};
class App extends React.Component {
state = {
currentTheme: themes.light
};
changeTheme = () => {
const { name } = this.state.currentTheme;
const nextTheme = name === "light" ? themes.dark : themes.light;
this.setState({
currentTheme: nextTheme
});
};
render() {
const { currentTheme } = this.state;
return (
<ThemeProvider theme={currentTheme}>
<App changeTheme={this.changeTheme} />
</ThemeProvider>
);
}
}
import React, { Component } from 'react'
import { Text, TouchableOpacity, View } from 'react-native'
import StyleSheet, { withStyles } from '@material-native-ui/theme-provider'
class App extends Component {
render() {
const { styles, changeTheme } = this.props
return (
<View style={styles.container}>
<Text style={styles.title}>Awesome Theme Provider</Text>
<View style={styles.actions}>
<TouchableOpacity style={styles.button} onPress={changeTheme('dark')}>
<Text>dark</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={changeTheme('light')}>
<Text>light</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
const style = StyleSheet.create(
(theme) => ({
container: {
flexGrow: 1,
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(2),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
},
title: {
marginBottom: theme.spacing(2),
},
button: {
borderRadius: 5,
justifyContent: 'center',
flexDirection: 'row',
backgroundColor: theme.palette.default,
},
actions: {
flexDirection: 'row',
},
})
)
export default withStyles(style)(App)
<ThemeProvider theme={themes.green}>
<Button color={'primary'} text="Submit" />
<ThemeProvider theme={themes.blue}>
<Button color={'primary'} text="Submit" />
</ThemeProvider>
<ThemeProvider theme={themes.light}>
import React, { Component } from 'react'
import StyleSheet, { useStyle } from '@material-native-ui/theme-provider'
const style = StyleSheet.create(
(theme) => ({
container: {
flexGrow: 1,
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(2),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
},
})
)
const App = function({ children }) {
const style = useStyle(style)
return (
<View style={styles.container}>
{/* content */}
</View>
)
}
import React, { Component } from 'react'
import { withTheme } from '@material-native-ui/theme-provider'
import {
NavigationContainer,
DefaultTheme,
} from '@react-navigation/native';
class App extends Component {
render() {
const { styles, theme } = this.props
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: theme.palette.primary,
},
};
return (
<NavigationContainer theme={MyTheme}>
{/* content */}
</NavigationContainer>
)
}
}
export default withTheme(App)
import React, { Component } from 'react'
import {
NavigationContainer,
DefaultTheme,
} from '@react-navigation/native';
const App = function({ children }) {
const theme = useTheme()
const MyTheme = { //send theme to react navigation theme
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: theme.palette.primary,
},
};
return (
<NavigationContainer theme={MyTheme}>
{/* content */}
</NavigationContainer>
)
}
import React, { Component } from 'react'
import { Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native'
import StyleSheet, { withStyles } from '@material-native-ui/theme-provider'
interface InterfaceStyles {
container: ViewStyle
button: ViewStyle
actions: ViewStyle
title: TextStyle
}
interface InterfaceProps {
styles: InterfaceStyles
changeTheme: Function
}
class App extends Component<InterfaceProps> {
render() {
const { styles, changeTheme } = this.props
return (
<View style={styles.container}>
// children
</View>
)
}
}
const style = StyleSheet.create(
(theme): InterfaceStyles => ({
//styles
})
)
export default withStyles(style)(App)
Use it in your components.
import Theme, { StylesConsumer, withStyles } from "@material-native-ui/theme-provider";
// with theme
const style = Theme.create((theme) => ({
container: {
color: theme.textColor,
// Theme inherits all properties from StyleSheet
...Theme.absoluteFillObject,
}
}));
// or without theme
const style = Theme.create({
color: "blue",
});
// or create a stylesheet directly
// but do not pass this to style prop on consumer/hoc
const stylesheet = Theme.sheet({
color: "blue",
})
// as consumer
const ThemedText = (props) => (
<StylesConsumer style={style}>
{(styles) => (
<Text {...props} styles={styles} />
)}
</StylesConsumer>
);
export default ThemedText;
// or as hoc
const ThemedText = (({ styles, ...props }) => (
<Text {...props} styles={styles} />
));
export default withStyles(style)(ThemedText);
state | react-native | react-native-web |
---|---|---|
fork from react-native-paint | ✅ | ✅ |
provide theme as props | ✅ | ✅ |
useStyle hook | ✅ | ✅ |
useTheme hook | ✅ | ✅ |
reWrite with type script |