Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useTheme hook for emotion-theming #1499

Merged
merged 5 commits into from
Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/weak-spies-help/changes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"releases": [{ "name": "emotion-theming", "type": "patch" }],
"dependents": []
}
1 change: 1 addition & 0 deletions .changeset/weak-spies-help/changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add useTheme React hook to emotion-theming
35 changes: 35 additions & 0 deletions docs/theming.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ npm install -S emotion-theming

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).

### With css prop
tkh44 marked this conversation as resolved.
Show resolved Hide resolved

```jsx
// @live
/** @jsx jsx */
Expand All @@ -36,3 +38,36 @@ render(
</ThemeProvider>
)
```

### Using the hook

```jsx
// @live
/** @jsx jsx */
import { jsx } from '@emotion/core'
import styled from '@emotion/styled'
import { ThemeProvider, useTheme } from 'emotion-theming'

const theme = {
colors: {
primary: 'hotpink'
}
}

function SomeText (props) {
const theme = useTheme()
return (
<div
css={{ color: theme.colors.primary }}
{...props}
/>
)
}

render(
<ThemeProvider theme={theme}>
<SomeText>some text</SomeText>
</ThemeProvider>
)
```

35 changes: 35 additions & 0 deletions packages/emotion-theming/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ _`emotion-theming` is a theming library inspired by [styled-components](https://
- [API](#api)
- [ThemeProvider](#themeprovider-reactcomponenttype)
- [withTheme](#withthemecomponent-reactcomponenttype-reactcomponenttype)
- [useTheme](#usetheme)
- [Credits](#credits)
- [License](#license)

Expand Down Expand Up @@ -149,6 +150,40 @@ TellMeTheColor.propTypes = {
const TellMeTheColorWithTheme = withTheme(TellMeTheColor)
```

### useTheme

A React hook that provides the current theme as its value. If the theme is updated, the child component will be re-rendered accordingly.

```jsx
// @live
/** @jsx jsx */
import { jsx } from '@emotion/core'
import styled from '@emotion/styled'
import { ThemeProvider, useTheme } from 'emotion-theming'

const theme = {
colors: {
primary: 'hotpink'
}
}

function SomeText (props) {
const theme = useTheme()
return (
<div
css={{ color: theme.colors.primary }}
{...props}
/>
)
}

render(
<ThemeProvider theme={theme}>
<SomeText>some text</SomeText>
</ThemeProvider>
)
```

## Credits

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.
Expand Down
46 changes: 46 additions & 0 deletions packages/emotion-theming/__tests__/__snapshots__/use-theme.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Nested useTheme works 1`] = `
.emotion-1 {
color: green;
}

.emotion-1:hover {
color: darkgreen;
}

.emotion-0 {
color: lawngreen;
}

.emotion-0:hover {
color: seagreen;
}

<div
className="emotion-1"
>
Should be green
<div
className="emotion-0"
>
Should be lawngreen
</div>
</div>
`;

exports[`useTheme works 1`] = `
.emotion-0 {
color: green;
}

.emotion-0:hover {
color: darkgreen;
}

<div
className="emotion-0"
>
Should be green
</div>
`;
77 changes: 77 additions & 0 deletions packages/emotion-theming/__tests__/use-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// @flow
/** @jsx jsx */
import 'test-utils/next-env'
import * as renderer from 'react-test-renderer'
import { jsx } from '@emotion/core'
import { useTheme, ThemeProvider } from 'emotion-theming'

test('useTheme works', () => {
function TestComponent(props) {
const theme = useTheme()
return (
<div
css={{ color: theme.lightGreen, '&:hover': { color: theme.darkGreen } }}
>
Should be green
</div>
)
}

expect(
renderer
.create(
<ThemeProvider theme={{ lightGreen: 'green', darkGreen: 'darkgreen' }}>
<TestComponent />
</ThemeProvider>
)
.toJSON()
).toMatchSnapshot()
})

test('Nested useTheme works', () => {
function TestComponent1(props) {
const theme = useTheme()
return (
<div
css={{ color: theme.lightGreen, '&:hover': { color: theme.darkGreen } }}
{...props}
/>
)
}

function NestedComponent(props) {
const theme = useTheme()
return (
<div
css={{
color: theme.lightGreen,
'&:hover': { color: theme.darkGreen }
}}
{...props}
/>
)
}

function TestComponent2(props) {
return (
<TestComponent1>
Should be green
<ThemeProvider
theme={{ lightGreen: 'lawngreen', darkGreen: 'seagreen' }}
>
<NestedComponent>Should be lawngreen</NestedComponent>
</ThemeProvider>
</TestComponent1>
)
}

expect(
renderer
.create(
<ThemeProvider theme={{ lightGreen: 'green', darkGreen: 'darkgreen' }}>
<TestComponent2 />
</ThemeProvider>
)
.toJSON()
).toMatchSnapshot()
})
1 change: 1 addition & 0 deletions packages/emotion-theming/src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @flow
export { default as ThemeProvider } from './theme-provider'
export { default as withTheme } from './with-theme'
export { default as useTheme } from './use-theme'
7 changes: 7 additions & 0 deletions packages/emotion-theming/src/use-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @flow
import * as React from 'react'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing 👇 will mean that emotion-theming won't break for people who aren't on >=16.8.0

Suggested change
import * as React from 'react'
import React from 'react'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mitchellhamilton import * as React from 'react' was always supported, this ain't nothing to do with [email protected]. And also - the wildcard is somewhat more correct than the default export. Or maybe you were referencing something I'm not aware of.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that it would fail for users who aren't on >=16.8.0 because rollup would change import * as React from 'react' to import { useContext } from 'react' and that export wouldn't exist so it would fail. Though I guess since React is CJS, it wouldn't have failed? I'd still rather leave it as import React from 'react' though just in case someone uses an ESM bundle of React and aliased it or rollup users with rollup-plugin-commonjs because of the namedExports option or something like that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting edge cases. I guess technically they are possible so yeah - let's keep the default for now.

import { ThemeContext } from '@emotion/core'

export default function useTheme() {
return React.useContext(ThemeContext)
}