1 | <p align="center">
|
2 | <img alt="react-theme-provider" src="./assets/theme-provider-logo.png" width="496">
|
3 | </p>
|
4 |
|
5 | ---
|
6 |
|
7 | [![Build Status][build-badge]][build]
|
8 | [![Version][version-badge]][package]
|
9 | [![MIT License][license-badge]][license]
|
10 |
|
11 | ## About
|
12 |
|
13 | `@callstack/react-theme-provider` is a set of utilities that help you create your own theming system in few easy steps.
|
14 | You can use it to customize colors, fonts, etc.
|
15 |
|
16 | ## Features
|
17 |
|
18 | - Works in **React** and **React Native**
|
19 | - `createTheming(defaultTheme)` - factory returns:
|
20 | - `ThemeProvider` - component
|
21 | - `withTheme` - Higher Order Component
|
22 | - `useTheme` - React Hook
|
23 |
|
24 | ## Examples
|
25 |
|
26 | - built-in example for web react - ['/examples/web'](/examples/web)
|
27 | - [![Edit v6o562k6l7](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/v6o562k6l7)
|
28 |
|
29 | ## Getting started
|
30 |
|
31 | ### Installation
|
32 |
|
33 | ```sh
|
34 | npm install --save @callstack/react-theme-provider
|
35 | ```
|
36 |
|
37 | or using yarn
|
38 |
|
39 | ```sh
|
40 | yarn add @callstack/react-theme-provider
|
41 | ```
|
42 |
|
43 | ### Usage
|
44 |
|
45 | Import `createTheming` from the library to create a theming object.
|
46 |
|
47 | ```js
|
48 | import { createTheming } from '@callstack/theme-provider';
|
49 |
|
50 | const { ThemeProvider, withTheme, useTheme } = createTheming(defaultTheme);
|
51 | ```
|
52 |
|
53 | Then wrap your code in `ThemeProvider` component to make it available to all components.
|
54 |
|
55 | ```js
|
56 | <ThemeProvider>
|
57 | <App />
|
58 | </ThemeProvider>
|
59 | ```
|
60 |
|
61 | You can access the theme data in your components by wrapping it in `withTheme` HOC:
|
62 |
|
63 | ```js
|
64 | class App extends React.Component {
|
65 | render() {
|
66 | return <div style={{ color: props.theme.primaryColor }}>Hello</div>;
|
67 | }
|
68 | }
|
69 |
|
70 | export default withTheme(App);
|
71 | ```
|
72 |
|
73 | You can also use the [hooks](https://reactjs.org/docs/hooks-intro.html) based API:
|
74 |
|
75 | ```js
|
76 | function App() {
|
77 | const theme = useTheme();
|
78 |
|
79 | return <div style={{ color: theme.primaryColor }}>Hello</div>;
|
80 | }
|
81 | ```
|
82 |
|
83 | ### Usage
|
84 |
|
85 | ```js
|
86 | const App = ({ theme }) => (
|
87 | <div style={{ color: theme.primaryColor }}>
|
88 | Hello
|
89 | </div>
|
90 | );
|
91 |
|
92 | export withTheme(App);
|
93 | ```
|
94 |
|
95 | ### Injected props
|
96 |
|
97 | It will inject the following props to the component:
|
98 |
|
99 | - `theme` - our theme object.
|
100 | - `getWrappedInstance` - exposed by some HOCs like react-redux's `connect`.
|
101 | Use it to get the ref of the underlying element.
|
102 |
|
103 | ### Injecting theme by a direct prop
|
104 |
|
105 | You can also override `theme` provided by `ThemeProvider` by setting `theme` prop on the component wrapped in `withTheme` HOC.
|
106 |
|
107 | Just like this:
|
108 |
|
109 | ```js
|
110 | const Button = withTheme(({ theme }) => (
|
111 | <div style={{ color: theme.primaryColor }}>Click me</div>
|
112 | ));
|
113 |
|
114 | const App = () => (
|
115 | <ThemeProvider theme={{ primaryColor: 'red' }}>
|
116 | <Button theme={{ primaryColor: 'green' }} />
|
117 | </ThemeProvider>
|
118 | );
|
119 | ```
|
120 |
|
121 | In this example Button will have green text.
|
122 |
|
123 | ## `createTheming`
|
124 |
|
125 | **type:**
|
126 |
|
127 | ```js
|
128 | <T, S>(defaultTheme: T) => {
|
129 | ThemeProvider: ThemeProviderType<T>,
|
130 | withTheme: WithThemeType<T, S>,
|
131 | }
|
132 | ```
|
133 |
|
134 | This is more advanced replacement to classic importing `ThemeProvider` and `withTheme` directly from the library.
|
135 | Thanks to it you can create your own ThemeProvider with any default theme.
|
136 |
|
137 | Returns instance of `ThemeProvider` component and `withTheme` HOC.
|
138 | You can use this factory to create a singleton with your instances of `ThemeProvider` and `withTheme`.
|
139 |
|
140 | > **Note:** `ThemeProvider` and `withTheme` generated by `createTheming` always will use different context so make sure you are using matching `withTheme`!
|
141 | > If you acidentially import `withTheme` from `@callstack/react-theme-provider` instead of your theming instance it won't work.
|
142 |
|
143 | ### Arguments
|
144 |
|
145 | - `defaultTheme` - default theme object
|
146 |
|
147 | ### Benefits
|
148 |
|
149 | - Possibility to define `flow` types for your theme
|
150 | - Possibility to pass default theme
|
151 | - You can use multiple `ThemeProvider`s in your app without any conflicts.
|
152 |
|
153 | ### Usage
|
154 |
|
155 | ```js
|
156 | // theming.js
|
157 | import { createTheming } from '@callstack/react-theme-provider';
|
158 | const { ThemeProvider, withTheme } = createTheming({
|
159 | primaryColor: 'red',
|
160 | secondaryColor: 'green',
|
161 | });
|
162 | export { ThemeProvider, withTheme };
|
163 |
|
164 | //App.js
|
165 | import { ThemeProvider, withTheme } from './theming';
|
166 | ```
|
167 |
|
168 | ### Helpers
|
169 |
|
170 | #### `ThemeProvider`
|
171 |
|
172 | **type:**
|
173 |
|
174 | ```js
|
175 | type ThemeProviderType<Theme> = React.ComponentType<{
|
176 | children: React.Node,
|
177 | theme?: Theme,
|
178 | }>;
|
179 | ```
|
180 |
|
181 | Component you have to use to provide the theme to any component wrapped in `withTheme` HOC.
|
182 |
|
183 | ##### Props
|
184 |
|
185 | -`theme` - your theme object
|
186 |
|
187 | #### `withTheme`
|
188 |
|
189 | **type:**
|
190 |
|
191 | ```js
|
192 | type WithThemeType<Theme> = React.ComponentType<{ theme: Theme }>
|
193 | ```
|
194 |
|
195 | Higher Order Component which takes your component as an argument and injects `theme` prop into it.
|
196 |
|
197 | ## Applying a custom theme to a component
|
198 |
|
199 | If you want to change the theme for a certain component, you can directly pass the theme prop to the component. The theme passed as the prop is merged with the theme from the Provider.
|
200 |
|
201 | ```js
|
202 | import * as React from 'react';
|
203 | import MyButton from './MyButton';
|
204 |
|
205 | export default function ButtonExample() {
|
206 | return <MyButton theme={{ roundness: 3 }}>Press me</MyButton>;
|
207 | }
|
208 | ```
|
209 |
|
210 | #### `useTheme`
|
211 |
|
212 | **type:**
|
213 |
|
214 | ```js
|
215 | type UseTheme = (overrides?: PartialTheme) => Theme;
|
216 | ```
|
217 |
|
218 | Hook which takes theme overrides and returns a theme object.
|
219 |
|
220 | Example:
|
221 |
|
222 | ```js
|
223 | function App(props) {
|
224 | const theme = useTheme(props.theme);
|
225 |
|
226 | return <div style={{ color: theme.primaryColor }}>Hello</div>;
|
227 | }
|
228 | ```
|
229 |
|
230 | ## Applying a custom theme to a component
|
231 |
|
232 | If you want to change the theme for a certain component, you can directly pass the theme prop to the component. The theme passed as the prop is merged with the theme from the Provider.
|
233 |
|
234 | ```js
|
235 | import * as React from 'react';
|
236 | import MyButton from './MyButton';
|
237 |
|
238 | export default function ButtonExample() {
|
239 | return <MyButton theme={{ roundness: 3 }}>Press me</MyButton>;
|
240 | }
|
241 | ```
|
242 |
|
243 | ## Gotchas
|
244 |
|
245 | The `ThemeProvider` exposes the theme to the components via [React's context API](https://reactjs.org/docs/context.html),
|
246 | which means that the component must be in the same tree as the `ThemeProvider`. Some React Native components will render a
|
247 | different tree such as a `Modal`, in which case the components inside the `Modal` won't be able to access the theme. The work
|
248 | around is to get the theme using the `withTheme` HOC and pass it down to the components as props, or expose it again with the
|
249 | exported `ThemeProvider` component.
|
250 |
|
251 | [build-badge]: https://img.shields.io/circleci/project/github/callstack/react-theme-provider/master.svg?style=flat-square
|
252 | [build]: https://circleci.com/gh/callstack/react-theme-provider
|
253 | [version-badge]: https://img.shields.io/npm/v/@callstack/react-theme-provider.svg?style=flat-square
|
254 | [package]: https://www.npmjs.com/package/@callstack/react-theme-provider
|
255 | [license-badge]: https://img.shields.io/npm/l/react-theme-provider.svg?style=flat-square
|
256 | [license]: https://opensource.org/licenses/MIT
|
257 | [chat-badge]: https://img.shields.io/badge/chat-slack-brightgreen.svg?style=flat-square&colorB=E01563
|
258 | [chat]: https://slack.callstack.com/
|