Skip to content

Commit

Permalink
[WIP] Update to new react context for the jss context (#924)
Browse files Browse the repository at this point in the history
* Update to new react context for the jss context

* Fixed types

* Fix some tests

* Remove unnecessary cloning

* Fix JssProvider

* Update logic of merging context

* Fix a few issues and tests

* Make getTheme non public

* Update warning inside JssProvider

* Remove duplicate beforeEach

* Update size-snapshot

* Fix a few bugs

* Created a Managers type

* Create sheetOptions prop type definition

* Removed meta property from sheet options shape

* Fix creating a new generateId for every render

* Move media into it's own prop

* Added changelog

* Rename to JssContextSubscriber

* Moved context to jssContext prop instead of spreading it
  • Loading branch information
Henri authored Dec 11, 2018
1 parent bec70a0 commit e2f15ae
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 303 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [all] Added TypeScript definitions to all packages ([#889](https://github.com/cssinjs/jss/pull/889))
- [jss-plugin-syntax-nested] Fixed referencing rules inside media queries ([#900](https://github.com/cssinjs/jss/pull/900))
- [jss-plugin-syntax-global] TypeError: Cannot read property '@global' of undefined ([#905](https://github.com/cssinjs/jss/pull/905))
- [react-jss] Move JssContext to new React Context, deprecate the `sheetOptions` prop on the JssProvider and support a `media` prop ([#924](https://github.com/cssinjs/jss/pull/924))

### Breaking changes

Expand Down
30 changes: 15 additions & 15 deletions packages/react-jss/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
"dist/react-jss.js": {
"bundled": 147748,
"minified": 48996,
"gzipped": 14503
"bundled": 146196,
"minified": 48865,
"gzipped": 14339
},
"dist/react-jss.min.js": {
"bundled": 112924,
"minified": 38291,
"gzipped": 11780
"bundled": 111372,
"minified": 38169,
"gzipped": 11622
},
"dist/react-jss.cjs.js": {
"bundled": 16595,
"minified": 6965,
"gzipped": 2424
"bundled": 15227,
"minified": 6630,
"gzipped": 2259
},
"dist/react-jss.esm.js": {
"bundled": 16113,
"minified": 6562,
"gzipped": 2317,
"bundled": 14671,
"minified": 6180,
"gzipped": 2158,
"treeshaked": {
"rollup": {
"code": 1866,
"import_statements": 410
"code": 1712,
"import_statements": 492
},
"webpack": {
"code": 3178
"code": 3130
}
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/react-jss/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"dependencies": {
"@babel/runtime": "^7.0.0",
"@types/react": "^16.4.18",
"create-react-context": "^0.2.3",
"hoist-non-react-statics": "^3.2.0",
"jss": "^9.7.0",
"jss-preset-default": "^4.3.0",
Expand Down
10 changes: 10 additions & 0 deletions packages/react-jss/src/JssContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @flow
import createReactContext, {type Context} from 'create-react-context'
import type {Context as JssContextValue} from './types'

const JssContext: Context<JssContextValue> = createReactContext({
sheetOptions: {},
disableStylesGeneration: false
})

export default JssContext
108 changes: 48 additions & 60 deletions packages/react-jss/src/JssProvider.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
// @flow
import {Component, type Node} from 'react'
import React, {Component, type Node} from 'react'
import PropTypes from 'prop-types'
import {
createGenerateId as createGenerateIdDefault,
type Jss,
type GenerateId,
type SheetsRegistry
} from 'jss'
import * as ns from './ns'
import contextTypes from './contextTypes'
import propTypes from './propTypes'
import type {Context} from './types'
import defaultJss, {createGenerateId, type Jss, type GenerateId, SheetsRegistry} from 'jss'
import type {Context, Managers} from './types'
import JssContext from './JssContext'

/* eslint-disable react/require-default-props */

Expand All @@ -20,85 +13,80 @@ type Props = {
generateId?: GenerateId,
classNamePrefix?: string,
disableStylesGeneration?: boolean,
media?: string,
children: Node
}

export default class JssProvider extends Component<Props> {
static propTypes = {
...propTypes,
registry: PropTypes.instanceOf(SheetsRegistry),
jss: PropTypes.instanceOf(defaultJss.constructor),
generateId: PropTypes.func,
classNamePrefix: PropTypes.string,
disableStylesGeneration: PropTypes.bool,
children: PropTypes.node.isRequired
children: PropTypes.node.isRequired,
media: PropTypes.string
}

static childContextTypes = contextTypes

static contextTypes = contextTypes

// JssProvider can be nested. We allow to overwrite any context prop at any level.
// 1. Check if there is a value passed over props.
// 2. If value was passed, we set it on the child context.
// 3. If value was not passed, we proxy parent context (default context behaviour).
getChildContext(): Context {
const {
registry,
classNamePrefix,
jss: localJss,
generateId,
disableStylesGeneration
} = this.props
// eslint-disable-next-line react/react/destructuring-assignment
const sheetOptions = this.context[ns.sheetOptions] || {}
const context: Context = {[ns.sheetOptions]: sheetOptions}
managers: Managers = {}

/**
* We need to merge the outer context with the props,
* because we allow overriding any prop at any level.
*/
createContext(outerContext: Context): Context {
const {registry, classNamePrefix, jss, generateId, disableStylesGeneration, media} = this.props
// Clone the outer context
const context = {
...outerContext,
managers: this.managers
}

if (registry) {
context[ns.sheetsRegistry] = registry
// This way we identify a new request on the server, because user will create
// a new Registry instance for each.
if (registry !== this.registry) {
// We reset managers because we have to regenerate all sheets for the new request.
this.managers = {}
this.registry = registry
}
context.registry = registry
}

// Make sure we don't loose managers when JssProvider is used inside of a stateful
// component which decides to rerender.
context[ns.managers] = this.managers

if (generateId) {
sheetOptions.generateId = generateId
} else if (!sheetOptions.generateId) {
context.sheetOptions.generateId = generateId
} else if (!context.sheetOptions.generateId) {
if (!this.generateId) {
let createGenerateId = createGenerateIdDefault
if (localJss && localJss.options.createGenerateId) {
createGenerateId = localJss.options.createGenerateId
}
// Make sure we don't loose the generator when JssProvider is used inside of a stateful
// component which decides to rerender.
this.generateId = createGenerateId()
}
context.sheetOptions.generateId = this.generateId
}

// Merge the classname prefix
if (classNamePrefix) {
context.sheetOptions.classNamePrefix =
(context.sheetOptions.classNamePrefix || '') + classNamePrefix
}

sheetOptions.generateId = this.generateId
if (media !== undefined) {
context.sheetOptions.media = media
}

if (jss) {
context.jss = jss
}

if (classNamePrefix) sheetOptions.classNamePrefix = classNamePrefix
if (localJss) context[ns.jss] = localJss
if (disableStylesGeneration !== undefined) {
sheetOptions.disableStylesGeneration = disableStylesGeneration
context.disableStylesGeneration = disableStylesGeneration
}

return context
}

registry: SheetsRegistry
generateId: GenerateId

managers: {}
renderProvider = (outerContext: Context) => {
const {children} = this.props

generateId: GenerateId
return (
<JssContext.Provider value={this.createContext(outerContext)}>{children}</JssContext.Provider>
)
}

render() {
return this.props.children
return <JssContext.Consumer>{this.renderProvider}</JssContext.Consumer>
}
}
50 changes: 24 additions & 26 deletions packages/react-jss/src/JssProvider.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import {renderToString} from 'react-dom/server'

import injectSheet, {SheetsRegistry, JssProvider} from '.'

const createGenerateId = () => {
let counter = 0
return rule => `${rule.key}-${counter++}`
}

describe('React-JSS: JssProvider', () => {
let node

Expand Down Expand Up @@ -106,7 +111,7 @@ describe('React-JSS: JssProvider', () => {
)

expect(registry.toString()).to.be(stripIndent`
.B-NoRenderer-a {
.A-B-NoRenderer-a {
color: red;
}
`)
Expand Down Expand Up @@ -281,6 +286,7 @@ describe('React-JSS: JssProvider', () => {
}

render(<MyComponent />, node)
// TODO: Does this make sense?
expect(registry.toString()).to.be(stripIndent`
.a-0 {
color: green;
Expand Down Expand Up @@ -309,16 +315,15 @@ describe('React-JSS: JssProvider', () => {

describe('with JssProvider for SSR', () => {
let localJss
let generateId

beforeEach(() => {
localJss = create({
...preset(),
virtual: true,
createGenerateId: () => {
let counter = 0
return rule => `${rule.key}-${counter++}`
}
virtual: true
})

generateId = createGenerateId()
})

it('should add style sheets to the registry from context', () => {
Expand All @@ -342,7 +347,7 @@ describe('React-JSS: JssProvider', () => {
expect(customSheets.registry.length).to.equal(2)
})

it('should use Jss istance from the context', () => {
it('should use Jss instance from the context', () => {
let receivedSheet

const MyComponent = injectSheet({}, {inject: ['sheet']})(({sheet}) => {
Expand Down Expand Up @@ -388,7 +393,7 @@ describe('React-JSS: JssProvider', () => {
let registry = new SheetsRegistry()

renderToString(
<JssProvider registry={registry} jss={localJss}>
<JssProvider registry={registry} generateId={generateId}>
<MyComponent border="green" />
</JssProvider>
)
Expand All @@ -403,9 +408,10 @@ describe('React-JSS: JssProvider', () => {
`)

registry = new SheetsRegistry()
generateId = createGenerateId()

renderToString(
<JssProvider registry={registry} jss={localJss}>
<JssProvider registry={registry} generateId={generateId}>
<MyComponent border="blue" />
</JssProvider>
)
Expand All @@ -431,13 +437,13 @@ describe('React-JSS: JssProvider', () => {
const customSheets2 = new SheetsRegistry()

renderToString(
<JssProvider jss={localJss} registry={customSheets1}>
<JssProvider registry={customSheets1}>
<MyComponent color="#000" />
</JssProvider>
)

renderToString(
<JssProvider jss={localJss} registry={customSheets2}>
<JssProvider registry={customSheets2}>
<MyComponent color="#000" />
</JssProvider>
)
Expand Down Expand Up @@ -465,13 +471,13 @@ describe('React-JSS: JssProvider', () => {
const customSheets2 = new SheetsRegistry()

renderToString(
<JssProvider jss={localJss} registry={customSheets1}>
<JssProvider registry={customSheets1}>
<ComponentA color="#000" />
</JssProvider>
)

render(
<JssProvider jss={localJss} registry={customSheets2}>
<JssProvider registry={customSheets2}>
<ComponentB color="#000" />
</JssProvider>,
node
Expand All @@ -484,14 +490,13 @@ describe('React-JSS: JssProvider', () => {
const Component1 = injectSheet({a: {color: 'red'}})()
const Component2 = injectSheet({a: {color: 'red'}})()
const registry = new SheetsRegistry()
const generateId = localJss.options.createGenerateId()

renderToString(
<div>
<JssProvider registry={registry} generateId={generateId} jss={localJss}>
<JssProvider registry={registry} generateId={generateId}>
<Component1 />
</JssProvider>
<JssProvider registry={registry} generateId={generateId} jss={localJss}>
<JssProvider registry={registry} generateId={generateId}>
<Component2 />
</JssProvider>
</div>
Expand All @@ -511,23 +516,16 @@ describe('React-JSS: JssProvider', () => {
const MyRenderComponent = () => null
const MyComponent = injectSheet({a: {color: 'red'}})(MyRenderComponent)
const registry = new SheetsRegistry()
const localJss2 = create({
...preset(),
virtual: true,
createGenerateId: () => {
let counter = 0
return (rule, sheet) => `${sheet.options.classNamePrefix}${rule.key}-${counter++}`
}
})
const generateId2 = (rule, sheet) => `${sheet.options.classNamePrefix}${rule.key}`

renderToString(
<JssProvider registry={registry} jss={localJss2} classNamePrefix="MyApp-">
<JssProvider registry={registry} generateId={generateId2} classNamePrefix="MyApp-">
<MyComponent />
</JssProvider>
)

expect(registry.toString()).to.be(stripIndent`
.MyApp-MyRenderComponent-a-0 {
.MyApp-MyRenderComponent-a {
color: red;
}
`)
Expand Down
11 changes: 0 additions & 11 deletions packages/react-jss/src/contextTypes.js

This file was deleted.

Loading

0 comments on commit e2f15ae

Please sign in to comment.