Skip to content

Commit bfb4005

Browse files
authored
Add useTheme hook for emotion-theming (#1499)
* Add useTheme hook for emotion-theming * Add changeset * Small fixes to imports and docs * Update theming.mdx
1 parent 1b38550 commit bfb4005

File tree

8 files changed

+230
-3
lines changed

8 files changed

+230
-3
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"releases": [{ "name": "emotion-theming", "type": "patch" }],
3+
"dependents": []
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add useTheme React hook to emotion-theming

docs/theming.mdx

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,33 @@ npm install -S emotion-theming
1010

1111
Add `ThemeProvider` to the top level of your app and access the theme with `props.theme` in a styled component or provide a function that accepts the theme as the css prop. The api is laid out in detail [in the documentation](https://emotion.sh/docs/emotion-theming).
1212

13+
## Examples
14+
15+
### css prop
16+
17+
```jsx
18+
// @live
19+
/** @jsx jsx */
20+
import { jsx } from '@emotion/core'
21+
import { ThemeProvider } from 'emotion-theming'
22+
23+
const theme = {
24+
colors: {
25+
primary: 'hotpink'
26+
}
27+
}
28+
29+
render(
30+
<ThemeProvider theme={theme}>
31+
<div css={theme => ({ color: theme.colors.primary })}>
32+
some other text
33+
</div>
34+
</ThemeProvider>
35+
)
36+
```
37+
38+
### styled
39+
1340
```jsx
1441
// @live
1542
/** @jsx jsx */
@@ -30,9 +57,38 @@ const SomeText = styled.div`
3057
render(
3158
<ThemeProvider theme={theme}>
3259
<SomeText>some text</SomeText>
33-
<div css={theme => ({ color: theme.colors.primary })}>
34-
some other text
35-
</div>
3660
</ThemeProvider>
3761
)
3862
```
63+
64+
### useTheme hook
65+
66+
```jsx
67+
// @live
68+
/** @jsx jsx */
69+
import { jsx } from '@emotion/core'
70+
import { ThemeProvider, useTheme } from 'emotion-theming'
71+
72+
const theme = {
73+
colors: {
74+
primary: 'hotpink'
75+
}
76+
}
77+
78+
function SomeText (props) {
79+
const theme = useTheme()
80+
return (
81+
<div
82+
css={{ color: theme.colors.primary }}
83+
{...props}
84+
/>
85+
)
86+
}
87+
88+
render(
89+
<ThemeProvider theme={theme}>
90+
<SomeText>some text</SomeText>
91+
</ThemeProvider>
92+
)
93+
```
94+

packages/emotion-theming/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ _`emotion-theming` is a theming library inspired by [styled-components](https://
1111
- [API](#api)
1212
- [ThemeProvider](#themeprovider-reactcomponenttype)
1313
- [withTheme](#withthemecomponent-reactcomponenttype-reactcomponenttype)
14+
- [useTheme](#usetheme)
1415
- [Credits](#credits)
1516
- [License](#license)
1617

@@ -149,6 +150,40 @@ TellMeTheColor.propTypes = {
149150
const TellMeTheColorWithTheme = withTheme(TellMeTheColor)
150151
```
151152

153+
### useTheme
154+
155+
A React hook that provides the current theme as its value. If the theme is updated, the child component will be re-rendered accordingly.
156+
157+
```jsx
158+
// @live
159+
/** @jsx jsx */
160+
import { jsx } from '@emotion/core'
161+
import styled from '@emotion/styled'
162+
import { ThemeProvider, useTheme } from 'emotion-theming'
163+
164+
const theme = {
165+
colors: {
166+
primary: 'hotpink'
167+
}
168+
}
169+
170+
function SomeText (props) {
171+
const theme = useTheme()
172+
return (
173+
<div
174+
css={{ color: theme.colors.primary }}
175+
{...props}
176+
/>
177+
)
178+
}
179+
180+
render(
181+
<ThemeProvider theme={theme}>
182+
<SomeText>some text</SomeText>
183+
</ThemeProvider>
184+
)
185+
```
186+
152187
## Credits
153188

154189
Thanks goes to the [styled-components team](https://github.com/styled-components/styled-components) and [their contributors](https://github.com/styled-components/styled-components/graphs/contributors) who designed this API.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Nested useTheme works 1`] = `
4+
.emotion-1 {
5+
color: green;
6+
}
7+
8+
.emotion-1:hover {
9+
color: darkgreen;
10+
}
11+
12+
.emotion-0 {
13+
color: lawngreen;
14+
}
15+
16+
.emotion-0:hover {
17+
color: seagreen;
18+
}
19+
20+
<div
21+
className="emotion-1"
22+
>
23+
Should be green
24+
<div
25+
className="emotion-0"
26+
>
27+
Should be lawngreen
28+
</div>
29+
</div>
30+
`;
31+
32+
exports[`useTheme works 1`] = `
33+
.emotion-0 {
34+
color: green;
35+
}
36+
37+
.emotion-0:hover {
38+
color: darkgreen;
39+
}
40+
41+
<div
42+
className="emotion-0"
43+
>
44+
Should be green
45+
</div>
46+
`;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// @flow
2+
/** @jsx jsx */
3+
import 'test-utils/next-env'
4+
import * as renderer from 'react-test-renderer'
5+
import { jsx } from '@emotion/core'
6+
import { useTheme, ThemeProvider } from 'emotion-theming'
7+
8+
test('useTheme works', () => {
9+
function TestComponent(props) {
10+
const theme = useTheme()
11+
return (
12+
<div
13+
css={{ color: theme.lightGreen, '&:hover': { color: theme.darkGreen } }}
14+
>
15+
Should be green
16+
</div>
17+
)
18+
}
19+
20+
expect(
21+
renderer
22+
.create(
23+
<ThemeProvider theme={{ lightGreen: 'green', darkGreen: 'darkgreen' }}>
24+
<TestComponent />
25+
</ThemeProvider>
26+
)
27+
.toJSON()
28+
).toMatchSnapshot()
29+
})
30+
31+
test('Nested useTheme works', () => {
32+
function TestComponent1(props) {
33+
const theme = useTheme()
34+
return (
35+
<div
36+
css={{ color: theme.lightGreen, '&:hover': { color: theme.darkGreen } }}
37+
{...props}
38+
/>
39+
)
40+
}
41+
42+
function NestedComponent(props) {
43+
const theme = useTheme()
44+
return (
45+
<div
46+
css={{
47+
color: theme.lightGreen,
48+
'&:hover': { color: theme.darkGreen }
49+
}}
50+
{...props}
51+
/>
52+
)
53+
}
54+
55+
function TestComponent2(props) {
56+
return (
57+
<TestComponent1>
58+
Should be green
59+
<ThemeProvider
60+
theme={{ lightGreen: 'lawngreen', darkGreen: 'seagreen' }}
61+
>
62+
<NestedComponent>Should be lawngreen</NestedComponent>
63+
</ThemeProvider>
64+
</TestComponent1>
65+
)
66+
}
67+
68+
expect(
69+
renderer
70+
.create(
71+
<ThemeProvider theme={{ lightGreen: 'green', darkGreen: 'darkgreen' }}>
72+
<TestComponent2 />
73+
</ThemeProvider>
74+
)
75+
.toJSON()
76+
).toMatchSnapshot()
77+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
// @flow
22
export { default as ThemeProvider } from './theme-provider'
33
export { default as withTheme } from './with-theme'
4+
export { default as useTheme } from './use-theme'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @flow
2+
import React from 'react'
3+
import { ThemeContext } from '@emotion/core'
4+
5+
export default function useTheme() {
6+
return React.useContext(ThemeContext)
7+
}

0 commit comments

Comments
 (0)