From 1b3fadeaa5e31a1b09b8e5ce8249238c7ddcac0b Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 2 Mar 2019 18:31:50 +0100 Subject: [PATCH 01/52] Revert "Revert "Add dynamic rules to static sheet"" This reverts commit 1e359673 --- packages/react-jss/.size-snapshot.json | 26 +++--- packages/react-jss/src/types.js | 6 +- packages/react-jss/src/withStyles.js | 116 ++++++++++++++++--------- 3 files changed, 91 insertions(+), 57 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index a65a6cca1..e4706ab6a 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/react-jss.js": { - "bundled": 109683, - "minified": 36814, - "gzipped": 11859 + "bundled": 110399, + "minified": 37053, + "gzipped": 11908 }, "dist/react-jss.min.js": { - "bundled": 85144, - "minified": 29568, - "gzipped": 9685 + "bundled": 85860, + "minified": 29807, + "gzipped": 9735 }, "dist/react-jss.cjs.js": { - "bundled": 14716, - "minified": 6874, - "gzipped": 2310 + "bundled": 15384, + "minified": 7062, + "gzipped": 2367 }, "dist/react-jss.esm.js": { - "bundled": 14035, - "minified": 6294, - "gzipped": 2193, + "bundled": 14703, + "minified": 6482, + "gzipped": 2247, "treeshaked": { "rollup": { "code": 1946, "import_statements": 457 }, "webpack": { - "code": 3338 + "code": 3310 } } } diff --git a/packages/react-jss/src/types.js b/packages/react-jss/src/types.js index 39eb3cbb7..e15c80e8c 100644 --- a/packages/react-jss/src/types.js +++ b/packages/react-jss/src/types.js @@ -1,5 +1,5 @@ // @flow -import type {StyleSheetFactoryOptions, Jss, SheetsRegistry, SheetsManager} from 'jss' +import type {StyleSheetFactoryOptions, Jss, SheetsRegistry, SheetsManager, BaseRule} from 'jss' import type {Node} from 'react' import type {Theming} from 'theming' @@ -32,5 +32,9 @@ export type InnerProps = { classes: {} } +export type DynamicRules = { + [key: string]: BaseRule, +}; + export type ThemedStyles = (theme: Theme) => StaticStyles export type Styles = StaticStyles | ThemedStyles diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index 2f0577ada..1cde0ee31 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -5,18 +5,16 @@ import {getDynamicStyles, SheetsManager, type StyleSheet} from 'jss' import {ThemeContext} from 'theming' import warning from 'tiny-warning' -import type {HOCProps, Options, Styles, InnerProps} from './types' +import type {HOCProps, Options, Styles, InnerProps, DynamicRules} from './types' import getDisplayName from './getDisplayName' import memoize from './memoize-one' import mergeClasses from './merge-classes' import defaultJss from './jss' import JssContext from './JssContext' -const dynamicStylesNS = Symbol.for('dynamicStyles') - -type State = { - dynamicSheet?: StyleSheet, - staticSheet?: StyleSheet, +interface State { + dynamicRules?: ?DynamicRules, + sheet?: StyleSheet, classes: {} } @@ -64,6 +62,8 @@ export default function withStyles>( return ( InnerComponent: ComponentType = NoRenderer ): ComponentType => { + let instanceCounter = 0; + const displayName = getDisplayName(InnerComponent) const defaultClassNamePrefix = process.env.NODE_ENV === 'production' ? '' : `${displayName}-` const managerId = managersCounter++ @@ -84,6 +84,8 @@ export default function withStyles>( classesProp ? mergeClasses(sheetClasses, classesProp) : sheetClasses ) + instanceId = instanceCounter++ + constructor(props: HOCProps) { super(props) @@ -96,8 +98,7 @@ export default function withStyles>( } componentDidUpdate(prevProps: HOCProps, prevState: State) { - const {dynamicSheet} = this.state - if (dynamicSheet) dynamicSheet.update(this.props) + this.updateDynamicRules(this.props, this.state) if (isThemingEnabled && this.props.theme !== prevProps.theme) { const newState = this.createState() @@ -132,7 +133,7 @@ export default function withStyles>( return manager } - getStaticSheet(): StyleSheet { + getSheet(): StyleSheet { const theme = getTheme(this.props) let staticSheet = this.manager.get(theme) @@ -141,69 +142,100 @@ export default function withStyles>( } const themedStyles = getStyles(styles, theme, displayName) + const dynamicStyles = getDynamicStyles(themedStyles) const contextSheetOptions = this.props.jssContext.sheetOptions staticSheet = this.jss.createStyleSheet(themedStyles, { ...sheetOptions, ...contextSheetOptions, index, - meta: `${displayName}, ${isThemingEnabled ? 'Themed' : 'Unthemed'}, Static`, - classNamePrefix: this.classNamePrefix + meta: `${displayName}, ${isThemingEnabled ? 'Themed' : 'Unthemed'}`, + classNamePrefix: this.classNamePrefix, + link: dynamicStyles !== null }) this.manager.add(theme, staticSheet) // $FlowFixMe Cannot add random fields to instance of class StyleSheet - staticSheet[dynamicStylesNS] = getDynamicStyles(themedStyles) + staticSheet.dynamicStyles = dynamicStyles + + // $FlowFixMe Cannot add random fields to instance of class StyleSheet + staticSheet.styles = themedStyles; return staticSheet } - getDynamicSheet(staticSheet: StyleSheet): StyleSheet | void { - // $FlowFixMe Cannot access random fields on instance of class StyleSheet - const dynamicStyles = staticSheet[dynamicStylesNS] + getSheetClasses(sheet) { + const classes = {}; - if (!dynamicStyles) return undefined + // $FlowFixMe + for (const key in sheet.styles) { + classes[key] = sheet.classes[key]; + } - const contextSheetOptions = this.props.jssContext.sheetOptions + // $FlowFixMe + if (sheet.dynamicStyles) { + // $FlowFixMe + for (const key in sheet.dynamicStyles) { + classes[key] += ` ${sheet.classes[`${key}-${this.instanceId}`]}` + } + } - return this.jss.createStyleSheet(dynamicStyles, { - ...sheetOptions, - ...contextSheetOptions, - index, - meta: `${displayName}, ${isThemingEnabled ? 'Themed' : 'Unthemed'}, Dynamic`, - classNamePrefix: this.classNamePrefix, - link: true - }) + return classes; } classNamePrefix: string manage(props, state) { - const {dynamicSheet, staticSheet} = state + const {sheet} = state const {registry} = props.jssContext - if (!staticSheet) { + if (!sheet) { return } + this.updateDynamicRules(props, state) + this.manager.manage(getTheme(props)) if (registry) { - registry.add(staticSheet) + registry.add(sheet) } + } - if (dynamicSheet) { - dynamicSheet.update(props).attach() + updateDynamicRules(props, { dynamicRules, sheet }: State) { + if (!sheet) { + return; + } - if (registry) { - registry.add(dynamicSheet) - } + for (const key in dynamicRules) { + sheet.update(`${key}-${this.instanceId}`, props); } } - unmanage(props, state) { + removeDynamicRules(props: Props, { dynamicRules, sheet }: State) { + if (!sheet) { + return; + } + + for (const key in dynamicRules) { + sheet.deleteRule(`${key}-${this.instanceId}`); + } + } + + unmanage(props, state: State) { + this.removeDynamicRules(props, state) + this.manager.unmanage(getTheme(props)) + } - if (state.dynamicSheet) { - this.jss.removeStyleSheet(state.dynamicSheet) + addDynamicStyles(sheet: StyleSheet): ?DynamicRules { + // $FlowFixMe Cannot access random fields on instance of class StyleSheet + if (!sheet.dynamicStyles) return undefined + + const rules = {}; + + for (const key in sheet.dynamicStyles) { + rules[key] = sheet.addRule(`${key}-${this.instanceId}`, rules[key]) } + + return rules; } createState(): State { @@ -211,15 +243,13 @@ export default function withStyles>( return {classes: {}} } - const staticSheet = this.getStaticSheet() - const dynamicSheet = this.getDynamicSheet(staticSheet) + const sheet = this.getSheet() + const dynamicRules = this.addDynamicStyles(sheet) return { - staticSheet, - dynamicSheet, - classes: dynamicSheet - ? mergeClasses(staticSheet.classes, dynamicSheet.classes) - : staticSheet.classes + sheet, + dynamicRules, + classes: this.getSheetClasses(sheet), } } From 5dbc7dc2935922f4ea47caabb38923aff3803c2c Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 2 Mar 2019 20:27:35 +0100 Subject: [PATCH 02/52] Fix adding dynamic rules to sheet --- packages/react-jss/.size-snapshot.json | 24 +++++++++---------- packages/react-jss/src/withStyles.js | 2 +- packages/react-jss/tests/dynamic-styles.js | 13 ++++------- packages/react-jss/tests/theming.js | 27 +++++++++------------- 4 files changed, 29 insertions(+), 37 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index e4706ab6a..e4a078f43 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 110399, - "minified": 37053, - "gzipped": 11908 + "bundled": 110413, + "minified": 37067, + "gzipped": 11910 }, "dist/react-jss.min.js": { - "bundled": 85860, - "minified": 29807, - "gzipped": 9735 + "bundled": 85874, + "minified": 29821, + "gzipped": 9737 }, "dist/react-jss.cjs.js": { - "bundled": 15384, - "minified": 7062, - "gzipped": 2367 + "bundled": 15398, + "minified": 7076, + "gzipped": 2369 }, "dist/react-jss.esm.js": { - "bundled": 14703, - "minified": 6482, - "gzipped": 2247, + "bundled": 14717, + "minified": 6496, + "gzipped": 2249, "treeshaked": { "rollup": { "code": 1946, diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index 1cde0ee31..e0cf713b2 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -232,7 +232,7 @@ export default function withStyles>( const rules = {}; for (const key in sheet.dynamicStyles) { - rules[key] = sheet.addRule(`${key}-${this.instanceId}`, rules[key]) + rules[key] = sheet.addRule(`${key}-${this.instanceId}`, sheet.dynamicStyles[key]) } return rules; diff --git a/packages/react-jss/tests/dynamic-styles.js b/packages/react-jss/tests/dynamic-styles.js index 118938c70..b1a0087ea 100644 --- a/packages/react-jss/tests/dynamic-styles.js +++ b/packages/react-jss/tests/dynamic-styles.js @@ -42,14 +42,12 @@ describe('React-JSS: dynamic styles', () => { ) - expect(registry.registry.length).to.equal(2) + expect(registry.registry.length).to.equal(1) expect(registry.registry[0].attached).to.equal(true) - expect(registry.registry[1].attached).to.equal(true) renderer.unmount() expect(registry.registry[0].attached).to.equal(false) - expect(registry.registry[1].attached).to.equal(false) }) it('should have correct meta attribute', () => { @@ -59,11 +57,10 @@ describe('React-JSS: dynamic styles', () => { ) - expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed, Static') - expect(registry.registry[1].options.meta).to.equal('NoRenderer, Unthemed, Dynamic') + expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed') }) - it('should reuse static sheet, but generate separate dynamic once', () => { + it('should reuse sheet between component instances', () => { TestRenderer.create( @@ -71,7 +68,7 @@ describe('React-JSS: dynamic styles', () => { ) - expect(registry.registry.length).to.equal(3) + expect(registry.registry.length).to.equal(1) }) it('should have dynamic and static styles', () => { @@ -82,7 +79,7 @@ describe('React-JSS: dynamic styles', () => { ) const props = renderer.root.findByType(NoRenderer).props - expect(props.classes.button).to.equal('button-0 button-1') + expect(props.classes.button).to.equal('button-0 button-0-1') }) it('should generate different dynamic values', () => { diff --git a/packages/react-jss/tests/theming.js b/packages/react-jss/tests/theming.js index 93c7155f2..8619cc597 100644 --- a/packages/react-jss/tests/theming.js +++ b/packages/react-jss/tests/theming.js @@ -127,7 +127,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry.length).to.equal(2) + expect(registry.registry.length).to.equal(1) }) it('one themed instance wo/ = 1 style, theme update = 1 style', () => { @@ -164,7 +164,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry.length).to.equal(2) + expect(registry.registry.length).to.equal(1) renderer.update( @@ -175,8 +175,7 @@ describe('React-JSS: theming', () => { ) expect(registry.registry[0].attached).to.be(false) - expect(registry.registry[1].attached).to.be(false) - expect(registry.registry.length).to.equal(4) + expect(registry.registry.length).to.equal(2) }) it('two themed instances wo/ dynamic props w/ same theme = 1 style', () => { @@ -204,7 +203,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry.length).to.equal(3) + expect(registry.registry.length).to.equal(1) }) it('two themed instances w/ dynamic props w/ same theme = 3 styles, theme update = 3 styles', () => { @@ -218,7 +217,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry.length).to.equal(3) + expect(registry.registry.length).to.equal(1) renderer.update( @@ -230,9 +229,7 @@ describe('React-JSS: theming', () => { ) expect(registry.registry[0].attached).to.equal(false) - expect(registry.registry[1].attached).to.equal(false) - expect(registry.registry[2].attached).to.equal(false) - expect(registry.registry.length).to.equal(6) + expect(registry.registry.length).to.equal(2) }) it('two themed instances wo/ dynamic props w/ same theme = 1 styles, different theme update = 2 styles', () => { @@ -277,7 +274,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry.length).to.equal(3) + expect(registry.registry.length).to.equal(1) renderer.update( @@ -290,8 +287,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry[2].attached).to.equal(false) - expect(registry.registry.length).to.equal(5) + expect(registry.registry.length).to.equal(2) }) it('two themed instances wo/ dynamic props w/ different themes = 2 styles, same theme update = 1 style', () => { @@ -337,7 +333,7 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry.length).to.equal(4) + expect(registry.registry.length).to.equal(2) renderer.update( @@ -350,9 +346,8 @@ describe('React-JSS: theming', () => { ) - expect(registry.registry[2].attached).to.equal(false) - expect(registry.registry[3].attached).to.equal(false) - expect(registry.registry.length).to.equal(5) + expect(registry.registry[1].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) }) describe('when theming object returned from createTheming is provided to injectSheet options', () => { From 0768cae37f9ab3916d3d1580df40e9fb4f23b63b Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 2 Mar 2019 20:48:59 +0100 Subject: [PATCH 03/52] Fix a few tests --- packages/react-jss/src/JssProvider.test.js | 4 +- packages/react-jss/tests/dynamic-styles.js | 56 +++++++++++----------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/packages/react-jss/src/JssProvider.test.js b/packages/react-jss/src/JssProvider.test.js index 9eb6ada41..0a60c2971 100644 --- a/packages/react-jss/src/JssProvider.test.js +++ b/packages/react-jss/src/JssProvider.test.js @@ -260,7 +260,7 @@ describe('React-JSS: JssProvider', () => { .button-0 { color: red; } - .button-1 { + .button-0-1 { border: green; } `) @@ -278,7 +278,7 @@ describe('React-JSS: JssProvider', () => { .button-0 { color: red; } - .button-1 { + .button-0-1 { border: blue; } `) diff --git a/packages/react-jss/tests/dynamic-styles.js b/packages/react-jss/tests/dynamic-styles.js index b1a0087ea..948d25a06 100644 --- a/packages/react-jss/tests/dynamic-styles.js +++ b/packages/react-jss/tests/dynamic-styles.js @@ -94,10 +94,10 @@ describe('React-JSS: dynamic styles', () => { .button-0 { color: ${color}; } - .button-1 { + .button-0-1 { height: 10px; } - .button-2 { + .button-1-2 { height: 20px; } `) @@ -118,10 +118,10 @@ describe('React-JSS: dynamic styles', () => { .button-0 { color: ${color}; } - .button-1 { + .button-0-1 { height: 10px; } - .button-2 { + .button-1-2 { height: 20px; } `) @@ -132,10 +132,10 @@ describe('React-JSS: dynamic styles', () => { .button-0 { color: ${color}; } - .button-1 { + .button-0-1 { height: 20px; } - .button-2 { + .button-1-2 { height: 40px; } `) @@ -161,7 +161,7 @@ describe('React-JSS: dynamic styles', () => { .button-0 { width: 10px; } - .button-1 { + .button-0-1 { height: 10px; } `) @@ -172,7 +172,7 @@ describe('React-JSS: dynamic styles', () => { .button-0 { width: 10px; } - .button-1 {} + .button-0-1 {} `) }) @@ -198,7 +198,8 @@ describe('React-JSS: dynamic styles', () => { .button0-0 { width: 10px; } - .button1-2 { + .button1-1 {} + .button1-0-2 { height: 10px; } `) @@ -209,7 +210,8 @@ describe('React-JSS: dynamic styles', () => { .button0-0 { width: 10px; } - .button1-2 {} + .button1-1 {} + .button1-0-2 {} `) }) @@ -256,14 +258,12 @@ describe('React-JSS: dynamic styles', () => { ) - expect(registry.registry.length).to.equal(2) + expect(registry.registry.length).to.equal(1) expect(registry.registry[0].attached).to.equal(true) - expect(registry.registry[1].attached).to.equal(true) renderer.unmount() expect(registry.registry[0].attached).to.equal(false) - expect(registry.registry[1].attached).to.equal(false) }) it('should have correct meta attribute', () => { @@ -273,8 +273,7 @@ describe('React-JSS: dynamic styles', () => { ) - expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed, Static') - expect(registry.registry[1].options.meta).to.equal('NoRenderer, Unthemed, Dynamic') + expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed') }) it('should reuse static sheet, but generate separate dynamic once', () => { @@ -285,7 +284,7 @@ describe('React-JSS: dynamic styles', () => { ) - expect(registry.registry.length).to.equal(3) + expect(registry.registry.length).to.equal(1) }) it('should have dynamic and static styles', () => { @@ -296,7 +295,7 @@ describe('React-JSS: dynamic styles', () => { ) const props = renderer.root.findByType(NoRenderer).props - expect(props.classes.button).to.equal('button-0 button-1') + expect(props.classes.button).to.equal('button-0 button-0-1') }) it('should generate different dynamic values', () => { @@ -307,18 +306,17 @@ describe('React-JSS: dynamic styles', () => { ) - expect(removeWhitespaces(registry.toString())).to.equal( - removeWhitespaces(` - .button-1 { - color: ${color}; - height: 10px; - } - .button-2 { - color: ${color}; - height: 20px; - } - `) - ) + expect(registry.toString()).to.equal(stripIndent` + .button-0 { + color: rgb(255,255,255); + } + .button-0-1 { + height: 10px; + } + .button-1-2 { + height: 20px; + } + `) }) it('should update dynamic values', () => { From d017126c6d8362319670ca8db043201e2cd0221a Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 2 Mar 2019 21:59:43 +0100 Subject: [PATCH 04/52] Fix tests --- packages/react-jss/.size-snapshot.json | 24 ++-- packages/react-jss/src/withStyles.js | 136 +++++++++++---------- packages/react-jss/tests/dynamic-styles.js | 75 ++++++------ 3 files changed, 116 insertions(+), 119 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index e4a078f43..e1b2902c3 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 110413, - "minified": 37067, - "gzipped": 11910 + "bundled": 110518, + "minified": 37015, + "gzipped": 11920 }, "dist/react-jss.min.js": { - "bundled": 85874, - "minified": 29821, - "gzipped": 9737 + "bundled": 85979, + "minified": 29769, + "gzipped": 9748 }, "dist/react-jss.cjs.js": { - "bundled": 15398, - "minified": 7076, - "gzipped": 2369 + "bundled": 15499, + "minified": 7024, + "gzipped": 2378 }, "dist/react-jss.esm.js": { - "bundled": 14717, - "minified": 6496, - "gzipped": 2249, + "bundled": 14818, + "minified": 6444, + "gzipped": 2259, "treeshaked": { "rollup": { "code": 1946, diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index e0cf713b2..eec077314 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -62,8 +62,6 @@ export default function withStyles>( return ( InnerComponent: ComponentType = NoRenderer ): ComponentType => { - let instanceCounter = 0; - const displayName = getDisplayName(InnerComponent) const defaultClassNamePrefix = process.env.NODE_ENV === 'production' ? '' : `${displayName}-` const managerId = managersCounter++ @@ -79,13 +77,66 @@ export default function withStyles>( // $FlowFixMe static defaultProps = {...InnerComponent.defaultProps} + static getSheetClasses(sheet, dynamicRules: ?DynamicRules) { + const classes = {}; + + // $FlowFixMe + for (const key in sheet.styles) { + classes[key] = sheet.classes[key]; + + if (dynamicRules && key in dynamicRules) { + classes[key] += ` ${sheet.classes[dynamicRules[key].key]}` + } + } + + return classes; + } + + static updateDynamicRules(props: HOCProps, { dynamicRules, sheet }: State) { + if (!sheet) { + return; + } + + for (const key in dynamicRules) { + // $FlowFixMe: Not sure why it throws an error here + sheet.update(dynamicRules[key].key, props, {}); + } + } + + static removeDynamicRules(props: Props, { dynamicRules, sheet }: State) { + if (!sheet) { + return; + } + + for (const key in dynamicRules) { + sheet.deleteRule(dynamicRules[key].key); + } + } + + static addDynamicStyles(sheet: StyleSheet): ?DynamicRules { + // $FlowFixMe Cannot access random fields on instance of class StyleSheet + if (!sheet.dynamicStyles) return undefined + + const rules: DynamicRules = {}; + + for (const key in sheet.dynamicStyles) { + // $FlowFixMe + const ruleKey = `${key}-${sheet.dynamicRuleCounter++}`; + const rule = sheet.addRule(ruleKey, sheet.dynamicStyles[key]); + + if (rule) { + rules[key] = rule; + } + } + + return rules; + } + mergeClassesProp = memoize( (sheetClasses, classesProp) => classesProp ? mergeClasses(sheetClasses, classesProp) : sheetClasses ) - instanceId = instanceCounter++ - constructor(props: HOCProps) { super(props) @@ -98,7 +149,7 @@ export default function withStyles>( } componentDidUpdate(prevProps: HOCProps, prevState: State) { - this.updateDynamicRules(this.props, this.state) + WithStyles.updateDynamicRules(this.props, this.state) if (isThemingEnabled && this.props.theme !== prevProps.theme) { const newState = this.createState() @@ -135,16 +186,16 @@ export default function withStyles>( getSheet(): StyleSheet { const theme = getTheme(this.props) - let staticSheet = this.manager.get(theme) + let sheet = this.manager.get(theme) - if (staticSheet) { - return staticSheet + if (sheet) { + return sheet } const themedStyles = getStyles(styles, theme, displayName) const dynamicStyles = getDynamicStyles(themedStyles) const contextSheetOptions = this.props.jssContext.sheetOptions - staticSheet = this.jss.createStyleSheet(themedStyles, { + sheet = this.jss.createStyleSheet(themedStyles, { ...sheetOptions, ...contextSheetOptions, index, @@ -152,33 +203,19 @@ export default function withStyles>( classNamePrefix: this.classNamePrefix, link: dynamicStyles !== null }) - this.manager.add(theme, staticSheet) - // $FlowFixMe Cannot add random fields to instance of class StyleSheet - staticSheet.dynamicStyles = dynamicStyles // $FlowFixMe Cannot add random fields to instance of class StyleSheet - staticSheet.styles = themedStyles; + sheet.dynamicStyles = dynamicStyles - return staticSheet - } - - getSheetClasses(sheet) { - const classes = {}; + // $FlowFixMe Cannot add random fields to instance of class StyleSheet + sheet.styles = themedStyles; // $FlowFixMe - for (const key in sheet.styles) { - classes[key] = sheet.classes[key]; - } + sheet.dynamicRuleCounter = 0; - // $FlowFixMe - if (sheet.dynamicStyles) { - // $FlowFixMe - for (const key in sheet.dynamicStyles) { - classes[key] += ` ${sheet.classes[`${key}-${this.instanceId}`]}` - } - } + this.manager.add(theme, sheet) - return classes; + return sheet } classNamePrefix: string @@ -191,7 +228,7 @@ export default function withStyles>( return } - this.updateDynamicRules(props, state) + WithStyles.updateDynamicRules(props, state) this.manager.manage(getTheme(props)) if (registry) { @@ -199,57 +236,24 @@ export default function withStyles>( } } - updateDynamicRules(props, { dynamicRules, sheet }: State) { - if (!sheet) { - return; - } - - for (const key in dynamicRules) { - sheet.update(`${key}-${this.instanceId}`, props); - } - } - - removeDynamicRules(props: Props, { dynamicRules, sheet }: State) { - if (!sheet) { - return; - } - - for (const key in dynamicRules) { - sheet.deleteRule(`${key}-${this.instanceId}`); - } - } - unmanage(props, state: State) { - this.removeDynamicRules(props, state) + WithStyles.removeDynamicRules(props, state) this.manager.unmanage(getTheme(props)) } - addDynamicStyles(sheet: StyleSheet): ?DynamicRules { - // $FlowFixMe Cannot access random fields on instance of class StyleSheet - if (!sheet.dynamicStyles) return undefined - - const rules = {}; - - for (const key in sheet.dynamicStyles) { - rules[key] = sheet.addRule(`${key}-${this.instanceId}`, sheet.dynamicStyles[key]) - } - - return rules; - } - createState(): State { if (this.props.jssContext.disableStylesGeneration) { return {classes: {}} } const sheet = this.getSheet() - const dynamicRules = this.addDynamicStyles(sheet) + const dynamicRules = WithStyles.addDynamicStyles(sheet) return { sheet, dynamicRules, - classes: this.getSheetClasses(sheet), + classes: WithStyles.getSheetClasses(sheet, dynamicRules), } } diff --git a/packages/react-jss/tests/dynamic-styles.js b/packages/react-jss/tests/dynamic-styles.js index 948d25a06..9a28a5a50 100644 --- a/packages/react-jss/tests/dynamic-styles.js +++ b/packages/react-jss/tests/dynamic-styles.js @@ -1,13 +1,12 @@ /* eslint-disable global-require, react/prop-types, react/no-find-dom-node, react/no-multi-comp, react/prefer-stateless-function */ import expect from 'expect.js' -import React, {PureComponent} from 'react' +import React from 'react' import TestRenderer from 'react-test-renderer' import {stripIndent} from 'common-tags' import injectSheet, {JssProvider, SheetsRegistry} from '../src' -const removeWhitespaces = str => str.replace(/\s/g, '') const createGenerateId = () => { let counter = 0 return rule => `${rule.key}-${counter++}` @@ -200,7 +199,7 @@ describe('React-JSS: dynamic styles', () => { } .button1-1 {} .button1-0-2 { - height: 10px; + height: 10; } `) @@ -307,13 +306,13 @@ describe('React-JSS: dynamic styles', () => { ) expect(registry.toString()).to.equal(stripIndent` - .button-0 { - color: rgb(255,255,255); - } + .button-0 {} .button-0-1 { + color: rgb(255, 255, 255); height: 10px; } .button-1-2 { + color: rgb(255, 255, 255); height: 20px; } `) @@ -321,47 +320,41 @@ describe('React-JSS: dynamic styles', () => { it('should update dynamic values', () => { const generateId = createGenerateId() - class Container extends PureComponent { - render() { - const {height} = this.props - return ( - - - - - ) - } + function Container({height}) { + return ( + + + + + ) } const renderer = TestRenderer.create() - expect(removeWhitespaces(registry.toString())).to.equal( - removeWhitespaces(` - .button-1 { - color: ${color}; - height: 10px; - } - .button-2 { - color: ${color}; - height: 20px; - } - `) - ) - + expect(registry.toString()).to.equal(stripIndent` + .button-0 {} + .button-0-1 { + color: ${color}; + height: 10px; + } + .button-1-2 { + color: ${color}; + height: 20px; + } + `) renderer.update() - expect(removeWhitespaces(registry.toString())).to.equal( - removeWhitespaces(` - .button-1 { - color: ${color}; - height: 20px; - } - .button-2 { - color: ${color}; - height: 40px; - } - `) - ) + expect(registry.toString()).to.equal(stripIndent` + .button-0 {} + .button-0-1 { + color: ${color}; + height: 20px; + } + .button-1-2 { + color: ${color}; + height: 40px; + } + `) }) it('should use the default props', () => { From 85cec4ea25b8084cd9497f6a108d3b9fcd695250 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 2 Mar 2019 22:08:34 +0100 Subject: [PATCH 05/52] Format code --- packages/react-jss/src/types.js | 4 +-- packages/react-jss/src/withStyles.js | 40 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/react-jss/src/types.js b/packages/react-jss/src/types.js index e15c80e8c..7d5faa398 100644 --- a/packages/react-jss/src/types.js +++ b/packages/react-jss/src/types.js @@ -33,8 +33,8 @@ export type InnerProps = { } export type DynamicRules = { - [key: string]: BaseRule, -}; + [key: string]: BaseRule +} export type ThemedStyles = (theme: Theme) => StaticStyles export type Styles = StaticStyles | ThemedStyles diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index eec077314..6eff87a8e 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -13,9 +13,9 @@ import defaultJss from './jss' import JssContext from './JssContext' interface State { - dynamicRules?: ?DynamicRules, - sheet?: StyleSheet, - classes: {} + dynamicRules?: ?DynamicRules; + sheet?: StyleSheet; + classes: {}; } /** @@ -78,38 +78,38 @@ export default function withStyles>( static defaultProps = {...InnerComponent.defaultProps} static getSheetClasses(sheet, dynamicRules: ?DynamicRules) { - const classes = {}; + const classes = {} // $FlowFixMe for (const key in sheet.styles) { - classes[key] = sheet.classes[key]; + classes[key] = sheet.classes[key] if (dynamicRules && key in dynamicRules) { classes[key] += ` ${sheet.classes[dynamicRules[key].key]}` } } - return classes; + return classes } - static updateDynamicRules(props: HOCProps, { dynamicRules, sheet }: State) { + static updateDynamicRules(props: HOCProps, {dynamicRules, sheet}: State) { if (!sheet) { - return; + return } for (const key in dynamicRules) { // $FlowFixMe: Not sure why it throws an error here - sheet.update(dynamicRules[key].key, props, {}); + sheet.update(dynamicRules[key].key, props, {}) } } - static removeDynamicRules(props: Props, { dynamicRules, sheet }: State) { + static removeDynamicRules(props: Props, {dynamicRules, sheet}: State) { if (!sheet) { - return; + return } for (const key in dynamicRules) { - sheet.deleteRule(dynamicRules[key].key); + sheet.deleteRule(dynamicRules[key].key) } } @@ -117,19 +117,19 @@ export default function withStyles>( // $FlowFixMe Cannot access random fields on instance of class StyleSheet if (!sheet.dynamicStyles) return undefined - const rules: DynamicRules = {}; + const rules: DynamicRules = {} for (const key in sheet.dynamicStyles) { // $FlowFixMe - const ruleKey = `${key}-${sheet.dynamicRuleCounter++}`; - const rule = sheet.addRule(ruleKey, sheet.dynamicStyles[key]); + const ruleKey = `${key}-${sheet.dynamicRuleCounter++}` + const rule = sheet.addRule(ruleKey, sheet.dynamicStyles[key]) if (rule) { - rules[key] = rule; + rules[key] = rule } } - return rules; + return rules } mergeClassesProp = memoize( @@ -208,10 +208,10 @@ export default function withStyles>( sheet.dynamicStyles = dynamicStyles // $FlowFixMe Cannot add random fields to instance of class StyleSheet - sheet.styles = themedStyles; + sheet.styles = themedStyles // $FlowFixMe - sheet.dynamicRuleCounter = 0; + sheet.dynamicRuleCounter = 0 this.manager.add(theme, sheet) @@ -253,7 +253,7 @@ export default function withStyles>( return { sheet, dynamicRules, - classes: WithStyles.getSheetClasses(sheet, dynamicRules), + classes: WithStyles.getSheetClasses(sheet, dynamicRules) } } From 91f68824e47ce9690e23e2c3de4963779bc1f206 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Wed, 6 Mar 2019 21:26:05 +0100 Subject: [PATCH 06/52] Add comments --- packages/react-jss/.size-snapshot.json | 24 ++++++++++++------------ packages/react-jss/src/withStyles.js | 7 ++++++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index e1b2902c3..31ff8a049 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 110518, - "minified": 37015, - "gzipped": 11920 + "bundled": 110896, + "minified": 37012, + "gzipped": 11918 }, "dist/react-jss.min.js": { - "bundled": 85979, - "minified": 29769, - "gzipped": 9748 + "bundled": 86357, + "minified": 29766, + "gzipped": 9747 }, "dist/react-jss.cjs.js": { - "bundled": 15499, - "minified": 7024, - "gzipped": 2378 + "bundled": 15873, + "minified": 7021, + "gzipped": 2376 }, "dist/react-jss.esm.js": { - "bundled": 14818, - "minified": 6444, - "gzipped": 2259, + "bundled": 15192, + "minified": 6441, + "gzipped": 2257, "treeshaked": { "rollup": { "code": 1946, diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index 6eff87a8e..b6eb0ac1a 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -97,9 +97,11 @@ export default function withStyles>( return } + // Loop over each dynamic rule and update it + // We can't just update the whole sheet as this has all of the rules for every component instance for (const key in dynamicRules) { // $FlowFixMe: Not sure why it throws an error here - sheet.update(dynamicRules[key].key, props, {}) + sheet.update(dynamicRules[key].key, props) } } @@ -108,6 +110,8 @@ export default function withStyles>( return } + // Loop over each dynamic rule and remove the dynamic rule + // We can't just remove the whole sheet as this has all of the rules for every component instance for (const key in dynamicRules) { sheet.deleteRule(dynamicRules[key].key) } @@ -119,6 +123,7 @@ export default function withStyles>( const rules: DynamicRules = {} + // Loop over each dynamic rule and add it to the stylesheet for (const key in sheet.dynamicStyles) { // $FlowFixMe const ruleKey = `${key}-${sheet.dynamicRuleCounter++}` From 2ca10ebdd1ca978695ff47da04b8469bfb7d3f83 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 10 Mar 2019 09:19:26 +0100 Subject: [PATCH 07/52] Update changelog --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index a55b5f0af..2050a9d9e 100755 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,10 @@ - [react-jss] Replace spaces inside the display name with hyphens ([#1049](https://github.com/cssinjs/jss/pull/1049)) +### Improvements + +- [react-jss] Add dynamic rules to the static sheet ([#1048](https://github.com/cssinjs/jss/pull/1048)) + ## 10.0.0-alpha.12 (2019-2-27) ### Bug fixes From 45215c6a2fcc5d394ab64b2414cab681333789bb Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 10 Mar 2019 09:22:33 +0100 Subject: [PATCH 08/52] Update size-snapshot --- packages/react-jss/.size-snapshot.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 31ff8a049..58ad4c4b1 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,8 +1,8 @@ { "dist/react-jss.js": { - "bundled": 110896, - "minified": 37012, - "gzipped": 11918 + "bundled": 110916, + "minified": 37031, + "gzipped": 11929 }, "dist/react-jss.min.js": { "bundled": 86357, @@ -10,14 +10,14 @@ "gzipped": 9747 }, "dist/react-jss.cjs.js": { - "bundled": 15873, - "minified": 7021, - "gzipped": 2376 + "bundled": 15893, + "minified": 7040, + "gzipped": 2390 }, "dist/react-jss.esm.js": { - "bundled": 15192, - "minified": 6441, - "gzipped": 2257, + "bundled": 15212, + "minified": 6460, + "gzipped": 2271, "treeshaked": { "rollup": { "code": 1946, From 48f899d563ba4930677d931b4a5b04aea83f8940 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 10 Mar 2019 12:55:52 +0100 Subject: [PATCH 09/52] Initial draft --- packages/react-jss/src/JssContext.js | 2 +- .../react-jss/src/{ => hoc}/getDisplayName.js | 0 .../react-jss/src/{ => hoc}/withStyles.js | 131 ++++-------------- .../src/{ => hoc}/withStyles.test.js | 0 packages/react-jss/src/hook/index.js | 39 ++++++ packages/react-jss/src/types.js | 20 ++- packages/react-jss/src/utils/create-sheet.js | 65 +++++++++ packages/react-jss/src/utils/index-counter.js | 19 +++ packages/react-jss/src/utils/managers.js | 30 ++++ 9 files changed, 196 insertions(+), 110 deletions(-) rename packages/react-jss/src/{ => hoc}/getDisplayName.js (100%) rename packages/react-jss/src/{ => hoc}/withStyles.js (60%) rename packages/react-jss/src/{ => hoc}/withStyles.test.js (100%) create mode 100644 packages/react-jss/src/hook/index.js create mode 100644 packages/react-jss/src/utils/create-sheet.js create mode 100644 packages/react-jss/src/utils/index-counter.js create mode 100644 packages/react-jss/src/utils/managers.js diff --git a/packages/react-jss/src/JssContext.js b/packages/react-jss/src/JssContext.js index ddfb077d0..af7a44354 100644 --- a/packages/react-jss/src/JssContext.js +++ b/packages/react-jss/src/JssContext.js @@ -3,7 +3,7 @@ import React, {type Context} from 'react' import type {Context as JssContextValue} from './types' const JssContext: Context = React.createContext({ - sheetOptions: {}, + sheetOptions: { classNamePrefix: '' }, disableStylesGeneration: false }) diff --git a/packages/react-jss/src/getDisplayName.js b/packages/react-jss/src/hoc/getDisplayName.js similarity index 100% rename from packages/react-jss/src/getDisplayName.js rename to packages/react-jss/src/hoc/getDisplayName.js diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/hoc/withStyles.js similarity index 60% rename from packages/react-jss/src/withStyles.js rename to packages/react-jss/src/hoc/withStyles.js index 13a6fdf59..877b7c073 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/hoc/withStyles.js @@ -1,16 +1,16 @@ // @flow import React, {Component, type ComponentType, type Node} from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' -import {getDynamicStyles, SheetsManager, type StyleSheet} from 'jss' +import {type StyleSheet} from 'jss' import {ThemeContext} from 'theming' -import warning from 'tiny-warning' -import type {HOCProps, Options, Styles, InnerProps, DynamicRules} from './types' +import type {HOCProps, HOCOptions, Styles, InnerProps, DynamicRules} from '../types' import getDisplayName from './getDisplayName' -import memoize from './memoize-one' -import mergeClasses from './merge-classes' -import defaultJss from './jss' -import JssContext from './JssContext' +import memoize from '../memoize-one' +import mergeClasses from '../merge-classes' +import JssContext from '../JssContext' +import {getIndex} from '../utils/index-counter' +import {createSheet} from '../utils/create-sheet' interface State { dynamicRules?: ?DynamicRules; @@ -18,44 +18,20 @@ interface State { classes: {}; } -/** - * Global index counter to preserve source order. - * As we create the style sheet during componentWillMount lifecycle, - * children are handled after the parents, so the order of style elements would - * be parent->child. It is a problem though when a parent passes a className - * which needs to override any childs styles. StyleSheet of the child has a higher - * specificity, because of the source order. - * So our solution is to render sheets them in the reverse order child->sheet, so - * that parent has a higher specificity. - */ -let indexCounter = -100000 - -let managersCounter = 0 - const NoRenderer = (props: {children?: Node}) => props.children || null -const getStyles = (styles: Styles, theme: Theme, displayName: string) => { - if (typeof styles !== 'function') { - return styles - } - warning( - styles.length !== 0, - `[JSS] <${displayName} />'s styles function doesn't rely on the "theme" argument. We recommend declaring styles as an object instead.` - ) - - return styles(theme) -} +const noTheme = {} /** * HOC creator function that wrapps the user component. * * `withStyles(styles, [options])(Component)` */ -export default function withStyles>( - styles: S, - options?: Options = {} +export default function withStyles( + styles: Styles, + options?: HOCOptions = {} ) { - const {index = indexCounter++, theming, injectTheme, jss: optionsJss, ...sheetOptions} = options + const {index = getIndex(), theming, injectTheme} = options const isThemingEnabled = typeof styles === 'function' const ThemeConsumer = (theming && theming.context.Consumer) || ThemeContext.Consumer @@ -63,14 +39,6 @@ export default function withStyles>( InnerComponent: ComponentType = NoRenderer ): ComponentType => { const displayName = getDisplayName(InnerComponent) - const defaultClassNamePrefix = - process.env.NODE_ENV === 'production' ? '' : `${displayName.replace(/\s/g, '-')}-` - const managerId = managersCounter++ - const manager = new SheetsManager() - const noTheme = {} - // $FlowFixMe - const getTheme = (props: HOCProps): Theme => - isThemingEnabled && props.theme ? props.theme : noTheme class WithStyles extends Component, State> { static displayName = `WithStyles(${displayName})` @@ -146,10 +114,6 @@ export default function withStyles>( constructor(props: HOCProps) { super(props) - const {sheetOptions: contextSheetOptions} = props.jssContext - - this.classNamePrefix = (contextSheetOptions.classNamePrefix || '') + defaultClassNamePrefix - this.state = this.createState() this.manage(props, this.state) } @@ -171,59 +135,6 @@ export default function withStyles>( this.unmanage(this.props, this.state) } - get jss() { - return this.props.jssContext.jss || optionsJss || defaultJss - } - - get manager(): SheetsManager { - const {managers} = this.props.jssContext - - // If `managers` map is present in the context, we use it in order to - // let JssProvider reset them when new response has to render server-side. - if (managers) { - if (!managers[managerId]) { - managers[managerId] = new SheetsManager() - } - return managers[managerId] - } - - return manager - } - - getSheet(): StyleSheet { - const theme = getTheme(this.props) - let sheet = this.manager.get(theme) - - if (sheet) { - return sheet - } - - const themedStyles = getStyles(styles, theme, displayName) - const dynamicStyles = getDynamicStyles(themedStyles) - const contextSheetOptions = this.props.jssContext.sheetOptions - sheet = this.jss.createStyleSheet(themedStyles, { - ...sheetOptions, - ...contextSheetOptions, - index, - meta: `${displayName}, ${isThemingEnabled ? 'Themed' : 'Unthemed'}`, - classNamePrefix: this.classNamePrefix, - link: dynamicStyles !== null - }) - - // $FlowFixMe Cannot add random fields to instance of class StyleSheet - sheet.dynamicStyles = dynamicStyles - - // $FlowFixMe Cannot add random fields to instance of class StyleSheet - sheet.styles = themedStyles - - // $FlowFixMe - sheet.dynamicRuleCounter = 0 - - this.manager.add(theme, sheet) - - return sheet - } - classNamePrefix: string manage(props, state) { @@ -249,11 +160,18 @@ export default function withStyles>( } createState(): State { - if (this.props.jssContext.disableStylesGeneration) { + const sheet = createSheet({ + styles, + theme: this.props.theme, + index, + name: displayName, + jssContext: this.props.jssContext, + }); + + if (!sheet) { return {classes: {}} } - const sheet = this.getSheet() const dynamicRules = WithStyles.addDynamicStyles(sheet) return { @@ -292,7 +210,12 @@ export default function withStyles>( ) } - return + return }} )) diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/hoc/withStyles.test.js similarity index 100% rename from packages/react-jss/src/withStyles.test.js rename to packages/react-jss/src/hoc/withStyles.test.js diff --git a/packages/react-jss/src/hook/index.js b/packages/react-jss/src/hook/index.js new file mode 100644 index 000000000..4bf040732 --- /dev/null +++ b/packages/react-jss/src/hook/index.js @@ -0,0 +1,39 @@ +// @flow + +import React from 'react' +import {ThemeContext as DefaultThemeContext} from 'theming' + +import JssContext from '../JssContext'; +import {createSheet} from '../utils/create-sheet' +import {getIndex} from '../utils/index-counter' +import type {HookOptions, Styles} from '../types' + +const noTheme = {}; + +function createUseStyles(styles: Styles, options?: HookOptions = {}) { + const {index = getIndex(), theming, name = '', ...sheetOptions} = options; + const ThemeContext = (theming && theming.context) || DefaultThemeContext + + return (data) => { + const jssContext = React.useContext(JssContext); + const theme = typeof styles === 'function' ? React.useContext(ThemeContext) : noTheme; + + const sheet = React.useMemo(() => { + if (jssContext.disableStylesGeneration) { + return undefined; + } + + return createSheet({ + jssContext, + styles, + name, + theme, + index, + }); + }, [theme, jssContext]); + + return React.useMemo(() => { + + }, [sheet]); + }; +} \ No newline at end of file diff --git a/packages/react-jss/src/types.js b/packages/react-jss/src/types.js index 7d5faa398..e3725b968 100644 --- a/packages/react-jss/src/types.js +++ b/packages/react-jss/src/types.js @@ -7,22 +7,32 @@ type StaticStyles = {[key: string]: {}} export type Managers = {[key: number]: SheetsManager} -export type Options = { +type StyleSheetOptions = StyleSheetFactoryOptions & { + classNamePrefix: '', +} + +export type HookOptions = StyleSheetFactoryOptions & { + index?: number, + name?: string, + theming?: Theming, +} + +export type HOCOptions = StyleSheetFactoryOptions & { + index?: number, theming?: Theming, injectTheme?: boolean, - jss?: Jss -} & StyleSheetFactoryOptions +} export type Context = { jss?: Jss, registry?: SheetsRegistry, managers?: Managers, - sheetOptions: StyleSheetFactoryOptions, + sheetOptions: StyleSheetOptions, disableStylesGeneration: boolean } export type HOCProps = Props & { - theme?: Theme, + theme: Theme, jssContext: Context, innerRef: any } diff --git a/packages/react-jss/src/utils/create-sheet.js b/packages/react-jss/src/utils/create-sheet.js new file mode 100644 index 000000000..1586f1a9e --- /dev/null +++ b/packages/react-jss/src/utils/create-sheet.js @@ -0,0 +1,65 @@ +// @flow +import warning from 'tiny-warning' +import {getDynamicStyles} from 'jss' +import type {Context, Styles} from '../types' +import {getManager} from './managers' +import defaultJss from '../jss' + +interface Options { + jssContext: Context, + theme: Theme, + name: string, + index: number, + styles: Styles, +} + +const getStyles = (options: Options) => { + const {styles} = options; + if (typeof styles !== 'function') { + return styles + } + + warning( + styles.length !== 0, + `[JSS] <${options.name} />'s styles function doesn't rely on the "theme" argument. We recommend declaring styles as an object instead.` + ) + + return styles(options.theme) +} + +function getSheetOptions(options: Options, link: boolean) { + return { + // TODO + // ...sheetOptions, + ...options.jssContext.sheetOptions, + index: options.index, + meta: `${options.name}, ${typeof options.styles === 'function' ? 'Themed' : 'Unthemed'}`, + classNamePrefix: options.jssContext.sheetOptions.classNamePrefix + process.env.NODE_ENV === 'production' ? '' : `${options.name.replace(/\s/g, '-')}-`, + link, + }; +} + + +function createSheet(options: Options) { + const manager = getManager(options.jssContext, options.index); + const existingSheet = manager.get(options.theme) + + if (existingSheet) { + return existingSheet + } + + const jss = options.jssContext.jss || defaultJss + const styles = getStyles(options) + const dynamicStyles = getDynamicStyles(styles) + const sheet = jss.createStyleSheet(styles, getSheetOptions(options, dynamicStyles !== null)) + + sheet.dynamicStyles = dynamicStyles + sheet.styles = styles + sheet.dynamicRuleCounter = 0 + + manager.add(options.theme, sheet) + + return sheet; +} + +export {createSheet} \ No newline at end of file diff --git a/packages/react-jss/src/utils/index-counter.js b/packages/react-jss/src/utils/index-counter.js new file mode 100644 index 000000000..00adfcca8 --- /dev/null +++ b/packages/react-jss/src/utils/index-counter.js @@ -0,0 +1,19 @@ +// @flow + +/** + * Global index counter to preserve source order. + * As we create the style sheet during componentWillMount lifecycle, + * children are handled after the parents, so the order of style elements would + * be parent->child. It is a problem though when a parent passes a className + * which needs to override any childs styles. StyleSheet of the child has a higher + * specificity, because of the source order. + * So our solution is to render sheets them in the reverse order child->sheet, so + * that parent has a higher specificity. + */ +let index = 0 + +function getIndex() { + return index++; +} + +export { getIndex }; diff --git a/packages/react-jss/src/utils/managers.js b/packages/react-jss/src/utils/managers.js new file mode 100644 index 000000000..44e57d48d --- /dev/null +++ b/packages/react-jss/src/utils/managers.js @@ -0,0 +1,30 @@ +// @flow + +import {SheetsManager} from 'jss' +import type {Context} from '../types' + +const defaultManagers = new Map(); + +function getManager(context: Context, managerId: number) { + // If `managers` map is present in the context, we use it in order to + // let JssProvider reset them when new response has to render server-side. + if (context.managers) { + if (!context.managers[managerId]) { + context.managers[managerId] = new SheetsManager() + } + return context.managers[managerId] + } + + let manager = defaultManagers.get(managerId); + + if (!manager) { + manager = new SheetsManager(); + defaultManagers.set(managerId, manager); + } + + return manager; +} + +export { + getManager, +} From 77693347816821c25281b2aaa6169a1f11d21a12 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 13 Apr 2019 12:01:32 +0200 Subject: [PATCH 10/52] Add missing dependency --- packages/react-jss/src/hook/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react-jss/src/hook/index.js b/packages/react-jss/src/hook/index.js index f424b35af..4a695a1a8 100644 --- a/packages/react-jss/src/hook/index.js +++ b/packages/react-jss/src/hook/index.js @@ -87,7 +87,10 @@ function createUseStyles(styles: Styles, options?: HookOptions // Only compute the sheet classes when there is a sheet, otherwise return an empty object // Because there are no deep properties, accessing any style will result in undefined - return React.useMemo(() => sheet ? getSheetClasses(sheet, dynamicRules) : {}, [sheet]) + return React.useMemo(() => (sheet ? getSheetClasses(sheet, dynamicRules) : {}), [ + sheet, + dynamicRules + ]) } } From 8fed8244ce2f9e06228eb845c0aede6487ab6280 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 14 Apr 2019 11:35:53 +0200 Subject: [PATCH 11/52] Fix some type issues --- package.json | 4 +- packages/jss-plugin-default-unit/src/index.js | 1 - packages/jss/src/PluginsRegistry.js | 1 - packages/react-jss/.size-snapshot.json | 30 +++--- packages/react-jss/src/hoc/index.js | 1 - packages/react-jss/src/hook/index.js | 6 +- packages/react-jss/src/index.js | 4 +- yarn.lock | 97 +++++-------------- 8 files changed, 45 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index 277ffdd77..67e816d40 100644 --- a/package.json +++ b/package.json @@ -87,8 +87,8 @@ "pre-commit": "^1.1.3", "prettier": "^1.13.5", "raf": "^3.4.0", - "react": "^16.4.1", - "react-test-renderer": "^16.7.0", + "react": "^16.8.6", + "react-test-renderer": "^16.8.6", "rimraf": "^2.5.4", "rollup": "^1.1.2", "rollup-plugin-babel": "^4.3.2", diff --git a/packages/jss-plugin-default-unit/src/index.js b/packages/jss-plugin-default-unit/src/index.js index 2348c81d3..3e5a5d444 100644 --- a/packages/jss-plugin-default-unit/src/index.js +++ b/packages/jss-plugin-default-unit/src/index.js @@ -80,7 +80,6 @@ export default function defaultUnit(options: Options = {}): Plugin { } function onChangeValue(value, prop) { - // $FlowFixMe return iterate(prop, value, camelCasedOptions) } diff --git a/packages/jss/src/PluginsRegistry.js b/packages/jss/src/PluginsRegistry.js index 81d5f885a..6f2e5c3f6 100644 --- a/packages/jss/src/PluginsRegistry.js +++ b/packages/jss/src/PluginsRegistry.js @@ -59,7 +59,6 @@ export default class PluginsRegistry { this.registry.onProcessRule[i](rule, sheet) } - // $FlowFixMe if (rule.style) this.onProcessStyle(rule.style, rule, sheet) rule.isProcessed = true diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 26f1df859..f591b463e 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/react-jss.js": { - "bundled": 112436, - "minified": 37717, - "gzipped": 12195 + "bundled": 113073, + "minified": 37750, + "gzipped": 12216 }, "dist/react-jss.min.js": { - "bundled": 87875, - "minified": 30433, - "gzipped": 10023 + "bundled": 88512, + "minified": 30466, + "gzipped": 10038 }, "dist/react-jss.cjs.js": { - "bundled": 15563, - "minified": 7161, - "gzipped": 2471 + "bundled": 18374, + "minified": 8523, + "gzipped": 2769 }, "dist/react-jss.esm.js": { - "bundled": 14882, - "minified": 6581, - "gzipped": 2353, + "bundled": 17581, + "minified": 7833, + "gzipped": 2645, "treeshaked": { "rollup": { - "code": 1946, - "import_statements": 457 + "code": 1881, + "import_statements": 410 }, "webpack": { - "code": 3346 + "code": 3237 } } } diff --git a/packages/react-jss/src/hoc/index.js b/packages/react-jss/src/hoc/index.js index 9e4d8fb65..3298d63c6 100644 --- a/packages/react-jss/src/hoc/index.js +++ b/packages/react-jss/src/hoc/index.js @@ -137,7 +137,6 @@ export function withStyles(styles: Styles, options?: HOCOptions ( {context => { diff --git a/packages/react-jss/src/hook/index.js b/packages/react-jss/src/hook/index.js index 4a695a1a8..037cd1364 100644 --- a/packages/react-jss/src/hook/index.js +++ b/packages/react-jss/src/hook/index.js @@ -1,6 +1,6 @@ // @flow -import React, {useEffect, useLayoutEffect} from 'react' +import React from 'react' import {ThemeContext as DefaultThemeContext} from 'theming' import {JssContext} from '../JssContext' @@ -63,7 +63,7 @@ function createUseStyles(styles: Styles, options?: HookOptions ) // Update the dynamic rules before the actual render if the data has changed - useLayoutEffect( + React.useLayoutEffect( () => { updateDynamicRules(data, sheet, dynamicRules) }, @@ -71,7 +71,7 @@ function createUseStyles(styles: Styles, options?: HookOptions ) // Remove the old sheet when the sheet has changed after the render - useEffect( + React.useEffect( () => () => { removeDynamicRules(sheet, dynamicRules) diff --git a/packages/react-jss/src/index.js b/packages/react-jss/src/index.js index 77c4ffd36..793a3e80d 100644 --- a/packages/react-jss/src/index.js +++ b/packages/react-jss/src/index.js @@ -1,6 +1,6 @@ // @flow -import {withStyles} from './hoc' -import {createUseStyles} from './hook' +import {withStyles} from './hoc/index' +import {createUseStyles} from './hook/index' export {ThemeProvider, withTheme, createTheming} from 'theming' export {JssProvider} from './JssProvider' diff --git a/yarn.lock b/yarn.lock index 4eff8c70c..af5f884ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1889,7 +1889,7 @@ arrify@^1.0.0, arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@^2.0.0, asap@~2.0.3: +asap@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -3016,11 +3016,6 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= - core-js@^2.2.0: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -4129,19 +4124,6 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fbjs@^0.8.16: - version "0.8.17" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" - integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -5363,7 +5345,7 @@ is-resolvable@^1.1.0: resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== -is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -5446,14 +5428,6 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -6740,14 +6714,6 @@ node-fetch-npm@^2.0.2: json-parse-better-errors "^1.0.0" safe-buffer "^5.1.1" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - node-gyp@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" @@ -7584,13 +7550,6 @@ promise-retry@^1.1.1: err-code "^1.0.0" retry "^0.10.0" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - promzard@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" @@ -7780,30 +7739,30 @@ react-is@^16.3.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.0.tgz#456645144581a6e99f6816ae2bd24ee94bdd0c01" integrity sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g== -react-is@^16.7.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa" - integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g== +react-is@^16.8.6: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" + integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== -react-test-renderer@^16.7.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.7.0.tgz#1ca96c2b450ab47c36ba92cd8c03fcefc52ea01c" - integrity sha512-tFbhSjknSQ6+ttzmuGdv+SjQfmvGcq3PFKyPItohwhhOBmRoTf1We3Mlt3rJtIn85mjPXOkKV+TaKK4irvk9Yg== +react-test-renderer@^16.8.6: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.6.tgz#188d8029b8c39c786f998aa3efd3ffe7642d5ba1" + integrity sha512-H2srzU5IWYT6cZXof6AhUcx/wEyJddQ8l7cLM/F7gDXYyPr4oq+vCIxJYXVGhId1J706sqziAjuOEjyNkfgoEw== dependencies: object-assign "^4.1.1" prop-types "^15.6.2" - react-is "^16.7.0" - scheduler "^0.12.0" + react-is "^16.8.6" + scheduler "^0.13.6" -react@^16.4.1: - version "16.4.2" - resolved "https://registry.yarnpkg.com/react/-/react-16.4.2.tgz#2cd90154e3a9d9dd8da2991149fdca3c260e129f" - integrity sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg== +react@^16.8.6: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe" + integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw== dependencies: - fbjs "^0.8.16" loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.0" + prop-types "^15.6.2" + scheduler "^0.13.6" read-cmd-shim@^1.0.1: version "1.0.1" @@ -8398,10 +8357,10 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.12.0.tgz#8ab17699939c0aedc5a196a657743c496538647b" - integrity sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw== +scheduler@^0.13.6: + version "0.13.6" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889" + integrity sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -8483,7 +8442,7 @@ set-value@^2.0.0: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4, setimmediate@^1.0.5, setimmediate@~1.0.4: +setimmediate@^1.0.4, setimmediate@~1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -9351,11 +9310,6 @@ typescript@^3.1.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" integrity sha512-+81MUSyX+BaSo+u2RbozuQk/UWx6hfG0a5gHu4ANEM4sU96XbuIyAB+rWBW1u70c6a5QuZfuYICn3s2UjuHUpA== -ua-parser-js@^0.7.18: - version "0.7.18" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" - integrity sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA== - uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -9783,11 +9737,6 @@ webpack@^4.28.4: watchpack "^1.5.0" webpack-sources "^1.3.0" -whatwg-fetch@>=0.10.0: - version "2.0.4" - resolved "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - whatwg-url@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" From 11b0fcf4fbf37d7ddeeff588b02e6516d3b6a3ca Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 14 Apr 2019 11:39:09 +0200 Subject: [PATCH 12/52] Rename hook folder to create-use-styles and hoc to with-styles --- .eslintrc.js | 3 +++ .../{hook/index.js => create-use-styles.js} | 16 +++++++-------- .../react-jss/src/{hoc => }/getDisplayName.js | 0 .../src/{hoc/index.js => with-styles.js} | 20 +++++++++---------- .../index.test.js => with-styles.test.js} | 0 5 files changed, 21 insertions(+), 18 deletions(-) rename packages/react-jss/src/{hook/index.js => create-use-styles.js} (85%) rename packages/react-jss/src/{hoc => }/getDisplayName.js (100%) rename packages/react-jss/src/{hoc/index.js => with-styles.js} (91%) rename packages/react-jss/src/{hoc/index.test.js => with-styles.test.js} (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 4289250c3..65e34e946 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,6 +10,9 @@ module.exports = { __VERSION__: true, CSS: true }, + rules: { + 'import/prefer-default-export': 'off' + }, overrides: [ { files: ['docs/*.md', 'docs/**/*.md'], diff --git a/packages/react-jss/src/hook/index.js b/packages/react-jss/src/create-use-styles.js similarity index 85% rename from packages/react-jss/src/hook/index.js rename to packages/react-jss/src/create-use-styles.js index 037cd1364..57f5bcd25 100644 --- a/packages/react-jss/src/hook/index.js +++ b/packages/react-jss/src/create-use-styles.js @@ -3,14 +3,14 @@ import React from 'react' import {ThemeContext as DefaultThemeContext} from 'theming' -import {JssContext} from '../JssContext' -import {createSheet} from '../utils/create-sheet' -import {getIndex} from '../utils/index-counter' -import type {HookOptions, Styles} from '../types' -import {addDynamicRules, removeDynamicRules, updateDynamicRules} from '../utils/dynamic-rules' -import {manageSheet} from '../utils/manage-sheet' -import {unmanageSheet} from '../utils/unmanage-sheet' -import {getSheetClasses} from '../utils/get-sheet-classes' +import {JssContext} from './JssContext' +import {createSheet} from './utils/create-sheet' +import {getIndex} from './utils/index-counter' +import type {HookOptions, Styles} from './types' +import {addDynamicRules, removeDynamicRules, updateDynamicRules} from './utils/dynamic-rules' +import {manageSheet} from './utils/manage-sheet' +import {unmanageSheet} from './utils/unmanage-sheet' +import {getSheetClasses} from './utils/get-sheet-classes' const noTheme = {} diff --git a/packages/react-jss/src/hoc/getDisplayName.js b/packages/react-jss/src/getDisplayName.js similarity index 100% rename from packages/react-jss/src/hoc/getDisplayName.js rename to packages/react-jss/src/getDisplayName.js diff --git a/packages/react-jss/src/hoc/index.js b/packages/react-jss/src/with-styles.js similarity index 91% rename from packages/react-jss/src/hoc/index.js rename to packages/react-jss/src/with-styles.js index 3298d63c6..99eecddec 100644 --- a/packages/react-jss/src/hoc/index.js +++ b/packages/react-jss/src/with-styles.js @@ -4,17 +4,17 @@ import hoistNonReactStatics from 'hoist-non-react-statics' import {type StyleSheet} from 'jss' import {ThemeContext} from 'theming' -import type {HOCProps, HOCOptions, Styles, InnerProps, DynamicRules} from '../types' +import type {HOCProps, HOCOptions, Styles, InnerProps, DynamicRules} from './types' import getDisplayName from './getDisplayName' -import memoize from '../utils/memoize-one' -import mergeClasses from '../utils/merge-classes' -import {JssContext} from '../JssContext' -import {getIndex} from '../utils/index-counter' -import {createSheet} from '../utils/create-sheet' -import {addDynamicRules, removeDynamicRules, updateDynamicRules} from '../utils/dynamic-rules' -import {unmanageSheet} from '../utils/unmanage-sheet' -import {manageSheet} from '../utils/manage-sheet' -import {getSheetClasses} from '../utils/get-sheet-classes' +import memoize from './utils/memoize-one' +import mergeClasses from './utils/merge-classes' +import {JssContext} from './JssContext' +import {getIndex} from './utils/index-counter' +import {createSheet} from './utils/create-sheet' +import {addDynamicRules, removeDynamicRules, updateDynamicRules} from './utils/dynamic-rules' +import {unmanageSheet} from './utils/unmanage-sheet' +import {manageSheet} from './utils/manage-sheet' +import {getSheetClasses} from './utils/get-sheet-classes' interface State { dynamicRules: ?DynamicRules; diff --git a/packages/react-jss/src/hoc/index.test.js b/packages/react-jss/src/with-styles.test.js similarity index 100% rename from packages/react-jss/src/hoc/index.test.js rename to packages/react-jss/src/with-styles.test.js From b20f7ea3730d325712151b3ef3b0cdc1754e6228 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 14 Apr 2019 11:44:52 +0200 Subject: [PATCH 13/52] Unify some files --- packages/react-jss/src/create-use-styles.js | 8 +-- packages/react-jss/src/utils/dynamic-rules.js | 58 ------------------ packages/react-jss/src/utils/manage-sheet.js | 29 --------- packages/react-jss/src/utils/managers.js | 36 ++++++++++- .../src/utils/{create-sheet.js => sheets.js} | 60 +++++++++++++++++-- .../react-jss/src/utils/unmanage-sheet.js | 24 -------- packages/react-jss/src/with-styles.js | 8 +-- 7 files changed, 96 insertions(+), 127 deletions(-) delete mode 100644 packages/react-jss/src/utils/dynamic-rules.js delete mode 100644 packages/react-jss/src/utils/manage-sheet.js rename packages/react-jss/src/utils/{create-sheet.js => sheets.js} (53%) delete mode 100644 packages/react-jss/src/utils/unmanage-sheet.js diff --git a/packages/react-jss/src/create-use-styles.js b/packages/react-jss/src/create-use-styles.js index 57f5bcd25..466401272 100644 --- a/packages/react-jss/src/create-use-styles.js +++ b/packages/react-jss/src/create-use-styles.js @@ -4,12 +4,10 @@ import React from 'react' import {ThemeContext as DefaultThemeContext} from 'theming' import {JssContext} from './JssContext' -import {createSheet} from './utils/create-sheet' +import {createStaticSheet, addDynamicRules, removeDynamicRules, updateDynamicRules} from './utils/sheets' import {getIndex} from './utils/index-counter' import type {HookOptions, Styles} from './types' -import {addDynamicRules, removeDynamicRules, updateDynamicRules} from './utils/dynamic-rules' -import {manageSheet} from './utils/manage-sheet' -import {unmanageSheet} from './utils/unmanage-sheet' +import {unmanageSheet, manageSheet} from './utils/managers' import {getSheetClasses} from './utils/get-sheet-classes' const noTheme = {} @@ -29,7 +27,7 @@ function createUseStyles(styles: Styles, options?: HookOptions return undefined } - const stylesheet = createSheet({ + const stylesheet = createStaticSheet({ context: jssContext, styles, name, diff --git a/packages/react-jss/src/utils/dynamic-rules.js b/packages/react-jss/src/utils/dynamic-rules.js deleted file mode 100644 index fd390c4e0..000000000 --- a/packages/react-jss/src/utils/dynamic-rules.js +++ /dev/null @@ -1,58 +0,0 @@ -// @flow - -import type {StyleSheet} from 'jss' -import type {DynamicRules} from '../types' -import {getMetaForSheet} from './sheets-meta' - -const removeDynamicRules = (sheet: ?StyleSheet, rules: ?DynamicRules) => { - if (!sheet || !rules) { - return - } - - // Loop over each dynamic rule and remove the dynamic rule - // We can't just remove the whole sheet as this has all of the rules for every component instance - for (const key in rules) { - sheet.deleteRule(rules[key].key) - } -} - -const updateDynamicRules = (data: any, sheet: ?StyleSheet, rules: ?DynamicRules) => { - if (!sheet || !rules) { - return - } - - // Loop over each dynamic rule and update it - // We can't just update the whole sheet as this has all of the rules for every component instance - for (const key in rules) { - // $FlowFixMe - sheet.update(rules[key].key, data) - } -} - -const addDynamicRules = (sheet: ?StyleSheet): ?DynamicRules => { - if (!sheet) { - return undefined - } - - const meta = getMetaForSheet(sheet) - - if (!meta) { - return undefined - } - - const rules: DynamicRules = {} - - // Loop over each dynamic rule and add it to the stylesheet - for (const key in meta.dynamicStyles) { - const name = `${key}-${meta.dynamicRuleCounter++}` - const rule = sheet.addRule(name, meta.dynamicStyles[key]) - - if (rule) { - rules[key] = rule - } - } - - return rules -} - -export {addDynamicRules, updateDynamicRules, removeDynamicRules} diff --git a/packages/react-jss/src/utils/manage-sheet.js b/packages/react-jss/src/utils/manage-sheet.js deleted file mode 100644 index 2bc25d16d..000000000 --- a/packages/react-jss/src/utils/manage-sheet.js +++ /dev/null @@ -1,29 +0,0 @@ -// @flow - -import type {StyleSheet} from 'jss' -import type {Context} from '../types' -import {getManager} from './managers' - -interface Options { - sheet: ?StyleSheet; - context: Context; - index: number; - theme: Theme; -} - -const manageSheet = (options: Options) => { - const {sheet} = options - if (!sheet) { - return - } - - const manager = getManager(options.context, options.index) - - manager.manage(options.theme) - - if (options.context.registry) { - options.context.registry.add(sheet) - } -} - -export {manageSheet} diff --git a/packages/react-jss/src/utils/managers.js b/packages/react-jss/src/utils/managers.js index 69470d1a9..3c8dba2e9 100644 --- a/packages/react-jss/src/utils/managers.js +++ b/packages/react-jss/src/utils/managers.js @@ -1,6 +1,6 @@ // @flow -import {SheetsManager} from 'jss' +import {SheetsManager, type StyleSheet} from 'jss' import type {Context} from '../types' const defaultManagers = new Map() @@ -25,4 +25,36 @@ function getManager(context: Context, managerId: number) { return manager } -export {getManager} +interface Options { + sheet: ?StyleSheet; + context: Context; + index: number; + theme: Theme; +} + +const manageSheet = (options: Options) => { + const {sheet} = options + if (!sheet) { + return + } + + const manager = getManager(options.context, options.index) + + manager.manage(options.theme) + + if (options.context.registry) { + options.context.registry.add(sheet) + } +} + +const unmanageSheet = (options: Options) => { + if (!options.sheet) { + return + } + + const manager = getManager(options.context, options.index) + + manager.unmanage(options.theme) +} + +export {getManager, manageSheet, unmanageSheet} diff --git a/packages/react-jss/src/utils/create-sheet.js b/packages/react-jss/src/utils/sheets.js similarity index 53% rename from packages/react-jss/src/utils/create-sheet.js rename to packages/react-jss/src/utils/sheets.js index 1a741ebe3..d37f5548c 100644 --- a/packages/react-jss/src/utils/create-sheet.js +++ b/packages/react-jss/src/utils/sheets.js @@ -1,10 +1,11 @@ // @flow import warning from 'tiny-warning' import {getDynamicStyles, type StyleSheetFactoryOptions} from 'jss' -import type {Context, Styles} from '../types' +import type {Context, DynamicRules, Styles} from '../types' import {getManager} from './managers' import {jss as defaultJss} from '../jss' -import {addMetaForSheet} from './sheets-meta' +import {addMetaForSheet, getMetaForSheet} from './sheets-meta' +import type {StyleSheet} from 'jss' interface Options { context: Context; @@ -45,7 +46,7 @@ function getSheetOptions(options: Options, link: boolean) { } } -function createSheet(options: Options) { +function createStaticSheet(options: Options) { const manager = getManager(options.context, options.index) const existingSheet = manager.get(options.theme) @@ -69,4 +70,55 @@ function createSheet(options: Options) { return sheet } -export {createSheet} +const removeDynamicRules = (sheet: ?StyleSheet, rules: ?DynamicRules) => { + if (!sheet || !rules) { + return + } + + // Loop over each dynamic rule and remove the dynamic rule + // We can't just remove the whole sheet as this has all of the rules for every component instance + for (const key in rules) { + sheet.deleteRule(rules[key].key) + } +} + +const updateDynamicRules = (data: any, sheet: ?StyleSheet, rules: ?DynamicRules) => { + if (!sheet || !rules) { + return + } + + // Loop over each dynamic rule and update it + // We can't just update the whole sheet as this has all of the rules for every component instance + for (const key in rules) { + // $FlowFixMe + sheet.update(rules[key].key, data) + } +} + +const addDynamicRules = (sheet: ?StyleSheet): ?DynamicRules => { + if (!sheet) { + return undefined + } + + const meta = getMetaForSheet(sheet) + + if (!meta) { + return undefined + } + + const rules: DynamicRules = {} + + // Loop over each dynamic rule and add it to the stylesheet + for (const key in meta.dynamicStyles) { + const name = `${key}-${meta.dynamicRuleCounter++}` + const rule = sheet.addRule(name, meta.dynamicStyles[key]) + + if (rule) { + rules[key] = rule + } + } + + return rules +} + +export {addDynamicRules, updateDynamicRules, removeDynamicRules, createStaticSheet} diff --git a/packages/react-jss/src/utils/unmanage-sheet.js b/packages/react-jss/src/utils/unmanage-sheet.js deleted file mode 100644 index 1928dffa8..000000000 --- a/packages/react-jss/src/utils/unmanage-sheet.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow - -import type {StyleSheet} from 'jss' -import type {Context} from '../types' -import {getManager} from './managers' - -interface Options { - sheet: ?StyleSheet; - context: Context; - index: number; - theme: {}; -} - -const unmanageSheet = (options: Options) => { - if (!options.sheet) { - return - } - - const manager = getManager(options.context, options.index) - - manager.unmanage(options.theme) -} - -export {unmanageSheet} diff --git a/packages/react-jss/src/with-styles.js b/packages/react-jss/src/with-styles.js index 99eecddec..1586b644f 100644 --- a/packages/react-jss/src/with-styles.js +++ b/packages/react-jss/src/with-styles.js @@ -10,10 +10,8 @@ import memoize from './utils/memoize-one' import mergeClasses from './utils/merge-classes' import {JssContext} from './JssContext' import {getIndex} from './utils/index-counter' -import {createSheet} from './utils/create-sheet' -import {addDynamicRules, removeDynamicRules, updateDynamicRules} from './utils/dynamic-rules' -import {unmanageSheet} from './utils/unmanage-sheet' -import {manageSheet} from './utils/manage-sheet' +import {createStaticSheet, updateDynamicRules, addDynamicRules, removeDynamicRules} from './utils/sheets' +import {manageSheet, unmanageSheet} from './utils/managers' import {getSheetClasses} from './utils/get-sheet-classes' interface State { @@ -50,7 +48,7 @@ export function withStyles(styles: Styles, options?: HOCOptions Date: Sun, 14 Apr 2019 13:00:21 +0200 Subject: [PATCH 14/52] Fix imports --- packages/react-jss/src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-jss/src/index.js b/packages/react-jss/src/index.js index 793a3e80d..13daa7671 100644 --- a/packages/react-jss/src/index.js +++ b/packages/react-jss/src/index.js @@ -1,6 +1,6 @@ // @flow -import {withStyles} from './hoc/index' -import {createUseStyles} from './hook/index' +import {withStyles} from './with-styles' +import {createUseStyles} from './create-use-styles' export {ThemeProvider, withTheme, createTheming} from 'theming' export {JssProvider} from './JssProvider' From cf23380a380d0b359c50305a67483f8b4afbc6d6 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 14 Apr 2019 13:12:31 +0200 Subject: [PATCH 15/52] Fix some flow issues --- packages/react-jss/src/create-use-styles.js | 10 ++++++++-- packages/react-jss/src/utils/sheets.js | 2 +- packages/react-jss/src/with-styles.js | 15 +++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/react-jss/src/create-use-styles.js b/packages/react-jss/src/create-use-styles.js index 466401272..85dc878e6 100644 --- a/packages/react-jss/src/create-use-styles.js +++ b/packages/react-jss/src/create-use-styles.js @@ -4,7 +4,12 @@ import React from 'react' import {ThemeContext as DefaultThemeContext} from 'theming' import {JssContext} from './JssContext' -import {createStaticSheet, addDynamicRules, removeDynamicRules, updateDynamicRules} from './utils/sheets' +import { + createStaticSheet, + addDynamicRules, + removeDynamicRules, + updateDynamicRules +} from './utils/sheets' import {getIndex} from './utils/index-counter' import type {HookOptions, Styles} from './types' import {unmanageSheet, manageSheet} from './utils/managers' @@ -18,7 +23,8 @@ function createUseStyles(styles: Styles, options?: HookOptions return (data: any) => { const jssContext = React.useContext(JssContext) - const theme = typeof styles === 'function' ? React.useContext(ThemeContext) : noTheme + // $FlowFixMe + const theme: Theme = typeof styles === 'function' ? React.useContext(ThemeContext) : noTheme // When the theme or the context changes we create a new sheet const sheet = React.useMemo( diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index d37f5548c..235548ffb 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -13,7 +13,7 @@ interface Options { name: string; index: number; styles: Styles; - sheetOptions: $Diff; + sheetOptions: $Diff; } const getStyles = (options: Options) => { diff --git a/packages/react-jss/src/with-styles.js b/packages/react-jss/src/with-styles.js index 1586b644f..354db41d1 100644 --- a/packages/react-jss/src/with-styles.js +++ b/packages/react-jss/src/with-styles.js @@ -1,7 +1,7 @@ // @flow import React, {Component, type ComponentType, type Node} from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' -import {type StyleSheet} from 'jss' +import {type StyleSheet, type Classes} from 'jss' import {ThemeContext} from 'theming' import type {HOCProps, HOCOptions, Styles, InnerProps, DynamicRules} from './types' @@ -10,7 +10,12 @@ import memoize from './utils/memoize-one' import mergeClasses from './utils/merge-classes' import {JssContext} from './JssContext' import {getIndex} from './utils/index-counter' -import {createStaticSheet, updateDynamicRules, addDynamicRules, removeDynamicRules} from './utils/sheets' +import { + createStaticSheet, + updateDynamicRules, + addDynamicRules, + removeDynamicRules +} from './utils/sheets' import {manageSheet, unmanageSheet} from './utils/managers' import {getSheetClasses} from './utils/get-sheet-classes' @@ -39,7 +44,7 @@ export function withStyles(styles: Styles, options?: HOCOptions => { const displayName = getDisplayName(InnerComponent) - const getTheme = (props): Theme => isThemingEnabled ? props.theme : noTheme + const getTheme = (props): Theme => (isThemingEnabled ? props.theme : ((noTheme: any): Theme)) class WithStyles extends Component, State> { static displayName = `WithStyles(${displayName})` @@ -90,7 +95,7 @@ export function withStyles(styles: Styles, options?: HOCOptions( (sheetClasses, classesProp) => classesProp ? mergeClasses(sheetClasses, classesProp) : sheetClasses ) @@ -125,6 +130,7 @@ export function withStyles(styles: Styles, options?: HOCOptions(styles: Styles, options?: HOCOptions Date: Sun, 14 Apr 2019 15:14:26 +0200 Subject: [PATCH 16/52] Update size snapshots --- packages/jss-plugin-default-unit/.size-snapshot.json | 8 ++++---- packages/jss-preset-default/.size-snapshot.json | 4 ++-- packages/jss/.size-snapshot.json | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/jss-plugin-default-unit/.size-snapshot.json b/packages/jss-plugin-default-unit/.size-snapshot.json index c79ae39a2..051cd68c4 100644 --- a/packages/jss-plugin-default-unit/.size-snapshot.json +++ b/packages/jss-plugin-default-unit/.size-snapshot.json @@ -1,21 +1,21 @@ { "dist/jss-plugin-default-unit.js": { - "bundled": 5933, + "bundled": 5913, "minified": 2742, "gzipped": 1055 }, "dist/jss-plugin-default-unit.min.js": { - "bundled": 5933, + "bundled": 5913, "minified": 2742, "gzipped": 1055 }, "dist/jss-plugin-default-unit.cjs.js": { - "bundled": 5221, + "bundled": 5203, "minified": 2843, "gzipped": 1020 }, "dist/jss-plugin-default-unit.esm.js": { - "bundled": 5141, + "bundled": 5123, "minified": 2777, "gzipped": 965, "treeshaked": { diff --git a/packages/jss-preset-default/.size-snapshot.json b/packages/jss-preset-default/.size-snapshot.json index 0312049d3..768d536e4 100644 --- a/packages/jss-preset-default/.size-snapshot.json +++ b/packages/jss-preset-default/.size-snapshot.json @@ -1,11 +1,11 @@ { "dist/jss-preset-default.js": { - "bundled": 55231, + "bundled": 55211, "minified": 19104, "gzipped": 6356 }, "dist/jss-preset-default.min.js": { - "bundled": 54477, + "bundled": 54457, "minified": 18645, "gzipped": 6144 }, diff --git a/packages/jss/.size-snapshot.json b/packages/jss/.size-snapshot.json index a9c653e62..5f15402af 100644 --- a/packages/jss/.size-snapshot.json +++ b/packages/jss/.size-snapshot.json @@ -1,21 +1,21 @@ { "dist/jss.js": { - "bundled": 59675, + "bundled": 59660, "minified": 22216, "gzipped": 6638 }, "dist/jss.min.js": { - "bundled": 58509, + "bundled": 58494, "minified": 21298, "gzipped": 6195 }, "dist/jss.cjs.js": { - "bundled": 55077, + "bundled": 55062, "minified": 24175, "gzipped": 6695 }, "dist/jss.esm.js": { - "bundled": 54581, + "bundled": 54566, "minified": 23771, "gzipped": 6613, "treeshaked": { From cbef52d17ffd736a45034e1cdee1d7935739bed4 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 14 Apr 2019 15:17:48 +0200 Subject: [PATCH 17/52] Fix some eslint problems --- .eslintrc.js | 3 ++- packages/jss-starter-kit/.size-snapshot.json | 4 ++-- packages/react-jss/.size-snapshot.json | 20 ++++++++++---------- packages/react-jss/src/JssProvider.test.js | 2 +- packages/react-jss/src/utils/sheets.js | 2 +- packages/react-jss/src/with-styles.test.js | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 65e34e946..73d55c4af 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,8 @@ module.exports = { CSS: true }, rules: { - 'import/prefer-default-export': 'off' + 'import/prefer-default-export': 'off', + 'import/no-named-as-default': 'off' }, overrides: [ { diff --git a/packages/jss-starter-kit/.size-snapshot.json b/packages/jss-starter-kit/.size-snapshot.json index 777dac63f..4d93f7103 100644 --- a/packages/jss-starter-kit/.size-snapshot.json +++ b/packages/jss-starter-kit/.size-snapshot.json @@ -1,11 +1,11 @@ { "dist/jss-starter-kit.js": { - "bundled": 70773, + "bundled": 70753, "minified": 29117, "gzipped": 8981 }, "dist/jss-starter-kit.min.js": { - "bundled": 70019, + "bundled": 69999, "minified": 28659, "gzipped": 8769 }, diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index f591b463e..374fe3a07 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 113073, + "bundled": 113066, "minified": 37750, - "gzipped": 12216 + "gzipped": 12221 }, "dist/react-jss.min.js": { - "bundled": 88512, + "bundled": 88505, "minified": 30466, - "gzipped": 10038 + "gzipped": 10042 }, "dist/react-jss.cjs.js": { - "bundled": 18374, - "minified": 8523, - "gzipped": 2769 + "bundled": 18385, + "minified": 8541, + "gzipped": 2770 }, "dist/react-jss.esm.js": { - "bundled": 17581, - "minified": 7833, - "gzipped": 2645, + "bundled": 17592, + "minified": 7851, + "gzipped": 2647, "treeshaked": { "rollup": { "code": 1881, diff --git a/packages/react-jss/src/JssProvider.test.js b/packages/react-jss/src/JssProvider.test.js index 0a60c2971..928803f2b 100644 --- a/packages/react-jss/src/JssProvider.test.js +++ b/packages/react-jss/src/JssProvider.test.js @@ -6,7 +6,7 @@ import {stripIndent} from 'common-tags' import {create} from 'jss' import TestRenderer from 'react-test-renderer' -import withStyles, {SheetsRegistry, JssProvider} from '.' +import {SheetsRegistry, JssProvider, withStyles} from '.' const createGenerateId = () => { let counter = 0 diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index 235548ffb..c10bf7425 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -1,11 +1,11 @@ // @flow import warning from 'tiny-warning' import {getDynamicStyles, type StyleSheetFactoryOptions} from 'jss' +import type {StyleSheet} from 'jss' import type {Context, DynamicRules, Styles} from '../types' import {getManager} from './managers' import {jss as defaultJss} from '../jss' import {addMetaForSheet, getMetaForSheet} from './sheets-meta' -import type {StyleSheet} from 'jss' interface Options { context: Context; diff --git a/packages/react-jss/src/with-styles.test.js b/packages/react-jss/src/with-styles.test.js index 7957d498b..a8e7e6948 100644 --- a/packages/react-jss/src/with-styles.test.js +++ b/packages/react-jss/src/with-styles.test.js @@ -5,7 +5,7 @@ import React from 'react' import {spy} from 'sinon' import TestRenderer from 'react-test-renderer' -import withStyles, {JssProvider, SheetsRegistry} from '.' +import {withStyles, JssProvider, SheetsRegistry} from '.' const createGenerateId = () => { let counter = 0 From ad05c907fbd70323d8984c9b5c8a0eb3d82a03c1 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 15 Apr 2019 04:53:34 +0200 Subject: [PATCH 18/52] Update packages/react-jss/src/create-use-styles.js Co-Authored-By: HenriBeck --- packages/react-jss/src/create-use-styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-jss/src/create-use-styles.js b/packages/react-jss/src/create-use-styles.js index 85dc878e6..9b8a0bffd 100644 --- a/packages/react-jss/src/create-use-styles.js +++ b/packages/react-jss/src/create-use-styles.js @@ -33,7 +33,7 @@ function createUseStyles(styles: Styles, options?: HookOptions return undefined } - const stylesheet = createStaticSheet({ + const staticSheet = createStaticSheet({ context: jssContext, styles, name, From ae7841a43c18362adc4a2f1c01646840b3718c47 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Mon, 15 Apr 2019 05:13:23 +0200 Subject: [PATCH 19/52] Update file names and default exports --- .../.size-snapshot.json | 8 +- .../.size-snapshot.json | 12 +- .../jss-preset-default/.size-snapshot.json | 12 +- packages/jss-starter-kit/.size-snapshot.json | 12 +- packages/jss/.size-snapshot.json | 28 +-- packages/react-jss/.size-snapshot.json | 24 +-- packages/react-jss/src/JssContext.js | 4 +- packages/react-jss/src/JssProvider.js | 6 +- ...reate-use-styles.js => createUseStyles.js} | 10 +- packages/react-jss/src/index.js | 10 +- packages/react-jss/src/jss.js | 2 +- .../react-jss/src/utils/get-sheet-classes.js | 4 +- packages/react-jss/src/utils/index-counter.js | 2 +- packages/react-jss/src/utils/managers.js | 2 +- .../utils/{memoize-one.js => memoizeOne.js} | 0 .../{merge-classes.js => mergeClasses.js} | 0 packages/react-jss/src/utils/sheets-meta.js | 6 +- packages/react-jss/src/utils/sheets.js | 8 +- packages/react-jss/src/with-styles.js | 168 ----------------- packages/react-jss/src/withStyles.js | 170 ++++++++++++++++++ ...with-styles.test.js => withStyles.test.js} | 0 21 files changed, 246 insertions(+), 242 deletions(-) rename packages/react-jss/src/{create-use-styles.js => createUseStyles.js} (91%) rename packages/react-jss/src/utils/{memoize-one.js => memoizeOne.js} (100%) rename packages/react-jss/src/utils/{merge-classes.js => mergeClasses.js} (100%) delete mode 100644 packages/react-jss/src/with-styles.js rename packages/react-jss/src/{with-styles.test.js => withStyles.test.js} (100%) diff --git a/packages/jss-plugin-default-unit/.size-snapshot.json b/packages/jss-plugin-default-unit/.size-snapshot.json index 051cd68c4..b40b19fba 100644 --- a/packages/jss-plugin-default-unit/.size-snapshot.json +++ b/packages/jss-plugin-default-unit/.size-snapshot.json @@ -1,21 +1,21 @@ { "dist/jss-plugin-default-unit.js": { - "bundled": 5913, + "bundled": 5701, "minified": 2742, "gzipped": 1055 }, "dist/jss-plugin-default-unit.min.js": { - "bundled": 5913, + "bundled": 5701, "minified": 2742, "gzipped": 1055 }, "dist/jss-plugin-default-unit.cjs.js": { - "bundled": 5203, + "bundled": 5003, "minified": 2843, "gzipped": 1020 }, "dist/jss-plugin-default-unit.esm.js": { - "bundled": 5123, + "bundled": 4923, "minified": 2777, "gzipped": 965, "treeshaked": { diff --git a/packages/jss-plugin-vendor-prefixer/.size-snapshot.json b/packages/jss-plugin-vendor-prefixer/.size-snapshot.json index add3b1626..e0e4d6bf2 100644 --- a/packages/jss-plugin-vendor-prefixer/.size-snapshot.json +++ b/packages/jss-plugin-vendor-prefixer/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/jss-plugin-vendor-prefixer.js": { - "bundled": 17480, - "minified": 5616, - "gzipped": 2183 + "bundled": 17314, + "minified": 5593, + "gzipped": 2167 }, "dist/jss-plugin-vendor-prefixer.min.js": { - "bundled": 17480, - "minified": 5616, - "gzipped": 2183 + "bundled": 17314, + "minified": 5593, + "gzipped": 2167 }, "dist/jss-plugin-vendor-prefixer.cjs.js": { "bundled": 1375, diff --git a/packages/jss-preset-default/.size-snapshot.json b/packages/jss-preset-default/.size-snapshot.json index 315e6f5df..94864c639 100644 --- a/packages/jss-preset-default/.size-snapshot.json +++ b/packages/jss-preset-default/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/jss-preset-default.js": { - "bundled": 54595, - "minified": 19525, - "gzipped": 6444 + "bundled": 54429, + "minified": 19499, + "gzipped": 6430 }, "dist/jss-preset-default.min.js": { - "bundled": 53841, - "minified": 19066, - "gzipped": 6229 + "bundled": 53675, + "minified": 19040, + "gzipped": 6220 }, "dist/jss-preset-default.cjs.js": { "bundled": 1329, diff --git a/packages/jss-starter-kit/.size-snapshot.json b/packages/jss-starter-kit/.size-snapshot.json index 4d93f7103..cd2abd902 100644 --- a/packages/jss-starter-kit/.size-snapshot.json +++ b/packages/jss-starter-kit/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/jss-starter-kit.js": { - "bundled": 70753, - "minified": 29117, - "gzipped": 8981 + "bundled": 69971, + "minified": 29537, + "gzipped": 9057 }, "dist/jss-starter-kit.min.js": { - "bundled": 69999, - "minified": 28659, - "gzipped": 8769 + "bundled": 69217, + "minified": 29079, + "gzipped": 8849 }, "dist/jss-starter-kit.cjs.js": { "bundled": 2592, diff --git a/packages/jss/.size-snapshot.json b/packages/jss/.size-snapshot.json index 5f15402af..bc0077f70 100644 --- a/packages/jss/.size-snapshot.json +++ b/packages/jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/jss.js": { - "bundled": 59660, - "minified": 22216, - "gzipped": 6638 + "bundled": 58891, + "minified": 21842, + "gzipped": 6572 }, "dist/jss.min.js": { - "bundled": 58494, - "minified": 21298, - "gzipped": 6195 + "bundled": 57725, + "minified": 20925, + "gzipped": 6130 }, "dist/jss.cjs.js": { - "bundled": 55062, - "minified": 24175, - "gzipped": 6695 + "bundled": 54349, + "minified": 23753, + "gzipped": 6620 }, "dist/jss.esm.js": { - "bundled": 54566, - "minified": 23771, - "gzipped": 6613, + "bundled": 53853, + "minified": 23349, + "gzipped": 6537, "treeshaked": { "rollup": { - "code": 19358, + "code": 18985, "import_statements": 281 }, "webpack": { - "code": 20773 + "code": 20400 } } } diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 374fe3a07..f7f618fa3 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 113066, - "minified": 37750, - "gzipped": 12221 + "bundled": 112379, + "minified": 38115, + "gzipped": 12293 }, "dist/react-jss.min.js": { - "bundled": 88505, - "minified": 30466, - "gzipped": 10042 + "bundled": 87818, + "minified": 30830, + "gzipped": 10117 }, "dist/react-jss.cjs.js": { - "bundled": 18385, - "minified": 8541, - "gzipped": 2770 + "bundled": 18480, + "minified": 8514, + "gzipped": 2762 }, "dist/react-jss.esm.js": { - "bundled": 17592, - "minified": 7851, - "gzipped": 2647, + "bundled": 17694, + "minified": 7831, + "gzipped": 2649, "treeshaked": { "rollup": { "code": 1881, diff --git a/packages/react-jss/src/JssContext.js b/packages/react-jss/src/JssContext.js index ab2c1cf37..1b796c0b8 100644 --- a/packages/react-jss/src/JssContext.js +++ b/packages/react-jss/src/JssContext.js @@ -2,7 +2,9 @@ import React, {type Context} from 'react' import type {Context as JssContextValue} from './types' -export const JssContext: Context = React.createContext({ +const JssContext: Context = React.createContext({ sheetOptions: {classNamePrefix: ''}, disableStylesGeneration: false }) + +export default JssContext; diff --git a/packages/react-jss/src/JssProvider.js b/packages/react-jss/src/JssProvider.js index 0e4883e50..5ffae09a4 100644 --- a/packages/react-jss/src/JssProvider.js +++ b/packages/react-jss/src/JssProvider.js @@ -3,8 +3,8 @@ import React, {Component, type Node} from 'react' import PropTypes from 'prop-types' import defaultJss, {createGenerateId, type Jss, type GenerateId, SheetsRegistry} from 'jss' import type {Context, Managers} from './types' -import {JssContext} from './JssContext' -import memoize from './utils/memoize-one' +import JssContext from './JssContext' +import memoize from './utils/memoizeOne' /* eslint-disable react/require-default-props, react/no-unused-prop-types */ @@ -18,7 +18,7 @@ type Props = { children: Node } -export class JssProvider extends Component { +export default class JssProvider extends Component { static propTypes = { registry: PropTypes.instanceOf(SheetsRegistry), jss: PropTypes.instanceOf(defaultJss.constructor), diff --git a/packages/react-jss/src/create-use-styles.js b/packages/react-jss/src/createUseStyles.js similarity index 91% rename from packages/react-jss/src/create-use-styles.js rename to packages/react-jss/src/createUseStyles.js index 9b8a0bffd..8c4ae2803 100644 --- a/packages/react-jss/src/create-use-styles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -3,7 +3,7 @@ import React from 'react' import {ThemeContext as DefaultThemeContext} from 'theming' -import {JssContext} from './JssContext' +import JssContext from './JssContext' import { createStaticSheet, addDynamicRules, @@ -17,7 +17,7 @@ import {getSheetClasses} from './utils/get-sheet-classes' const noTheme = {} -function createUseStyles(styles: Styles, options?: HookOptions = {}) { +const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { const {index = getIndex(), theming, name = 'Hook', ...sheetOptions} = options const ThemeContext = (theming && theming.context) || DefaultThemeContext @@ -45,11 +45,11 @@ function createUseStyles(styles: Styles, options?: HookOptions manageSheet({ index, context: jssContext, - sheet: stylesheet, + sheet: staticSheet, theme }) - return sheet + return staticSheet }, [theme, jssContext] ) @@ -98,4 +98,4 @@ function createUseStyles(styles: Styles, options?: HookOptions } } -export {createUseStyles} +export default createUseStyles diff --git a/packages/react-jss/src/index.js b/packages/react-jss/src/index.js index 13daa7671..5eb6a24d9 100644 --- a/packages/react-jss/src/index.js +++ b/packages/react-jss/src/index.js @@ -1,12 +1,12 @@ // @flow -import {withStyles} from './with-styles' -import {createUseStyles} from './create-use-styles' +import withStyles from './withStyles' +import createUseStyles from './createUseStyles' export {ThemeProvider, withTheme, createTheming} from 'theming' -export {JssProvider} from './JssProvider' -export {jss} from './jss' +export {default as JssProvider} from './JssProvider' +export {default as jss} from './jss' export {SheetsRegistry, createGenerateId} from 'jss' -export {JssContext} from './JssContext' +export {default as JssContext} from './JssContext' export {withStyles, createUseStyles} diff --git a/packages/react-jss/src/jss.js b/packages/react-jss/src/jss.js index c563d1519..da51ba09b 100644 --- a/packages/react-jss/src/jss.js +++ b/packages/react-jss/src/jss.js @@ -2,4 +2,4 @@ import {create} from 'jss' import preset from 'jss-preset-default' -export const jss = create(preset()) +export default create(preset()) diff --git a/packages/react-jss/src/utils/get-sheet-classes.js b/packages/react-jss/src/utils/get-sheet-classes.js index 64a4e24ab..611889d74 100644 --- a/packages/react-jss/src/utils/get-sheet-classes.js +++ b/packages/react-jss/src/utils/get-sheet-classes.js @@ -2,7 +2,7 @@ import type {StyleSheet} from 'jss' import type {DynamicRules} from '../types' -import {getMetaForSheet} from './sheets-meta' +import {getMeta} from './sheets-meta' const getSheetClasses = (sheet: StyleSheet, dynamicRules: ?DynamicRules) => { if (!dynamicRules) { @@ -10,7 +10,7 @@ const getSheetClasses = (sheet: StyleSheet, dynamicRules: ?DynamicRules) => { } const classes = {} - const meta = getMetaForSheet(sheet) + const meta = getMeta(sheet) if (!meta) { return sheet.classes diff --git a/packages/react-jss/src/utils/index-counter.js b/packages/react-jss/src/utils/index-counter.js index 466ab78fe..0c7443026 100644 --- a/packages/react-jss/src/utils/index-counter.js +++ b/packages/react-jss/src/utils/index-counter.js @@ -12,7 +12,7 @@ */ let index = 0 -function getIndex() { +const getIndex = () => { return index++ } diff --git a/packages/react-jss/src/utils/managers.js b/packages/react-jss/src/utils/managers.js index 3c8dba2e9..a1544b8a9 100644 --- a/packages/react-jss/src/utils/managers.js +++ b/packages/react-jss/src/utils/managers.js @@ -5,7 +5,7 @@ import type {Context} from '../types' const defaultManagers = new Map() -function getManager(context: Context, managerId: number) { +const getManager = (context: Context, managerId: number) => { // If `managers` map is present in the context, we use it in order to // let JssProvider reset them when new response has to render server-side. if (context.managers) { diff --git a/packages/react-jss/src/utils/memoize-one.js b/packages/react-jss/src/utils/memoizeOne.js similarity index 100% rename from packages/react-jss/src/utils/memoize-one.js rename to packages/react-jss/src/utils/memoizeOne.js diff --git a/packages/react-jss/src/utils/merge-classes.js b/packages/react-jss/src/utils/mergeClasses.js similarity index 100% rename from packages/react-jss/src/utils/merge-classes.js rename to packages/react-jss/src/utils/mergeClasses.js diff --git a/packages/react-jss/src/utils/sheets-meta.js b/packages/react-jss/src/utils/sheets-meta.js index 65eb3a774..cd7783d60 100644 --- a/packages/react-jss/src/utils/sheets-meta.js +++ b/packages/react-jss/src/utils/sheets-meta.js @@ -11,12 +11,12 @@ interface SheetMeta { const sheetsMeta = new WeakMap() -function getMetaForSheet(sheet: StyleSheet) { +const getMeta = (sheet: StyleSheet) => { return sheetsMeta.get(sheet) } -function addMetaForSheet(sheet: StyleSheet, meta: SheetMeta) { +const addMeta = (sheet: StyleSheet, meta: SheetMeta) => { sheetsMeta.set(sheet, meta) } -export {getMetaForSheet, addMetaForSheet} +export {getMeta, addMeta} diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index c10bf7425..f69aabd5c 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -4,8 +4,8 @@ import {getDynamicStyles, type StyleSheetFactoryOptions} from 'jss' import type {StyleSheet} from 'jss' import type {Context, DynamicRules, Styles} from '../types' import {getManager} from './managers' -import {jss as defaultJss} from '../jss' -import {addMetaForSheet, getMetaForSheet} from './sheets-meta' +import defaultJss from '../jss' +import {addMeta, getMeta} from './sheets-meta' interface Options { context: Context; @@ -59,7 +59,7 @@ function createStaticSheet(options: Options) { const dynamicStyles = getDynamicStyles(styles) const sheet = jss.createStyleSheet(styles, getSheetOptions(options, dynamicStyles !== null)) - addMetaForSheet(sheet, { + addMeta(sheet, { dynamicStyles, styles, dynamicRuleCounter: 0 @@ -100,7 +100,7 @@ const addDynamicRules = (sheet: ?StyleSheet): ?DynamicRules => { return undefined } - const meta = getMetaForSheet(sheet) + const meta = getMeta(sheet) if (!meta) { return undefined diff --git a/packages/react-jss/src/with-styles.js b/packages/react-jss/src/with-styles.js deleted file mode 100644 index 354db41d1..000000000 --- a/packages/react-jss/src/with-styles.js +++ /dev/null @@ -1,168 +0,0 @@ -// @flow -import React, {Component, type ComponentType, type Node} from 'react' -import hoistNonReactStatics from 'hoist-non-react-statics' -import {type StyleSheet, type Classes} from 'jss' -import {ThemeContext} from 'theming' - -import type {HOCProps, HOCOptions, Styles, InnerProps, DynamicRules} from './types' -import getDisplayName from './getDisplayName' -import memoize from './utils/memoize-one' -import mergeClasses from './utils/merge-classes' -import {JssContext} from './JssContext' -import {getIndex} from './utils/index-counter' -import { - createStaticSheet, - updateDynamicRules, - addDynamicRules, - removeDynamicRules -} from './utils/sheets' -import {manageSheet, unmanageSheet} from './utils/managers' -import {getSheetClasses} from './utils/get-sheet-classes' - -interface State { - dynamicRules: ?DynamicRules; - sheet: ?StyleSheet; - classes: {}; -} - -const NoRenderer = (props: {children?: Node}) => props.children || null - -const noTheme = {} - -/** - * HOC creator function that wrapps the user component. - * - * `withStyles(styles, [options])(Component)` - */ -export function withStyles(styles: Styles, options?: HOCOptions = {}) { - const {index = getIndex(), theming, injectTheme, ...sheetOptions} = options - const isThemingEnabled = typeof styles === 'function' - const ThemeConsumer = (theming && theming.context.Consumer) || ThemeContext.Consumer - - return ( - InnerComponent: ComponentType = NoRenderer - ): ComponentType => { - const displayName = getDisplayName(InnerComponent) - - const getTheme = (props): Theme => (isThemingEnabled ? props.theme : ((noTheme: any): Theme)) - - class WithStyles extends Component, State> { - static displayName = `WithStyles(${displayName})` - - // $FlowFixMe - static defaultProps = {...InnerComponent.defaultProps} - - static createState(props) { - const sheet = createStaticSheet({ - styles, - theme: getTheme(props), - index, - name: displayName, - context: props.jssContext, - sheetOptions - }) - - if (!sheet) { - return {classes: {}, dynamicRules: undefined, sheet: undefined} - } - - const dynamicRules = addDynamicRules(sheet) - - return { - sheet, - dynamicRules, - classes: getSheetClasses(sheet, dynamicRules) - } - } - - static manage(props, state) { - manageSheet({ - sheet: state.sheet, - index, - context: props.jssContext, - theme: getTheme(props) - }) - } - - static unmanage(props, state) { - removeDynamicRules(state.sheet, state.dynamicRules) - - unmanageSheet({ - context: props.jssContext, - index, - sheet: state.sheet, - theme: getTheme(props) - }) - } - - mergeClassesProp = memoize( - (sheetClasses, classesProp) => - classesProp ? mergeClasses(sheetClasses, classesProp) : sheetClasses - ) - - constructor(props: HOCProps) { - super(props) - - this.state = WithStyles.createState(props) - WithStyles.manage(props, this.state) - } - - componentDidUpdate(prevProps: HOCProps, prevState: State) { - if (isThemingEnabled && this.props.theme !== prevProps.theme) { - const newState = WithStyles.createState(this.props) - WithStyles.manage(this.props, newState) - WithStyles.unmanage(prevProps, prevState) - - // eslint-disable-next-line react/no-did-update-set-state - this.setState(newState) - } else { - // Only update the rules when we don't generate a new sheet - updateDynamicRules(this.props, this.state.sheet, this.state.dynamicRules) - } - } - - componentWillUnmount() { - WithStyles.unmanage(this.props, this.state) - } - - render() { - const {innerRef, jssContext, theme, classes, ...rest} = this.props - const {classes: sheetClasses} = this.state - const props = { - ...rest, - // $FlowFixMe - classes: this.mergeClassesProp(sheetClasses, classes) - } - - if (innerRef) props.ref = innerRef - if (injectTheme) props.theme = theme - - return - } - } - - const JssContextSubscriber = React.forwardRef((props, ref) => ( - - {context => { - if (isThemingEnabled || injectTheme) { - return ( - - {theme => ( - - )} - - ) - } - - return - }} - - )) - - JssContextSubscriber.displayName = 'JssContextSubscriber' - // $FlowFixMe - JssContextSubscriber.InnerComponent = InnerComponent - - return hoistNonReactStatics(JssContextSubscriber, InnerComponent) - } -} diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index e69de29bb..9e1d28817 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -0,0 +1,170 @@ +// @flow +import React, {Component, type ComponentType, type Node} from 'react' +import hoistNonReactStatics from 'hoist-non-react-statics' +import {type StyleSheet, type Classes} from 'jss' +import {ThemeContext} from 'theming' + +import type {HOCProps, HOCOptions, Styles, InnerProps, DynamicRules} from './types' +import getDisplayName from './getDisplayName' +import memoize from './utils/memoizeOne' +import mergeClasses from './utils/mergeClasses' +import JssContext from './JssContext' +import {getIndex} from './utils/index-counter' +import { + createStaticSheet, + updateDynamicRules, + addDynamicRules, + removeDynamicRules +} from './utils/sheets' +import {manageSheet, unmanageSheet} from './utils/managers' +import {getSheetClasses} from './utils/get-sheet-classes' + +interface State { + dynamicRules: ?DynamicRules; + sheet: ?StyleSheet; + classes: {}; +} + +const NoRenderer = (props: {children?: Node}) => props.children || null + +const noTheme = {} + +/** + * HOC creator function that wrapps the user component. + * + * `withStyles(styles, [options])(Component)` + */ +const withStyles = (styles: Styles, options?: HOCOptions = {}) => { + const {index = getIndex(), theming, injectTheme, ...sheetOptions} = options + const isThemingEnabled = typeof styles === 'function' + const ThemeConsumer = (theming && theming.context.Consumer) || ThemeContext.Consumer + + return ( + InnerComponent: ComponentType = NoRenderer + ): ComponentType => { + const displayName = getDisplayName(InnerComponent) + + const getTheme = (props): Theme => (isThemingEnabled ? props.theme : ((noTheme: any): Theme)) + + class WithStyles extends Component, State> { + static displayName = `WithStyles(${displayName})` + + // $FlowFixMe + static defaultProps = {...InnerComponent.defaultProps} + + static createState(props) { + const sheet = createStaticSheet({ + styles, + theme: getTheme(props), + index, + name: displayName, + context: props.jssContext, + sheetOptions + }) + + if (!sheet) { + return {classes: {}, dynamicRules: undefined, sheet: undefined} + } + + const dynamicRules = addDynamicRules(sheet) + + return { + sheet, + dynamicRules, + classes: getSheetClasses(sheet, dynamicRules) + } + } + + static manage(props, state) { + manageSheet({ + sheet: state.sheet, + index, + context: props.jssContext, + theme: getTheme(props) + }) + } + + static unmanage(props, state) { + removeDynamicRules(state.sheet, state.dynamicRules) + + unmanageSheet({ + context: props.jssContext, + index, + sheet: state.sheet, + theme: getTheme(props) + }) + } + + mergeClassesProp = memoize( + (sheetClasses, classesProp) => + classesProp ? mergeClasses(sheetClasses, classesProp) : sheetClasses + ) + + constructor(props: HOCProps) { + super(props) + + this.state = WithStyles.createState(props) + WithStyles.manage(props, this.state) + } + + componentDidUpdate(prevProps: HOCProps, prevState: State) { + if (isThemingEnabled && this.props.theme !== prevProps.theme) { + const newState = WithStyles.createState(this.props) + WithStyles.manage(this.props, newState) + WithStyles.unmanage(prevProps, prevState) + + // eslint-disable-next-line react/no-did-update-set-state + this.setState(newState) + } else { + // Only update the rules when we don't generate a new sheet + updateDynamicRules(this.props, this.state.sheet, this.state.dynamicRules) + } + } + + componentWillUnmount() { + WithStyles.unmanage(this.props, this.state) + } + + render() { + const {innerRef, jssContext, theme, classes, ...rest} = this.props + const {classes: sheetClasses} = this.state + const props = { + ...rest, + // $FlowFixMe + classes: this.mergeClassesProp(sheetClasses, classes) + } + + if (innerRef) props.ref = innerRef + if (injectTheme) props.theme = theme + + return + } + } + + const JssContextSubscriber = React.forwardRef((props, ref) => ( + + {context => { + if (isThemingEnabled || injectTheme) { + return ( + + {theme => ( + + )} + + ) + } + + return + }} + + )) + + JssContextSubscriber.displayName = 'JssContextSubscriber' + // $FlowFixMe + JssContextSubscriber.InnerComponent = InnerComponent + + return hoistNonReactStatics(JssContextSubscriber, InnerComponent) + } +} + +export default withStyles; diff --git a/packages/react-jss/src/with-styles.test.js b/packages/react-jss/src/withStyles.test.js similarity index 100% rename from packages/react-jss/src/with-styles.test.js rename to packages/react-jss/src/withStyles.test.js From 800a929596daaf3b0a7b1b4800ecb13a36c79879 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Mon, 15 Apr 2019 05:20:10 +0200 Subject: [PATCH 20/52] Use type instead of interface --- packages/react-jss/src/JssContext.js | 2 +- packages/react-jss/src/utils/sheets-meta.js | 10 +++++----- packages/react-jss/src/withStyles.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/react-jss/src/JssContext.js b/packages/react-jss/src/JssContext.js index 1b796c0b8..e499801d0 100644 --- a/packages/react-jss/src/JssContext.js +++ b/packages/react-jss/src/JssContext.js @@ -7,4 +7,4 @@ const JssContext: Context = React.createContext({ disableStylesGeneration: false }) -export default JssContext; +export default JssContext diff --git a/packages/react-jss/src/utils/sheets-meta.js b/packages/react-jss/src/utils/sheets-meta.js index cd7783d60..20e1b3df8 100644 --- a/packages/react-jss/src/utils/sheets-meta.js +++ b/packages/react-jss/src/utils/sheets-meta.js @@ -3,11 +3,11 @@ import type {StyleSheet} from 'jss' import type {StaticStyles} from '../types' -interface SheetMeta { - styles: StaticStyles; - dynamicStyles: StaticStyles; - dynamicRuleCounter: number; -} +type SheetMeta = {| + styles: StaticStyles, + dynamicStyles: StaticStyles, + dynamicRuleCounter: number +|} const sheetsMeta = new WeakMap() diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index 9e1d28817..f156d1b81 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -167,4 +167,4 @@ const withStyles = (styles: Styles, options?: HOCOptions = } } -export default withStyles; +export default withStyles From 4967ece607ac9c06877e464e3cfdcbde164f56f5 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Mon, 15 Apr 2019 05:24:37 +0200 Subject: [PATCH 21/52] Fix linting --- packages/react-jss/src/utils/sheets-meta.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/react-jss/src/utils/sheets-meta.js b/packages/react-jss/src/utils/sheets-meta.js index 20e1b3df8..e61e0d286 100644 --- a/packages/react-jss/src/utils/sheets-meta.js +++ b/packages/react-jss/src/utils/sheets-meta.js @@ -11,9 +11,7 @@ type SheetMeta = {| const sheetsMeta = new WeakMap() -const getMeta = (sheet: StyleSheet) => { - return sheetsMeta.get(sheet) -} +const getMeta = (sheet: StyleSheet) => sheetsMeta.get(sheet) const addMeta = (sheet: StyleSheet, meta: SheetMeta) => { sheetsMeta.set(sheet, meta) From b49de752c0d08be8d27b16a3d47011bed8d84790 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Mon, 15 Apr 2019 05:27:20 +0200 Subject: [PATCH 22/52] Fixed PR comments --- packages/react-jss/src/createUseStyles.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 8c4ae2803..6eb34a812 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -20,21 +20,26 @@ const noTheme = {} const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { const {index = getIndex(), theming, name = 'Hook', ...sheetOptions} = options const ThemeContext = (theming && theming.context) || DefaultThemeContext + const useTheme = + typeof styles === 'function' + ? // $FlowFixMe + (): Theme => React.useContext(ThemeContext) + : // $FlowFixMe + (): Theme => noTheme return (data: any) => { - const jssContext = React.useContext(JssContext) - // $FlowFixMe - const theme: Theme = typeof styles === 'function' ? React.useContext(ThemeContext) : noTheme + const context = React.useContext(JssContext) + const theme = useTheme() // When the theme or the context changes we create a new sheet const sheet = React.useMemo( () => { - if (jssContext.disableStylesGeneration) { + if (context.disableStylesGeneration) { return undefined } const staticSheet = createStaticSheet({ - context: jssContext, + context, styles, name, theme, @@ -44,14 +49,14 @@ const createUseStyles = (styles: Styles, options?: HookOptions manageSheet({ index, - context: jssContext, + context, sheet: staticSheet, theme }) return staticSheet }, - [theme, jssContext] + [theme, context] ) // When the sheet changes, we readd the dynamic rules and update them @@ -80,7 +85,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions removeDynamicRules(sheet, dynamicRules) unmanageSheet({ - context: jssContext, + context, index, theme, sheet From 50725d3f6d5c79e77a21a32e422ea6de14c5b179 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 20 Apr 2019 20:00:25 +0200 Subject: [PATCH 23/52] Update size snapshots --- .../.size-snapshot.json | 12 +++++----- .../jss-preset-default/.size-snapshot.json | 12 +++++----- packages/jss-starter-kit/.size-snapshot.json | 12 +++++----- packages/react-jss/.size-snapshot.json | 24 +++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/packages/jss-plugin-vendor-prefixer/.size-snapshot.json b/packages/jss-plugin-vendor-prefixer/.size-snapshot.json index e0e4d6bf2..add3b1626 100644 --- a/packages/jss-plugin-vendor-prefixer/.size-snapshot.json +++ b/packages/jss-plugin-vendor-prefixer/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/jss-plugin-vendor-prefixer.js": { - "bundled": 17314, - "minified": 5593, - "gzipped": 2167 + "bundled": 17480, + "minified": 5616, + "gzipped": 2183 }, "dist/jss-plugin-vendor-prefixer.min.js": { - "bundled": 17314, - "minified": 5593, - "gzipped": 2167 + "bundled": 17480, + "minified": 5616, + "gzipped": 2183 }, "dist/jss-plugin-vendor-prefixer.cjs.js": { "bundled": 1375, diff --git a/packages/jss-preset-default/.size-snapshot.json b/packages/jss-preset-default/.size-snapshot.json index 94864c639..315e6f5df 100644 --- a/packages/jss-preset-default/.size-snapshot.json +++ b/packages/jss-preset-default/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/jss-preset-default.js": { - "bundled": 54429, - "minified": 19499, - "gzipped": 6430 + "bundled": 54595, + "minified": 19525, + "gzipped": 6444 }, "dist/jss-preset-default.min.js": { - "bundled": 53675, - "minified": 19040, - "gzipped": 6220 + "bundled": 53841, + "minified": 19066, + "gzipped": 6229 }, "dist/jss-preset-default.cjs.js": { "bundled": 1329, diff --git a/packages/jss-starter-kit/.size-snapshot.json b/packages/jss-starter-kit/.size-snapshot.json index cd2abd902..09e23b690 100644 --- a/packages/jss-starter-kit/.size-snapshot.json +++ b/packages/jss-starter-kit/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/jss-starter-kit.js": { - "bundled": 69971, - "minified": 29537, - "gzipped": 9057 + "bundled": 70137, + "minified": 29563, + "gzipped": 9075 }, "dist/jss-starter-kit.min.js": { - "bundled": 69217, - "minified": 29079, - "gzipped": 8849 + "bundled": 69383, + "minified": 29105, + "gzipped": 8867 }, "dist/jss-starter-kit.cjs.js": { "bundled": 2592, diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index f7f618fa3..7f5fc8be2 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 112379, - "minified": 38115, - "gzipped": 12293 + "bundled": 112647, + "minified": 38185, + "gzipped": 12319 }, "dist/react-jss.min.js": { - "bundled": 87818, - "minified": 30830, - "gzipped": 10117 + "bundled": 88086, + "minified": 30900, + "gzipped": 10143 }, "dist/react-jss.cjs.js": { - "bundled": 18480, - "minified": 8514, - "gzipped": 2762 + "bundled": 18568, + "minified": 8558, + "gzipped": 2771 }, "dist/react-jss.esm.js": { - "bundled": 17694, - "minified": 7831, - "gzipped": 2649, + "bundled": 17782, + "minified": 7875, + "gzipped": 2660, "treeshaked": { "rollup": { "code": 1881, From 8fcc455025c4e5cbaeafbd544984bb6df9d624e4 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 23 Apr 2019 11:21:01 +0200 Subject: [PATCH 24/52] fix linter, make all file names camel cased --- packages/react-jss/src/createUseStyles.js | 4 ++-- .../src/utils/{get-sheet-classes.js => getSheetClasses.js} | 2 +- .../src/utils/{index-counter.js => indexCounter.js} | 6 +----- .../utils/{merge-classes.test.js => mergeClasses.test.js} | 2 +- packages/react-jss/src/utils/sheets.js | 2 +- .../react-jss/src/utils/{sheets-meta.js => sheetsMeta.js} | 0 packages/react-jss/src/withStyles.js | 4 ++-- .../react-jss/tests/{dynamic-styles.js => dynamicStyles.js} | 0 8 files changed, 8 insertions(+), 12 deletions(-) rename packages/react-jss/src/utils/{get-sheet-classes.js => getSheetClasses.js} (93%) rename packages/react-jss/src/utils/{index-counter.js => indexCounter.js} (89%) rename packages/react-jss/src/utils/{merge-classes.test.js => mergeClasses.test.js} (91%) rename packages/react-jss/src/utils/{sheets-meta.js => sheetsMeta.js} (100%) rename packages/react-jss/tests/{dynamic-styles.js => dynamicStyles.js} (100%) diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 6eb34a812..4f3efd730 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -10,10 +10,10 @@ import { removeDynamicRules, updateDynamicRules } from './utils/sheets' -import {getIndex} from './utils/index-counter' +import {getIndex} from './utils/indexCounter' import type {HookOptions, Styles} from './types' import {unmanageSheet, manageSheet} from './utils/managers' -import {getSheetClasses} from './utils/get-sheet-classes' +import {getSheetClasses} from './utils/getSheetClasses' const noTheme = {} diff --git a/packages/react-jss/src/utils/get-sheet-classes.js b/packages/react-jss/src/utils/getSheetClasses.js similarity index 93% rename from packages/react-jss/src/utils/get-sheet-classes.js rename to packages/react-jss/src/utils/getSheetClasses.js index 611889d74..2910b9ec7 100644 --- a/packages/react-jss/src/utils/get-sheet-classes.js +++ b/packages/react-jss/src/utils/getSheetClasses.js @@ -2,7 +2,7 @@ import type {StyleSheet} from 'jss' import type {DynamicRules} from '../types' -import {getMeta} from './sheets-meta' +import {getMeta} from './sheetsMeta' const getSheetClasses = (sheet: StyleSheet, dynamicRules: ?DynamicRules) => { if (!dynamicRules) { diff --git a/packages/react-jss/src/utils/index-counter.js b/packages/react-jss/src/utils/indexCounter.js similarity index 89% rename from packages/react-jss/src/utils/index-counter.js rename to packages/react-jss/src/utils/indexCounter.js index 0c7443026..3e3bbb444 100644 --- a/packages/react-jss/src/utils/index-counter.js +++ b/packages/react-jss/src/utils/indexCounter.js @@ -12,8 +12,4 @@ */ let index = 0 -const getIndex = () => { - return index++ -} - -export {getIndex} +export const getIndex = () => index++ diff --git a/packages/react-jss/src/utils/merge-classes.test.js b/packages/react-jss/src/utils/mergeClasses.test.js similarity index 91% rename from packages/react-jss/src/utils/merge-classes.test.js rename to packages/react-jss/src/utils/mergeClasses.test.js index 265c4d483..6ba9da5d0 100644 --- a/packages/react-jss/src/utils/merge-classes.test.js +++ b/packages/react-jss/src/utils/mergeClasses.test.js @@ -1,5 +1,5 @@ import expect from 'expect.js' -import compose from './merge-classes' +import compose from './mergeClasses' describe('react-jss: merge-classes', () => { it('should merge two class objects', () => { diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index f69aabd5c..f060af313 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -5,7 +5,7 @@ import type {StyleSheet} from 'jss' import type {Context, DynamicRules, Styles} from '../types' import {getManager} from './managers' import defaultJss from '../jss' -import {addMeta, getMeta} from './sheets-meta' +import {addMeta, getMeta} from './sheetsMeta' interface Options { context: Context; diff --git a/packages/react-jss/src/utils/sheets-meta.js b/packages/react-jss/src/utils/sheetsMeta.js similarity index 100% rename from packages/react-jss/src/utils/sheets-meta.js rename to packages/react-jss/src/utils/sheetsMeta.js diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index f156d1b81..bc5d80211 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -9,7 +9,7 @@ import getDisplayName from './getDisplayName' import memoize from './utils/memoizeOne' import mergeClasses from './utils/mergeClasses' import JssContext from './JssContext' -import {getIndex} from './utils/index-counter' +import {getIndex} from './utils/indexCounter' import { createStaticSheet, updateDynamicRules, @@ -17,7 +17,7 @@ import { removeDynamicRules } from './utils/sheets' import {manageSheet, unmanageSheet} from './utils/managers' -import {getSheetClasses} from './utils/get-sheet-classes' +import {getSheetClasses} from './utils/getSheetClasses' interface State { dynamicRules: ?DynamicRules; diff --git a/packages/react-jss/tests/dynamic-styles.js b/packages/react-jss/tests/dynamicStyles.js similarity index 100% rename from packages/react-jss/tests/dynamic-styles.js rename to packages/react-jss/tests/dynamicStyles.js From 01c0f54107dc8decbf671b20a265b52f9c3af040 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 4 May 2019 20:30:00 +0200 Subject: [PATCH 25/52] Use state instead of relying on memo --- packages/react-jss/src/createUseStyles.js | 88 +++++++++-------------- packages/react-jss/src/utils/managers.js | 6 +- packages/react-jss/src/utils/sheets.js | 20 ++---- 3 files changed, 40 insertions(+), 74 deletions(-) diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 6eb34a812..27c2c7a9b 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -7,12 +7,11 @@ import JssContext from './JssContext' import { createStaticSheet, addDynamicRules, - removeDynamicRules, updateDynamicRules } from './utils/sheets' import {getIndex} from './utils/index-counter' import type {HookOptions, Styles} from './types' -import {unmanageSheet, manageSheet} from './utils/managers' +import {manageSheet} from './utils/managers' import {getSheetClasses} from './utils/get-sheet-classes' const noTheme = {} @@ -27,79 +26,60 @@ const createUseStyles = (styles: Styles, options?: HookOptions : // $FlowFixMe (): Theme => noTheme + const useLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect + return (data: any) => { const context = React.useContext(JssContext) const theme = useTheme() - // When the theme or the context changes we create a new sheet - const sheet = React.useMemo( - () => { - if (context.disableStylesGeneration) { - return undefined - } + if (context.disableStylesGeneration) { + return {} + } - const staticSheet = createStaticSheet({ - context, - styles, - name, - theme, - index, - sheetOptions - }) + const [staticSheet, setStaticSheet] = React.useState(() => { + const sheet = createStaticSheet({ + context, + styles, + name, + theme, + index, + sheetOptions + }) + + if (context.registry) { + context.registry.add(sheet) + } + return sheet + }) + + const [dynamicRules, setDynamicRules] = React.useState(() => addDynamicRules(staticSheet, data)) + + const [classes, setClasses] = React.useState(() => getSheetClasses(staticSheet, dynamicRules)) + + useLayoutEffect( + () => { manageSheet({ index, context, sheet: staticSheet, theme }) - - return staticSheet }, - [theme, context] + [staticSheet] ) - // When the sheet changes, we readd the dynamic rules and update them - const dynamicRules = React.useMemo( + useLayoutEffect( () => { - const rules = addDynamicRules(sheet) - - updateDynamicRules(data, sheet, rules) - - return rules - }, - [sheet] - ) - - // Update the dynamic rules before the actual render if the data has changed - React.useLayoutEffect( - () => { - updateDynamicRules(data, sheet, dynamicRules) + updateDynamicRules(data, staticSheet, dynamicRules) }, [data] ) - // Remove the old sheet when the sheet has changed after the render - React.useEffect( - () => () => { - removeDynamicRules(sheet, dynamicRules) - - unmanageSheet({ - context, - index, - theme, - sheet - }) - }, - [sheet] - ) + React.useDebugValue(classes); + React.useDebugValue(theme === noTheme ? 'No theme' : theme); - // Only compute the sheet classes when there is a sheet, otherwise return an empty object - // Because there are no deep properties, accessing any style will result in undefined - return React.useMemo(() => (sheet ? getSheetClasses(sheet, dynamicRules) : {}), [ - sheet, - dynamicRules - ]) + return classes; } } diff --git a/packages/react-jss/src/utils/managers.js b/packages/react-jss/src/utils/managers.js index a1544b8a9..f464216cb 100644 --- a/packages/react-jss/src/utils/managers.js +++ b/packages/react-jss/src/utils/managers.js @@ -26,7 +26,7 @@ const getManager = (context: Context, managerId: number) => { } interface Options { - sheet: ?StyleSheet; + sheet: StyleSheet; context: Context; index: number; theme: Theme; @@ -41,10 +41,6 @@ const manageSheet = (options: Options) => { const manager = getManager(options.context, options.index) manager.manage(options.theme) - - if (options.context.registry) { - options.context.registry.add(sheet) - } } const unmanageSheet = (options: Options) => { diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index f69aabd5c..46c2e6353 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -70,11 +70,7 @@ function createStaticSheet(options: Options) { return sheet } -const removeDynamicRules = (sheet: ?StyleSheet, rules: ?DynamicRules) => { - if (!sheet || !rules) { - return - } - +const removeDynamicRules = (sheet: StyleSheet, rules: DynamicRules) => { // Loop over each dynamic rule and remove the dynamic rule // We can't just remove the whole sheet as this has all of the rules for every component instance for (const key in rules) { @@ -82,11 +78,7 @@ const removeDynamicRules = (sheet: ?StyleSheet, rules: ?DynamicRules) => { } } -const updateDynamicRules = (data: any, sheet: ?StyleSheet, rules: ?DynamicRules) => { - if (!sheet || !rules) { - return - } - +const updateDynamicRules = (data: any, sheet: StyleSheet, rules: DynamicRules) => { // Loop over each dynamic rule and update it // We can't just update the whole sheet as this has all of the rules for every component instance for (const key in rules) { @@ -95,11 +87,7 @@ const updateDynamicRules = (data: any, sheet: ?StyleSheet, rules: ?DynamicRules) } } -const addDynamicRules = (sheet: ?StyleSheet): ?DynamicRules => { - if (!sheet) { - return undefined - } - +const addDynamicRules = (sheet: StyleSheet, data: any): DynamicRules => { const meta = getMeta(sheet) if (!meta) { @@ -113,6 +101,8 @@ const addDynamicRules = (sheet: ?StyleSheet): ?DynamicRules => { const name = `${key}-${meta.dynamicRuleCounter++}` const rule = sheet.addRule(name, meta.dynamicStyles[key]) + sheet.update(name, data); + if (rule) { rules[key] = rule } From 02b641cac89435b6a469a901e087cf8734285913 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 4 May 2019 22:24:36 +0200 Subject: [PATCH 26/52] Use is-in-browser package --- packages/react-jss/.size-snapshot.json | 30 +++++++++++------------ packages/react-jss/package.json | 1 + packages/react-jss/src/createUseStyles.js | 3 ++- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 7f5fc8be2..c92503ed7 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/react-jss.js": { - "bundled": 112647, - "minified": 38185, - "gzipped": 12319 + "bundled": 112230, + "minified": 38153, + "gzipped": 12328 }, "dist/react-jss.min.js": { - "bundled": 88086, - "minified": 30900, - "gzipped": 10143 + "bundled": 87669, + "minified": 30868, + "gzipped": 10150 }, "dist/react-jss.cjs.js": { - "bundled": 18568, - "minified": 8558, - "gzipped": 2771 + "bundled": 18230, + "minified": 8596, + "gzipped": 2810 }, "dist/react-jss.esm.js": { - "bundled": 17782, - "minified": 7875, - "gzipped": 2660, + "bundled": 17406, + "minified": 7880, + "gzipped": 2696, "treeshaked": { "rollup": { - "code": 1881, - "import_statements": 410 + "code": 1903, + "import_statements": 432 }, "webpack": { - "code": 3237 + "code": 3295 } } } diff --git a/packages/react-jss/package.json b/packages/react-jss/package.json index 5558beb8a..1f0a3a760 100644 --- a/packages/react-jss/package.json +++ b/packages/react-jss/package.json @@ -43,6 +43,7 @@ "dependencies": { "@babel/runtime": "^7.3.1", "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", "jss": "10.0.0-alpha.16", "jss-preset-default": "10.0.0-alpha.16", "prop-types": "^15.6.0", diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 2c06f6cab..974bf660b 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -1,6 +1,7 @@ // @flow import React from 'react' +import isInBrowser from 'is-in-browser' import {ThemeContext as DefaultThemeContext} from 'theming' import JssContext from './JssContext' @@ -22,7 +23,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions : // $FlowFixMe (): Theme => noTheme - const useLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect + const useLayoutEffect = isInBrowser ? React.useLayoutEffect : React.useEffect return (data: any) => { const context = React.useContext(JssContext) From 8a185abf2bde3544235e050644b8e83b95b86135 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 5 May 2019 22:28:57 +0200 Subject: [PATCH 27/52] Fix some type issues and add support for recreating the sheet when the theme changes --- packages/react-jss/.size-snapshot.json | 24 +++++----- packages/react-jss/src/createUseStyles.js | 55 +++++++++++++++++++++-- packages/react-jss/src/types.js | 12 ++--- packages/react-jss/src/utils/sheets.js | 2 +- packages/react-jss/src/withStyles.js | 38 +++++++++------- 5 files changed, 94 insertions(+), 37 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index c92503ed7..07258b5a3 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 112230, - "minified": 38153, - "gzipped": 12328 + "bundled": 113578, + "minified": 38514, + "gzipped": 12417 }, "dist/react-jss.min.js": { - "bundled": 87669, - "minified": 30868, - "gzipped": 10150 + "bundled": 89017, + "minified": 31229, + "gzipped": 10240 }, "dist/react-jss.cjs.js": { - "bundled": 18230, - "minified": 8596, - "gzipped": 2810 + "bundled": 19496, + "minified": 9034, + "gzipped": 2914 }, "dist/react-jss.esm.js": { - "bundled": 17406, - "minified": 7880, - "gzipped": 2696, + "bundled": 18654, + "minified": 8300, + "gzipped": 2794, "treeshaked": { "rollup": { "code": 1903, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 974bf660b..db6dadec3 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -5,16 +5,22 @@ import isInBrowser from 'is-in-browser' import {ThemeContext as DefaultThemeContext} from 'theming' import JssContext from './JssContext' -import {createStaticSheet, addDynamicRules, updateDynamicRules} from './utils/sheets' +import { + createStaticSheet, + addDynamicRules, + updateDynamicRules, + removeDynamicRules +} from './utils/sheets' import {getIndex} from './utils/indexCounter' import type {HookOptions, Styles} from './types' -import {manageSheet} from './utils/managers' +import {manageSheet, unmanageSheet} from './utils/managers' import {getSheetClasses} from './utils/getSheetClasses' const noTheme = {} const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { const {index = getIndex(), theming, name = 'Hook', ...sheetOptions} = options + const isFirstMount = React.useRef(true) const ThemeContext = (theming && theming.context) || DefaultThemeContext const useTheme = typeof styles === 'function' @@ -62,20 +68,63 @@ const createUseStyles = (styles: Styles, options?: HookOptions sheet: staticSheet, theme }) + + return () => { + unmanageSheet({ + index, + context, + sheet: staticSheet, + theme + }) + + if (dynamicRules) { + removeDynamicRules(staticSheet, dynamicRules) + } + } }, [staticSheet] ) useLayoutEffect( () => { - updateDynamicRules(data, staticSheet, dynamicRules) + if (dynamicRules) { + updateDynamicRules(data, staticSheet, dynamicRules) + } }, [data] ) + useLayoutEffect( + () => { + if (!isFirstMount.current) { + const newStaticSheet = createStaticSheet({ + context, + styles, + name, + theme, + index, + sheetOptions + }) + const newDynamicRules = addDynamicRules(staticSheet, data) + const newClasses = getSheetClasses(staticSheet, dynamicRules) + + setStaticSheet(newStaticSheet) + setDynamicRules(newDynamicRules) + setClasses(newClasses) + } + }, + [theme, context] + ) + + // $FlowFixMe React.useDebugValue(classes) + // $FlowFixMe React.useDebugValue(theme === noTheme ? 'No theme' : theme) + React.useEffect(() => { + isFirstMount.current = false + }) + return classes } } diff --git a/packages/react-jss/src/types.js b/packages/react-jss/src/types.js index 3227e7c73..e95d5f668 100644 --- a/packages/react-jss/src/types.js +++ b/packages/react-jss/src/types.js @@ -7,22 +7,22 @@ export type StaticStyles = {[key: string]: {}} export type Managers = {[key: number]: SheetsManager} -type StyleSheetOptions = {| +type StyleSheetOptions = { ...StyleSheetFactoryOptions, classNamePrefix: string -|} +} -export type HookOptions = StyleSheetFactoryOptions & {| +export type HookOptions = StyleSheetFactoryOptions & { index?: number, name?: string, theming?: Theming -|} +} -export type HOCOptions = StyleSheetFactoryOptions & {| +export type HOCOptions = StyleSheetFactoryOptions & { index?: number, theming?: Theming, injectTheme?: boolean -|} +} export type Context = {| jss?: Jss, diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index bcb0c7bf4..104f96e5b 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -87,7 +87,7 @@ const updateDynamicRules = (data: any, sheet: StyleSheet, rules: DynamicRules) = } } -const addDynamicRules = (sheet: StyleSheet, data: any): DynamicRules => { +const addDynamicRules = (sheet: StyleSheet, data: any): ?DynamicRules => { const meta = getMeta(sheet) if (!meta) { diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index bc5d80211..6c6b8225e 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -76,23 +76,31 @@ const withStyles = (styles: Styles, options?: HOCOptions = } static manage(props, state) { - manageSheet({ - sheet: state.sheet, - index, - context: props.jssContext, - theme: getTheme(props) - }) + if (state.sheet) { + manageSheet({ + sheet: state.sheet, + index, + context: props.jssContext, + theme: getTheme(props) + }) + } } static unmanage(props, state) { - removeDynamicRules(state.sheet, state.dynamicRules) - - unmanageSheet({ - context: props.jssContext, - index, - sheet: state.sheet, - theme: getTheme(props) - }) + const sheet = state.sheet + + if (sheet) { + unmanageSheet({ + context: props.jssContext, + index, + sheet, + theme: getTheme(props) + }) + + if (state.dynamicRules) { + removeDynamicRules(sheet, state.dynamicRules) + } + } } mergeClassesProp = memoize( @@ -115,7 +123,7 @@ const withStyles = (styles: Styles, options?: HOCOptions = // eslint-disable-next-line react/no-did-update-set-state this.setState(newState) - } else { + } else if (this.state.sheet && this.state.dynamicRules) { // Only update the rules when we don't generate a new sheet updateDynamicRules(this.props, this.state.sheet, this.state.dynamicRules) } From 7e2a92eecd0e0b03e62e27184a83a00bef9cac38 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 7 May 2019 08:43:14 +0200 Subject: [PATCH 28/52] upgrade theming --- packages/react-jss/.size-snapshot.json | 12 ++++++------ packages/react-jss/package.json | 2 +- yarn.lock | 26 +++++++++++++------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 07258b5a3..f9c65be4d 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,13 +1,13 @@ { "dist/react-jss.js": { - "bundled": 113578, - "minified": 38514, - "gzipped": 12417 + "bundled": 126897, + "minified": 43702, + "gzipped": 13649 }, "dist/react-jss.min.js": { - "bundled": 89017, - "minified": 31229, - "gzipped": 10240 + "bundled": 94510, + "minified": 33810, + "gzipped": 10856 }, "dist/react-jss.cjs.js": { "bundled": 19496, diff --git a/packages/react-jss/package.json b/packages/react-jss/package.json index 1f0a3a760..89ec3b77b 100644 --- a/packages/react-jss/package.json +++ b/packages/react-jss/package.json @@ -47,7 +47,7 @@ "jss": "10.0.0-alpha.16", "jss-preset-default": "10.0.0-alpha.16", "prop-types": "^15.6.0", - "theming": "^3.0.3", + "theming": "3.2.0", "tiny-warning": "^1.0.2" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 2ba9acaf4..aef24c75c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4791,13 +4791,6 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.1.0.tgz#42414ccdfff019cd2168168be998c7b3bd5245c0" - integrity sha512-MYcYuROh7SBM69xHGqXEwQqDux34s9tz+sCnxJmN18kgWh6JFdTw/5YdZtqsOdZJXddE/wUpCzfEdDrJj8p0Iw== - dependencies: - react-is "^16.3.2" - hoist-non-react-statics@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.2.0.tgz#d21b9fc72b50fdc38c5d88f6e2c52f2c2dbe5ee2" @@ -4805,6 +4798,13 @@ hoist-non-react-statics@^3.2.0: dependencies: react-is "^16.3.2" +hoist-non-react-statics@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -7739,7 +7739,7 @@ react-is@^16.3.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.0.tgz#456645144581a6e99f6816ae2bd24ee94bdd0c01" integrity sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g== -react-is@^16.8.6: +react-is@^16.7.0, react-is@^16.8.6: version "16.8.6" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== @@ -9114,12 +9114,12 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -theming@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/theming/-/theming-3.0.3.tgz#688e26f1a629d75b10fee6c0c5b884a7adaefcc0" - integrity sha512-5cE88hlvTNGgxX2j1mktAeByTOJzeVFf4sd8xHD+1GwIy2VTBb/8sMGgESS8Q+rMtjEy24y4fyoqCc8SnjEaBQ== +theming@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/theming/-/theming-3.2.0.tgz#237b13ae46e0596a7d1dc2ce4a31bcfce52cad8e" + integrity sha512-n0fSNYXkX63rcFBBeAthy14IcgPZLHp0OGkGZheaj64j7cBoP7INLd6+7HIXqWVjFn1M5cYSiZ1nszi+jo/Szg== dependencies: - hoist-non-react-statics "^3.1.0" + hoist-non-react-statics "^3.3.0" prop-types "^15.5.8" react-display-name "^0.2.4" tiny-warning "^1.0.2" From b08cd37fc80bf82fc7f5fd3fb22fb7b371e8e7b3 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 10 May 2019 14:05:49 +0200 Subject: [PATCH 29/52] add sheet to the registry when managing sheets, pass a theme when using one --- packages/react-jss/.size-snapshot.json | 24 +++++++++++------------ packages/react-jss/src/utils/managers.js | 10 ++++++---- packages/react-jss/src/withStyles.js | 11 ++++++----- packages/react-jss/src/withStyles.test.js | 6 +++--- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index f9c65be4d..472421168 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 126897, - "minified": 43702, - "gzipped": 13649 + "bundled": 127101, + "minified": 43747, + "gzipped": 13674 }, "dist/react-jss.min.js": { - "bundled": 94510, - "minified": 33810, - "gzipped": 10856 + "bundled": 94714, + "minified": 33855, + "gzipped": 10879 }, "dist/react-jss.cjs.js": { - "bundled": 19496, - "minified": 9034, - "gzipped": 2914 + "bundled": 19684, + "minified": 9079, + "gzipped": 2938 }, "dist/react-jss.esm.js": { - "bundled": 18654, - "minified": 8300, - "gzipped": 2794, + "bundled": 18842, + "minified": 8345, + "gzipped": 2819, "treeshaked": { "rollup": { "code": 1903, diff --git a/packages/react-jss/src/utils/managers.js b/packages/react-jss/src/utils/managers.js index f464216cb..1247eab64 100644 --- a/packages/react-jss/src/utils/managers.js +++ b/packages/react-jss/src/utils/managers.js @@ -33,14 +33,16 @@ interface Options { } const manageSheet = (options: Options) => { - const {sheet} = options + const {sheet, context, index, theme} = options if (!sheet) { return } - const manager = getManager(options.context, options.index) - - manager.manage(options.theme) + const manager = getManager(context, index) + manager.manage(theme) + if (context.registry) { + context.registry.add(sheet) + } } const unmanageSheet = (options: Options) => { diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index 6c6b8225e..f352723df 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -76,9 +76,10 @@ const withStyles = (styles: Styles, options?: HOCOptions = } static manage(props, state) { - if (state.sheet) { + const {sheet} = state + if (sheet) { manageSheet({ - sheet: state.sheet, + sheet, index, context: props.jssContext, theme: getTheme(props) @@ -87,7 +88,7 @@ const withStyles = (styles: Styles, options?: HOCOptions = } static unmanage(props, state) { - const sheet = state.sheet + const {sheet, dynamicRules} = state if (sheet) { unmanageSheet({ @@ -97,8 +98,8 @@ const withStyles = (styles: Styles, options?: HOCOptions = theme: getTheme(props) }) - if (state.dynamicRules) { - removeDynamicRules(sheet, state.dynamicRules) + if (dynamicRules) { + removeDynamicRules(sheet, dynamicRules) } } } diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/withStyles.test.js index a8e7e6948..385e4940e 100644 --- a/packages/react-jss/src/withStyles.test.js +++ b/packages/react-jss/src/withStyles.test.js @@ -266,7 +266,7 @@ describe('React-JSS: withStyles', () => { } const MyComponent = withStyles(() => ({}))(DisplayNameTest) - TestRenderer.create() + TestRenderer.create() expect( console.warn.calledWithExactly( @@ -275,13 +275,13 @@ describe('React-JSS: withStyles', () => { ).to.be(true) }) - it('doesnt warn if themed styles _do use_ theme', () => { + it('should not warn if themed styles _do use_ theme', () => { function DisplayNameTest() { return null } const MyComponent = withStyles(theme => ({}))(DisplayNameTest) // eslint-disable-line no-unused-vars - TestRenderer.create() + TestRenderer.create() expect(console.warn.called).to.be(false) }) From 2036cf461fc58547a785cc2c5b862eb62d04632e Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Thu, 30 May 2019 19:11:05 +0200 Subject: [PATCH 30/52] Fixed all tests --- packages/react-jss/.size-snapshot.json | 24 +++++++++++------------ packages/react-jss/src/utils/sheets.js | 4 ++++ packages/react-jss/src/withStyles.js | 2 +- packages/react-jss/src/withStyles.test.js | 4 ---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 472421168..645b36fcd 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 127101, - "minified": 43747, - "gzipped": 13674 + "bundled": 113871, + "minified": 38601, + "gzipped": 12450 }, "dist/react-jss.min.js": { - "bundled": 94714, - "minified": 33855, - "gzipped": 10879 + "bundled": 89310, + "minified": 31316, + "gzipped": 10274 }, "dist/react-jss.cjs.js": { - "bundled": 19684, - "minified": 9079, - "gzipped": 2938 + "bundled": 19767, + "minified": 9121, + "gzipped": 2949 }, "dist/react-jss.esm.js": { - "bundled": 18842, - "minified": 8345, - "gzipped": 2819, + "bundled": 18925, + "minified": 8387, + "gzipped": 2829, "treeshaked": { "rollup": { "code": 1903, diff --git a/packages/react-jss/src/utils/sheets.js b/packages/react-jss/src/utils/sheets.js index 104f96e5b..5135e7fe3 100644 --- a/packages/react-jss/src/utils/sheets.js +++ b/packages/react-jss/src/utils/sheets.js @@ -47,6 +47,10 @@ function getSheetOptions(options: Options, link: boolean) { } function createStaticSheet(options: Options) { + if (options.context.disableStylesGeneration) { + return undefined + } + const manager = getManager(options.context, options.index) const existingSheet = manager.get(options.theme) diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index f352723df..072c5723c 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -66,7 +66,7 @@ const withStyles = (styles: Styles, options?: HOCOptions = return {classes: {}, dynamicRules: undefined, sheet: undefined} } - const dynamicRules = addDynamicRules(sheet) + const dynamicRules = addDynamicRules(sheet, props) return { sheet, diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/withStyles.test.js index 385e4940e..9c88d549c 100644 --- a/packages/react-jss/src/withStyles.test.js +++ b/packages/react-jss/src/withStyles.test.js @@ -82,8 +82,6 @@ describe('React-JSS: withStyles', () => { const indexA = registry.registry[0].options.index const indexB = registry.registry[1].options.index - expect(indexA).to.be.lessThan(0) - expect(indexB).to.be.lessThan(0) expect(indexA).to.be.lessThan(indexB) }) @@ -99,8 +97,6 @@ describe('React-JSS: withStyles', () => { const indexA = registry.registry[0].options.index const indexB = registry.registry[1].options.index - expect(indexA).to.be.lessThan(0) - expect(indexB).to.be.lessThan(0) expect(indexA).to.be.lessThan(indexB) }) From 5aed3f8517e746c15baaebe4333d32f268d28454 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Thu, 30 May 2019 19:21:44 +0200 Subject: [PATCH 31/52] Fix linting etc. --- packages/react-jss/.size-snapshot.json | 24 +++++------ packages/react-jss/src/createUseStyles.js | 50 +++++++++++++++-------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 645b36fcd..638c8a762 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 113871, - "minified": 38601, - "gzipped": 12450 + "bundled": 127500, + "minified": 43831, + "gzipped": 13703 }, "dist/react-jss.min.js": { - "bundled": 89310, - "minified": 31316, - "gzipped": 10274 + "bundled": 95113, + "minified": 33939, + "gzipped": 10911 }, "dist/react-jss.cjs.js": { - "bundled": 19767, - "minified": 9121, - "gzipped": 2949 + "bundled": 20057, + "minified": 9163, + "gzipped": 2966 }, "dist/react-jss.esm.js": { - "bundled": 18925, - "minified": 8387, - "gzipped": 2829, + "bundled": 19215, + "minified": 8429, + "gzipped": 2848, "treeshaked": { "rollup": { "code": 1903, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index db6dadec3..85a890633 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -49,36 +49,52 @@ const createUseStyles = (styles: Styles, options?: HookOptions sheetOptions }) - if (context.registry) { + if (context.registry && sheet) { context.registry.add(sheet) } return sheet }) - const [dynamicRules, setDynamicRules] = React.useState(() => addDynamicRules(staticSheet, data)) + const [dynamicRules, setDynamicRules] = React.useState(() => { + if (staticSheet) { + return addDynamicRules(staticSheet, data) + } + + return undefined + }) - const [classes, setClasses] = React.useState(() => getSheetClasses(staticSheet, dynamicRules)) + const [classes, setClasses] = React.useState(() => { + if (staticSheet) { + return getSheetClasses(staticSheet, dynamicRules) + } + + return {} + }) useLayoutEffect( () => { - manageSheet({ - index, - context, - sheet: staticSheet, - theme - }) - - return () => { - unmanageSheet({ + if (staticSheet) { + manageSheet({ index, context, sheet: staticSheet, theme }) + } - if (dynamicRules) { - removeDynamicRules(staticSheet, dynamicRules) + return () => { + if (staticSheet) { + unmanageSheet({ + index, + context, + sheet: staticSheet, + theme + }) + + if (dynamicRules) { + removeDynamicRules(staticSheet, dynamicRules) + } } } }, @@ -87,7 +103,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions useLayoutEffect( () => { - if (dynamicRules) { + if (dynamicRules && staticSheet) { updateDynamicRules(data, staticSheet, dynamicRules) } }, @@ -105,8 +121,8 @@ const createUseStyles = (styles: Styles, options?: HookOptions index, sheetOptions }) - const newDynamicRules = addDynamicRules(staticSheet, data) - const newClasses = getSheetClasses(staticSheet, dynamicRules) + const newDynamicRules = staticSheet ? addDynamicRules(staticSheet, data) : undefined + const newClasses = staticSheet ? getSheetClasses(staticSheet, dynamicRules) : undefined setStaticSheet(newStaticSheet) setDynamicRules(newDynamicRules) From d4d372a05cd0a9326cfa8fe6a7e53bcedac6d207 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Thu, 30 May 2019 19:30:42 +0200 Subject: [PATCH 32/52] Use MIN_SAFE_INTEGER --- packages/react-jss/.size-snapshot.json | 26 ++++++++++---------- packages/react-jss/src/utils/indexCounter.js | 5 +++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 638c8a762..11e1596e5 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/react-jss.js": { - "bundled": 127500, - "minified": 43831, - "gzipped": 13703 + "bundled": 127683, + "minified": 43853, + "gzipped": 13724 }, "dist/react-jss.min.js": { - "bundled": 95113, - "minified": 33939, - "gzipped": 10911 + "bundled": 95296, + "minified": 33961, + "gzipped": 10931 }, "dist/react-jss.cjs.js": { - "bundled": 20057, - "minified": 9163, - "gzipped": 2966 + "bundled": 20234, + "minified": 9185, + "gzipped": 2989 }, "dist/react-jss.esm.js": { - "bundled": 19215, - "minified": 8429, - "gzipped": 2848, + "bundled": 19392, + "minified": 8451, + "gzipped": 2871, "treeshaked": { "rollup": { "code": 1903, "import_statements": 432 }, "webpack": { - "code": 3295 + "code": 3319 } } } diff --git a/packages/react-jss/src/utils/indexCounter.js b/packages/react-jss/src/utils/indexCounter.js index 3e3bbb444..d864fedd4 100644 --- a/packages/react-jss/src/utils/indexCounter.js +++ b/packages/react-jss/src/utils/indexCounter.js @@ -9,7 +9,10 @@ * specificity, because of the source order. * So our solution is to render sheets them in the reverse order child->sheet, so * that parent has a higher specificity. + * + * We start at [Number.MIN_SAFE_INTEGER] to always insert sheets from react-jss first before any + * sheet which might be inserted manually by the user. */ -let index = 0 +let index = Number.MIN_SAFE_INTEGER export const getIndex = () => index++ From afa04d805c64d51c90553b7bfa10243a5759b252 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sun, 2 Jun 2019 18:25:37 +0200 Subject: [PATCH 33/52] remove the need for extra eslit rules --- .eslintrc.js | 4 ---- packages/react-jss/.size-snapshot.json | 20 +++++++++---------- packages/react-jss/src/createUseStyles.js | 6 +++--- packages/react-jss/src/index.js | 6 +++--- packages/react-jss/src/index.test.js | 3 ++- .../react-jss/src/utils/getSheetClasses.js | 2 +- .../{indexCounter.js => getSheetIndex.js} | 4 +++- packages/react-jss/src/withStyles.js | 6 +++--- 8 files changed, 25 insertions(+), 26 deletions(-) rename packages/react-jss/src/utils/{indexCounter.js => getSheetIndex.js} (91%) diff --git a/.eslintrc.js b/.eslintrc.js index 73d55c4af..4289250c3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,10 +10,6 @@ module.exports = { __VERSION__: true, CSS: true }, - rules: { - 'import/prefer-default-export': 'off', - 'import/no-named-as-default': 'off' - }, overrides: [ { files: ['docs/*.md', 'docs/**/*.md'], diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 07ee02618..d37ca9184 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 127832, + "bundled": 127853, "minified": 43924, - "gzipped": 13757 + "gzipped": 13758 }, "dist/react-jss.min.js": { - "bundled": 95445, + "bundled": 95466, "minified": 34032, - "gzipped": 10966 + "gzipped": 10967 }, "dist/react-jss.cjs.js": { - "bundled": 20367, - "minified": 9281, - "gzipped": 3023 + "bundled": 20388, + "minified": 9296, + "gzipped": 3026 }, "dist/react-jss.esm.js": { - "bundled": 19525, - "minified": 8547, - "gzipped": 2903, + "bundled": 19546, + "minified": 8562, + "gzipped": 2907, "treeshaked": { "rollup": { "code": 1977, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 85a890633..d5ae10829 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -11,15 +11,15 @@ import { updateDynamicRules, removeDynamicRules } from './utils/sheets' -import {getIndex} from './utils/indexCounter' +import getSheetIndex from './utils/getSheetIndex' import type {HookOptions, Styles} from './types' import {manageSheet, unmanageSheet} from './utils/managers' -import {getSheetClasses} from './utils/getSheetClasses' +import getSheetClasses from './utils/getSheetClasses' const noTheme = {} const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { - const {index = getIndex(), theming, name = 'Hook', ...sheetOptions} = options + const {index = getSheetIndex(), theming, name = 'Hook', ...sheetOptions} = options const isFirstMount = React.useRef(true) const ThemeContext = (theming && theming.context) || DefaultThemeContext const useTheme = diff --git a/packages/react-jss/src/index.js b/packages/react-jss/src/index.js index 5eb6a24d9..4e411ce0e 100644 --- a/packages/react-jss/src/index.js +++ b/packages/react-jss/src/index.js @@ -1,14 +1,14 @@ // @flow import withStyles from './withStyles' -import createUseStyles from './createUseStyles' +export {default as createUseStyles} from './createUseStyles' export {ThemeProvider, withTheme, createTheming} from 'theming' export {default as JssProvider} from './JssProvider' export {default as jss} from './jss' export {SheetsRegistry, createGenerateId} from 'jss' export {default as JssContext} from './JssContext' -export {withStyles, createUseStyles} +export {withStyles} -// Kept for backwards compatibility +// Kept for backwards compatibility. export default withStyles diff --git a/packages/react-jss/src/index.test.js b/packages/react-jss/src/index.test.js index e3a8feb34..32723db6a 100644 --- a/packages/react-jss/src/index.test.js +++ b/packages/react-jss/src/index.test.js @@ -1,5 +1,6 @@ import expect from 'expect.js' -import withStyles, { +import { + withStyles, jss, createGenerateId, ThemeProvider, diff --git a/packages/react-jss/src/utils/getSheetClasses.js b/packages/react-jss/src/utils/getSheetClasses.js index 2910b9ec7..fd5605018 100644 --- a/packages/react-jss/src/utils/getSheetClasses.js +++ b/packages/react-jss/src/utils/getSheetClasses.js @@ -27,4 +27,4 @@ const getSheetClasses = (sheet: StyleSheet, dynamicRules: ?DynamicRules) => { return classes } -export {getSheetClasses} +export default getSheetClasses diff --git a/packages/react-jss/src/utils/indexCounter.js b/packages/react-jss/src/utils/getSheetIndex.js similarity index 91% rename from packages/react-jss/src/utils/indexCounter.js rename to packages/react-jss/src/utils/getSheetIndex.js index d864fedd4..5276fceef 100644 --- a/packages/react-jss/src/utils/indexCounter.js +++ b/packages/react-jss/src/utils/getSheetIndex.js @@ -15,4 +15,6 @@ */ let index = Number.MIN_SAFE_INTEGER -export const getIndex = () => index++ +const getSheetIndex = () => index++ + +export default getSheetIndex diff --git a/packages/react-jss/src/withStyles.js b/packages/react-jss/src/withStyles.js index 072c5723c..97bc53bbb 100644 --- a/packages/react-jss/src/withStyles.js +++ b/packages/react-jss/src/withStyles.js @@ -9,7 +9,7 @@ import getDisplayName from './getDisplayName' import memoize from './utils/memoizeOne' import mergeClasses from './utils/mergeClasses' import JssContext from './JssContext' -import {getIndex} from './utils/indexCounter' +import getSheetIndex from './utils/getSheetIndex' import { createStaticSheet, updateDynamicRules, @@ -17,7 +17,7 @@ import { removeDynamicRules } from './utils/sheets' import {manageSheet, unmanageSheet} from './utils/managers' -import {getSheetClasses} from './utils/getSheetClasses' +import getSheetClasses from './utils/getSheetClasses' interface State { dynamicRules: ?DynamicRules; @@ -35,7 +35,7 @@ const noTheme = {} * `withStyles(styles, [options])(Component)` */ const withStyles = (styles: Styles, options?: HOCOptions = {}) => { - const {index = getIndex(), theming, injectTheme, ...sheetOptions} = options + const {index = getSheetIndex(), theming, injectTheme, ...sheetOptions} = options const isThemingEnabled = typeof styles === 'function' const ThemeConsumer = (theming && theming.context.Consumer) || ThemeContext.Consumer From f6a9af4bd9e21047d903c91dd2a7c989dc3585fe Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 2 Jun 2019 19:28:34 +0200 Subject: [PATCH 34/52] Add tests for hooks and fix some issue --- packages/react-jss/.size-snapshot.json | 24 +-- packages/react-jss/src/createUseStyles.js | 4 +- .../react-jss/src/createUseStyles.test.js | 167 ++++++++++++++++++ 3 files changed, 181 insertions(+), 14 deletions(-) create mode 100644 packages/react-jss/src/createUseStyles.test.js diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index d37ca9184..99809a1ae 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 127853, - "minified": 43924, - "gzipped": 13758 + "bundled": 127868, + "minified": 43928, + "gzipped": 13767 }, "dist/react-jss.min.js": { - "bundled": 95466, - "minified": 34032, - "gzipped": 10967 + "bundled": 95481, + "minified": 34036, + "gzipped": 10973 }, "dist/react-jss.cjs.js": { - "bundled": 20388, - "minified": 9296, - "gzipped": 3026 + "bundled": 20403, + "minified": 9307, + "gzipped": 3033 }, "dist/react-jss.esm.js": { - "bundled": 19546, - "minified": 8562, - "gzipped": 2907, + "bundled": 19561, + "minified": 8573, + "gzipped": 2914, "treeshaked": { "rollup": { "code": 1977, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index d5ae10829..36b848337 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -20,18 +20,18 @@ const noTheme = {} const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { const {index = getSheetIndex(), theming, name = 'Hook', ...sheetOptions} = options - const isFirstMount = React.useRef(true) const ThemeContext = (theming && theming.context) || DefaultThemeContext const useTheme = typeof styles === 'function' ? // $FlowFixMe - (): Theme => React.useContext(ThemeContext) + (): Theme => React.useContext(ThemeContext) || noTheme : // $FlowFixMe (): Theme => noTheme const useLayoutEffect = isInBrowser ? React.useLayoutEffect : React.useEffect return (data: any) => { + const isFirstMount = React.useRef(true) const context = React.useContext(JssContext) const theme = useTheme() diff --git a/packages/react-jss/src/createUseStyles.test.js b/packages/react-jss/src/createUseStyles.test.js new file mode 100644 index 000000000..81908b04e --- /dev/null +++ b/packages/react-jss/src/createUseStyles.test.js @@ -0,0 +1,167 @@ +/* eslint-disable global-require, react/prop-types, no-underscore-dangle */ + +import expect from 'expect.js' +import React from 'react' +import {spy} from 'sinon' +import TestRenderer from 'react-test-renderer' + +import {JssProvider, SheetsRegistry} from '.' +import createUseStyles from './createUseStyles' + +const createHookComp = (styles, options) => { + const useStyles = createUseStyles(styles, options) + + const Comp = props => { + useStyles(props) + + return null + } + + return Comp +} + +describe('React-JSS: createUseStyles', () => { + it('should work in StrictMode without error on React 16.3+', () => { + const MyComponent = createHookComp({}) + + spy(console, 'error') + + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + + expect(console.error.notCalled).to.be(true) + + console.error.restore() + }) + + describe('reusing style sheets', () => { + it('should reuse one static sheet for many elements and detach sheet', () => { + const registry = new SheetsRegistry() + const MyComponent = createHookComp({ + button: {color: 'red'} + }) + + TestRenderer.act(() => { + TestRenderer.create( + + + + + + ) + }) + + expect(registry.registry.length, 1) + }) + }) + + describe('.withStyles() preserving source order', () => { + let ComponentA + let ComponentB + let ComponentC + let registry + + beforeEach(() => { + registry = new SheetsRegistry() + ComponentA = createHookComp({ + button: {color: 'red'} + }) + ComponentB = createHookComp({ + button: {color: 'blue'} + }) + ComponentC = createHookComp( + { + button: {color: 'green'} + }, + {index: 1234} + ) + }) + + it('should provide a default index in ascending order', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + + ) + }) + + expect(registry.registry.length).to.equal(2) + const indexA = registry.registry[0].options.index + const indexB = registry.registry[1].options.index + + expect(indexA).to.be.lessThan(indexB) + }) + + it('should not be affected by rendering order', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + + ) + }) + + expect(registry.registry.length).to.equal(2) + const indexA = registry.registry[0].options.index + const indexB = registry.registry[1].options.index + + expect(indexA).to.be.lessThan(indexB) + }) + + it('should keep custom index', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + + expect(registry.registry.length).to.equal(1) + const indexC = registry.registry[0].options.index + expect(indexC).to.equal(1234) + }) + }) + + describe('.withStyles() properly warns about themed styles misuse', () => { + beforeEach(() => { + spy(console, 'warn') + }) + + afterEach(() => { + console.warn.restore() + }) + + it('warn if themed styles dont use theme', () => { + const MyComponent = createHookComp(() => ({})) + + TestRenderer.act(() => { + TestRenderer.create() + }) + + expect( + console.warn.calledWithExactly( + `Warning: [JSS] 's styles function doesn't rely on the "theme" argument. We recommend declaring styles as an object instead.` + ) + ).to.be(true) + }) + + it('should not warn if themed styles _do use_ theme', () => { + const MyComponent = createHookComp(theme => ({})) // eslint-disable-line no-unused-vars + + TestRenderer.act(() => { + TestRenderer.create() + }) + + expect(console.warn.called).to.be(false) + }) + }) +}) From 59e5a2cd0151fca194de488cc58dff4097e09167 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sun, 2 Jun 2019 19:34:22 +0200 Subject: [PATCH 35/52] Remove check for disableStylesGeneration --- packages/react-jss/.size-snapshot.json | 24 +++++++++++------------ packages/react-jss/src/createUseStyles.js | 4 ---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 99809a1ae..db5d9b6ca 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 127868, - "minified": 43928, - "gzipped": 13767 + "bundled": 127795, + "minified": 43886, + "gzipped": 13753 }, "dist/react-jss.min.js": { - "bundled": 95481, - "minified": 34036, - "gzipped": 10973 + "bundled": 95408, + "minified": 33994, + "gzipped": 10964 }, "dist/react-jss.cjs.js": { - "bundled": 20403, - "minified": 9307, - "gzipped": 3033 + "bundled": 20336, + "minified": 9265, + "gzipped": 3024 }, "dist/react-jss.esm.js": { - "bundled": 19561, - "minified": 8573, - "gzipped": 2914, + "bundled": 19494, + "minified": 8531, + "gzipped": 2907, "treeshaked": { "rollup": { "code": 1977, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 36b848337..f477c14d8 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -35,10 +35,6 @@ const createUseStyles = (styles: Styles, options?: HookOptions const context = React.useContext(JssContext) const theme = useTheme() - if (context.disableStylesGeneration) { - return {} - } - const [staticSheet, setStaticSheet] = React.useState(() => { const sheet = createStaticSheet({ context, From 4f17feafa8764de1cc4e7814659ba6a09c8b73b6 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 11:24:20 +0200 Subject: [PATCH 36/52] more explicit name for the hook --- packages/react-jss/.size-snapshot.json | 30 +++++++++++------------ packages/react-jss/src/createUseStyles.js | 10 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index db5d9b6ca..d8b415844 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/react-jss.js": { - "bundled": 127795, - "minified": 43886, - "gzipped": 13753 + "bundled": 127825, + "minified": 43890, + "gzipped": 13755 }, "dist/react-jss.min.js": { - "bundled": 95408, - "minified": 33994, - "gzipped": 10964 + "bundled": 95438, + "minified": 33998, + "gzipped": 10967 }, "dist/react-jss.cjs.js": { - "bundled": 20336, - "minified": 9265, - "gzipped": 3024 + "bundled": 20366, + "minified": 9353, + "gzipped": 3036 }, "dist/react-jss.esm.js": { - "bundled": 19494, - "minified": 8531, - "gzipped": 2907, + "bundled": 19524, + "minified": 8619, + "gzipped": 2916, "treeshaked": { "rollup": { - "code": 1977, - "import_statements": 432 + "code": 2016, + "import_statements": 439 }, "webpack": { - "code": 3399 + "code": 3446 } } } diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index f477c14d8..f2e0b43bb 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -16,6 +16,8 @@ import type {HookOptions, Styles} from './types' import {manageSheet, unmanageSheet} from './utils/managers' import getSheetClasses from './utils/getSheetClasses' +const useEffectOrLayoutEffect = isInBrowser ? React.useLayoutEffect : React.useEffect + const noTheme = {} const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { @@ -28,8 +30,6 @@ const createUseStyles = (styles: Styles, options?: HookOptions : // $FlowFixMe (): Theme => noTheme - const useLayoutEffect = isInBrowser ? React.useLayoutEffect : React.useEffect - return (data: any) => { const isFirstMount = React.useRef(true) const context = React.useContext(JssContext) @@ -68,7 +68,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions return {} }) - useLayoutEffect( + useEffectOrLayoutEffect( () => { if (staticSheet) { manageSheet({ @@ -97,7 +97,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions [staticSheet] ) - useLayoutEffect( + useEffectOrLayoutEffect( () => { if (dynamicRules && staticSheet) { updateDynamicRules(data, staticSheet, dynamicRules) @@ -106,7 +106,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions [data] ) - useLayoutEffect( + useEffectOrLayoutEffect( () => { if (!isFirstMount.current) { const newStaticSheet = createStaticSheet({ From 71b53e6e25bfb73cf6c4be2b893d00f8e75f7666 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 13:47:23 +0200 Subject: [PATCH 37/52] port class name prefix test --- .../react-jss/src/createUseStyles.test.js | 34 ++++ packages/react-jss/src/index.test.js | 7 +- packages/react-jss/src/withStyles.test.js | 168 ------------------ 3 files changed, 40 insertions(+), 169 deletions(-) diff --git a/packages/react-jss/src/createUseStyles.test.js b/packages/react-jss/src/createUseStyles.test.js index 81908b04e..48a6f8012 100644 --- a/packages/react-jss/src/createUseStyles.test.js +++ b/packages/react-jss/src/createUseStyles.test.js @@ -164,4 +164,38 @@ describe('React-JSS: createUseStyles', () => { expect(console.warn.called).to.be(false) }) }) + + describe('classNamePrefix', () => { + let classNamePrefix + const generateId = (rule, sheet) => { + classNamePrefix = sheet.options.classNamePrefix + return `${rule.key}-id` + } + + const renderTest = (name = 'DisplayNameTest') => { + const MyComponent = createHookComp( + { + a: {color: 'red'} + }, + {name} + ) + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + } + + it('should pass displayName as prefix', () => { + renderTest() + expect(classNamePrefix).to.be('DisplayNameTest-') + }) + + it('should handle spaces correctly', () => { + renderTest('Display Name Test') + expect(classNamePrefix).to.be('Display-Name-Test-') + }) + }) }) diff --git a/packages/react-jss/src/index.test.js b/packages/react-jss/src/index.test.js index 32723db6a..fe11f12f1 100644 --- a/packages/react-jss/src/index.test.js +++ b/packages/react-jss/src/index.test.js @@ -7,7 +7,8 @@ import { JssProvider, SheetsRegistry, withTheme, - createTheming + createTheming, + createUseStyles } from '.' describe('React-JSS: exports', () => { @@ -42,4 +43,8 @@ describe('React-JSS: exports', () => { it('should export createTheming', () => { expect(createTheming).to.be.a(Function) }) + + it('should export createUseStyles', () => { + expect(createUseStyles).to.be.a(Function) + }) }) diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/withStyles.test.js index 6603c9e74..035fa8c8e 100644 --- a/packages/react-jss/src/withStyles.test.js +++ b/packages/react-jss/src/withStyles.test.js @@ -13,105 +13,6 @@ const createGenerateId = () => { } describe('React-JSS: withStyles', () => { - it('should work in StrictMode without error on React 16.3+', () => { - const MyComponent = withStyles({})() - - spy(console, 'error') - - TestRenderer.create( - - - - ) - - expect(console.error.notCalled).to.be(true) - - console.error.restore() - }) - - describe('reusing style sheets', () => { - it('should reuse one static sheet for many elements and detach sheet', () => { - const registry = new SheetsRegistry() - const MyComponent = withStyles({ - button: {color: 'red'} - })() - - TestRenderer.create( - - - - - - ) - - expect(registry.registry.length, 1) - }) - }) - - describe('.withStyles() preserving source order', () => { - let ComponentA - let ComponentB - let ComponentC - let registry - - beforeEach(() => { - registry = new SheetsRegistry() - ComponentA = withStyles({ - button: {color: 'red'} - })() - ComponentB = withStyles({ - button: {color: 'blue'} - })() - ComponentC = withStyles( - { - button: {color: 'green'} - }, - {index: 1234} - )() - }) - - it('should provide a default index in ascending order', () => { - TestRenderer.create( - - - - - ) - - expect(registry.registry.length).to.equal(2) - const indexA = registry.registry[0].options.index - const indexB = registry.registry[1].options.index - - expect(indexA).to.be.lessThan(indexB) - }) - - it('should not be affected by rendering order', () => { - TestRenderer.create( - - - - - ) - - expect(registry.registry.length).to.equal(2) - const indexA = registry.registry[0].options.index - const indexB = registry.registry[1].options.index - - expect(indexA).to.be.lessThan(indexB) - }) - - it('should keep custom index', () => { - TestRenderer.create( - - - - ) - expect(registry.registry.length).to.equal(1) - const indexC = registry.registry[0].options.index - expect(indexC).to.equal(1234) - }) - }) - describe('should merge the classes', () => { const styles = { button: {color: 'red'} @@ -206,73 +107,4 @@ describe('React-JSS: withStyles', () => { expect(innerRef.callCount).to.be(1) }) }) - - describe('classNamePrefix', () => { - let classNamePrefix - const generateId = (rule, sheet) => { - classNamePrefix = sheet.options.classNamePrefix - return `${rule.key}-id` - } - - const renderTest = (displayName = 'DisplayNameTest') => { - function DisplayNameTest() { - return null - } - DisplayNameTest.displayName = displayName - const MyComponent = withStyles({ - a: {color: 'red'} - })(DisplayNameTest) - TestRenderer.create( - - - - ) - } - - it('should pass displayName as prefix', () => { - renderTest() - expect(classNamePrefix).to.be('DisplayNameTest-') - }) - - it('should handle spaces correctly', () => { - renderTest('Display Name Test') - expect(classNamePrefix).to.be('Display-Name-Test-') - }) - }) - - describe('.withStyles() properly warns about themed styles misuse', () => { - beforeEach(() => { - spy(console, 'warn') - }) - - afterEach(() => { - console.warn.restore() - }) - - it('warn if themed styles dont use theme', () => { - function DisplayNameTest() { - return null - } - const MyComponent = withStyles(() => ({}))(DisplayNameTest) - - TestRenderer.create() - - expect( - console.warn.calledWithExactly( - `Warning: [JSS] 's styles function doesn't rely on the "theme" argument. We recommend declaring styles as an object instead.` - ) - ).to.be(true) - }) - - it('should not warn if themed styles _do use_ theme', () => { - function DisplayNameTest() { - return null - } - const MyComponent = withStyles(theme => ({}))(DisplayNameTest) // eslint-disable-line no-unused-vars - - TestRenderer.create() - - expect(console.warn.called).to.be(false) - }) - }) }) From 59c2560f936b215c4031988ff28f1aa65be7eb94 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 14:46:00 +0200 Subject: [PATCH 38/52] reuse tests between hooks and hocs --- .../react-jss/src/createUseStyles.test.js | 190 +----------------- packages/react-jss/src/withStyles.test.js | 11 +- .../test-utils/createHocAndHooksTests.js | 188 +++++++++++++++++ 3 files changed, 201 insertions(+), 188 deletions(-) create mode 100644 packages/react-jss/test-utils/createHocAndHooksTests.js diff --git a/packages/react-jss/src/createUseStyles.test.js b/packages/react-jss/src/createUseStyles.test.js index 48a6f8012..adfc2028e 100644 --- a/packages/react-jss/src/createUseStyles.test.js +++ b/packages/react-jss/src/createUseStyles.test.js @@ -1,201 +1,17 @@ /* eslint-disable global-require, react/prop-types, no-underscore-dangle */ -import expect from 'expect.js' -import React from 'react' -import {spy} from 'sinon' -import TestRenderer from 'react-test-renderer' - -import {JssProvider, SheetsRegistry} from '.' import createUseStyles from './createUseStyles' +import createHocAndHooksTests from '../test-utils/createHocAndHooksTests' -const createHookComp = (styles, options) => { +const createStyledComponent = (styles, options) => { const useStyles = createUseStyles(styles, options) - const Comp = props => { useStyles(props) - return null } - return Comp } describe('React-JSS: createUseStyles', () => { - it('should work in StrictMode without error on React 16.3+', () => { - const MyComponent = createHookComp({}) - - spy(console, 'error') - - TestRenderer.act(() => { - TestRenderer.create( - - - - ) - }) - - expect(console.error.notCalled).to.be(true) - - console.error.restore() - }) - - describe('reusing style sheets', () => { - it('should reuse one static sheet for many elements and detach sheet', () => { - const registry = new SheetsRegistry() - const MyComponent = createHookComp({ - button: {color: 'red'} - }) - - TestRenderer.act(() => { - TestRenderer.create( - - - - - - ) - }) - - expect(registry.registry.length, 1) - }) - }) - - describe('.withStyles() preserving source order', () => { - let ComponentA - let ComponentB - let ComponentC - let registry - - beforeEach(() => { - registry = new SheetsRegistry() - ComponentA = createHookComp({ - button: {color: 'red'} - }) - ComponentB = createHookComp({ - button: {color: 'blue'} - }) - ComponentC = createHookComp( - { - button: {color: 'green'} - }, - {index: 1234} - ) - }) - - it('should provide a default index in ascending order', () => { - TestRenderer.act(() => { - TestRenderer.create( - - - - - ) - }) - - expect(registry.registry.length).to.equal(2) - const indexA = registry.registry[0].options.index - const indexB = registry.registry[1].options.index - - expect(indexA).to.be.lessThan(indexB) - }) - - it('should not be affected by rendering order', () => { - TestRenderer.act(() => { - TestRenderer.create( - - - - - ) - }) - - expect(registry.registry.length).to.equal(2) - const indexA = registry.registry[0].options.index - const indexB = registry.registry[1].options.index - - expect(indexA).to.be.lessThan(indexB) - }) - - it('should keep custom index', () => { - TestRenderer.act(() => { - TestRenderer.create( - - - - ) - }) - - expect(registry.registry.length).to.equal(1) - const indexC = registry.registry[0].options.index - expect(indexC).to.equal(1234) - }) - }) - - describe('.withStyles() properly warns about themed styles misuse', () => { - beforeEach(() => { - spy(console, 'warn') - }) - - afterEach(() => { - console.warn.restore() - }) - - it('warn if themed styles dont use theme', () => { - const MyComponent = createHookComp(() => ({})) - - TestRenderer.act(() => { - TestRenderer.create() - }) - - expect( - console.warn.calledWithExactly( - `Warning: [JSS] 's styles function doesn't rely on the "theme" argument. We recommend declaring styles as an object instead.` - ) - ).to.be(true) - }) - - it('should not warn if themed styles _do use_ theme', () => { - const MyComponent = createHookComp(theme => ({})) // eslint-disable-line no-unused-vars - - TestRenderer.act(() => { - TestRenderer.create() - }) - - expect(console.warn.called).to.be(false) - }) - }) - - describe('classNamePrefix', () => { - let classNamePrefix - const generateId = (rule, sheet) => { - classNamePrefix = sheet.options.classNamePrefix - return `${rule.key}-id` - } - - const renderTest = (name = 'DisplayNameTest') => { - const MyComponent = createHookComp( - { - a: {color: 'red'} - }, - {name} - ) - TestRenderer.act(() => { - TestRenderer.create( - - - - ) - }) - } - - it('should pass displayName as prefix', () => { - renderTest() - expect(classNamePrefix).to.be('DisplayNameTest-') - }) - - it('should handle spaces correctly', () => { - renderTest('Display Name Test') - expect(classNamePrefix).to.be('Display-Name-Test-') - }) - }) + createHocAndHooksTests({createStyledComponent}) }) diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/withStyles.test.js index 035fa8c8e..5b7d76f23 100644 --- a/packages/react-jss/src/withStyles.test.js +++ b/packages/react-jss/src/withStyles.test.js @@ -5,14 +5,23 @@ import React from 'react' import {spy} from 'sinon' import TestRenderer from 'react-test-renderer' -import {withStyles, JssProvider, SheetsRegistry} from '.' +import {withStyles, JssProvider} from '.' +import createHocAndHooksTests from '../test-utils/createHocAndHooksTests' const createGenerateId = () => { let counter = 0 return rule => `${rule.key}-${counter++}` } +const createStyledComponent = (styles, options = {}) => { + const Comp = () => null + Comp.displayName = options.name + return withStyles(styles, options)(Comp) +} + describe('React-JSS: withStyles', () => { + createHocAndHooksTests({createStyledComponent}) + describe('should merge the classes', () => { const styles = { button: {color: 'red'} diff --git a/packages/react-jss/test-utils/createHocAndHooksTests.js b/packages/react-jss/test-utils/createHocAndHooksTests.js new file mode 100644 index 000000000..7b94401fb --- /dev/null +++ b/packages/react-jss/test-utils/createHocAndHooksTests.js @@ -0,0 +1,188 @@ +/* eslint-disable global-require, react/prop-types, no-underscore-dangle */ + +import expect from 'expect.js' +import React from 'react' +import {spy} from 'sinon' +import TestRenderer from 'react-test-renderer' + +import {JssProvider, SheetsRegistry} from '../src' + +export default ({createStyledComponent}) => { + it('should work in StrictMode without error on React 16.3+', () => { + const MyComponent = createStyledComponent({}) + + spy(console, 'error') + + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + + expect(console.error.notCalled).to.be(true) + + console.error.restore() + }) + + describe('reusing style sheets', () => { + it('should reuse one static sheet for many elements and detach sheet', () => { + const registry = new SheetsRegistry() + const MyComponent = createStyledComponent({ + button: {color: 'red'} + }) + + TestRenderer.act(() => { + TestRenderer.create( + + + + + + ) + }) + + expect(registry.registry.length, 1) + }) + }) + + describe('.withStyles() preserving source order', () => { + let ComponentA + let ComponentB + let ComponentC + let registry + + beforeEach(() => { + registry = new SheetsRegistry() + ComponentA = createStyledComponent({ + button: {color: 'red'} + }) + ComponentB = createStyledComponent({ + button: {color: 'blue'} + }) + ComponentC = createStyledComponent( + { + button: {color: 'green'} + }, + {index: 1234} + ) + }) + + it('should provide a default index in ascending order', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + + ) + }) + + expect(registry.registry.length).to.equal(2) + const indexA = registry.registry[0].options.index + const indexB = registry.registry[1].options.index + + expect(indexA).to.be.lessThan(indexB) + }) + + it('should not be affected by rendering order', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + + ) + }) + + expect(registry.registry.length).to.equal(2) + const indexA = registry.registry[0].options.index + const indexB = registry.registry[1].options.index + + expect(indexA).to.be.lessThan(indexB) + }) + + it('should keep custom index', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + + expect(registry.registry.length).to.equal(1) + const indexC = registry.registry[0].options.index + expect(indexC).to.equal(1234) + }) + }) + + describe('.withStyles() properly warns about themed styles misuse', () => { + beforeEach(() => { + spy(console, 'warn') + }) + + afterEach(() => { + console.warn.restore() + }) + + it('warn if themed styles dont use theme', () => { + const MyComponent = createStyledComponent(() => ({}), {name: 'Comp'}) + + TestRenderer.act(() => { + TestRenderer.create() + }) + + expect( + console.warn.calledWithExactly( + `Warning: [JSS] 's styles function doesn't rely on the "theme" argument. We recommend declaring styles as an object instead.` + ) + ).to.be(true) + }) + + it('should not warn if themed styles _do use_ theme', () => { + const MyComponent = createStyledComponent(theme => ({})) // eslint-disable-line no-unused-vars + + TestRenderer.act(() => { + TestRenderer.create() + }) + + expect(console.warn.called).to.be(false) + }) + }) + + describe('classNamePrefix', () => { + let classNamePrefix + const generateId = (rule, sheet) => { + classNamePrefix = sheet.options.classNamePrefix + return `${rule.key}-id` + } + + const renderTest = (name = 'DisplayNameTest') => { + const MyComponent = createStyledComponent( + { + a: {color: 'red'} + }, + {name} + ) + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + } + + it('should pass displayName as prefix', () => { + renderTest() + expect(classNamePrefix).to.be('DisplayNameTest-') + }) + + it('should handle spaces correctly', () => { + renderTest('Display Name Test') + expect(classNamePrefix).to.be('Display-Name-Test-') + }) + }) +} From aef6158962c881b47af6ac5f35018e328f3a2783 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 20:53:03 +0200 Subject: [PATCH 39/52] make dynamicStyles tests use hooks --- .../react-jss/src/createUseStyles.test.js | 2 +- packages/react-jss/src/withStyles.test.js | 2 +- .../test-utils/createDynamicStylesTests.js | 390 ++++++++++++++++++ packages/react-jss/tests/dynamicStyles.js | 389 +---------------- 4 files changed, 406 insertions(+), 377 deletions(-) create mode 100644 packages/react-jss/test-utils/createDynamicStylesTests.js diff --git a/packages/react-jss/src/createUseStyles.test.js b/packages/react-jss/src/createUseStyles.test.js index adfc2028e..79473c600 100644 --- a/packages/react-jss/src/createUseStyles.test.js +++ b/packages/react-jss/src/createUseStyles.test.js @@ -1,4 +1,4 @@ -/* eslint-disable global-require, react/prop-types, no-underscore-dangle */ +/* eslint-disable react/prop-types */ import createUseStyles from './createUseStyles' import createHocAndHooksTests from '../test-utils/createHocAndHooksTests' diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/withStyles.test.js index 5b7d76f23..725074484 100644 --- a/packages/react-jss/src/withStyles.test.js +++ b/packages/react-jss/src/withStyles.test.js @@ -1,4 +1,4 @@ -/* eslint-disable global-require, react/prop-types, no-underscore-dangle */ +/* eslint-disable react/prop-types */ import expect from 'expect.js' import React from 'react' diff --git a/packages/react-jss/test-utils/createDynamicStylesTests.js b/packages/react-jss/test-utils/createDynamicStylesTests.js new file mode 100644 index 000000000..b47bbbdfa --- /dev/null +++ b/packages/react-jss/test-utils/createDynamicStylesTests.js @@ -0,0 +1,390 @@ +/* eslint-disable global-require, react/prop-types, react/no-find-dom-node, react/no-multi-comp, react/prefer-stateless-function */ + +import expect from 'expect.js' +import React from 'react' +import TestRenderer from 'react-test-renderer' +import {stripIndent} from 'common-tags' + +import injectSheet, {JssProvider, SheetsRegistry} from '../src' + +const createGenerateId = () => { + let counter = 0 + return rule => `${rule.key}-${counter++}` +} + +export default ({createStyledComponent}) => { + const NoRenderer = () => null + NoRenderer.displayName = 'NoRenderer' + let registry + + beforeEach(() => { + registry = new SheetsRegistry() + }) + + describe('function values', () => { + let MyComponent + let classes + + beforeEach(() => { + MyComponent = createStyledComponent( + { + button: { + color: 'rgb(255, 255, 255)', + height: ({height = 1}) => `${height}px` + } + }, + {name: 'NoRenderer'} + ) + MyComponent.defaultProps = { + getClasses: cls => { + classes = cls + } + } + }) + + it('should attach and detach a sheet', () => { + const renderer = TestRenderer.create( + + + + ) + + expect(registry.registry.length).to.equal(1) + expect(registry.registry[0].attached).to.equal(true) + + renderer.unmount() + + expect(registry.registry[0].attached).to.equal(false) + }) + + it('should have correct meta attribute', () => { + TestRenderer.create( + + + + ) + + expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed') + }) + + it('should reuse sheet between component instances', () => { + TestRenderer.create( + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('should have dynamic and static styles', () => { + TestRenderer.act(() => { + TestRenderer.create( + + + + ) + }) + + expect(classes.button).to.equal('button-0 button-0-1') + }) + + it('should generate different dynamic values', () => { + TestRenderer.create( + + + + + ) + + expect(registry.toString()).to.equal(stripIndent` + .button-0 { + color: rgb(255, 255, 255); + } + .button-0-1 { + height: 10px; + } + .button-1-2 { + height: 20px; + } + `) + }) + + it('should update dynamic values', () => { + const generateId = createGenerateId() + const Container = ({height}) => ( + + + + + ) + + const renderer = TestRenderer.create() + + expect(registry.toString()).to.equal(stripIndent` + .button-0 { + color: rgb(255, 255, 255); + } + .button-0-1 { + height: 10px; + } + .button-1-2 { + height: 20px; + } + `) + + renderer.update() + + expect(registry.toString()).to.equal(stripIndent` + .button-0 { + color: rgb(255, 255, 255); + } + .button-0-1 { + height: 20px; + } + .button-1-2 { + height: 40px; + } + `) + }) + + it('should unset values when null is returned from fn value', () => { + const generateId = createGenerateId() + MyComponent = injectSheet({ + button: { + width: 10, + height: ({height}) => height + } + })(NoRenderer) + const Container = ({height}) => ( + + + + ) + + const renderer = TestRenderer.create() + + expect(registry.toString()).to.equal(stripIndent` + .button-0 { + width: 10px; + } + .button-0-1 { + height: 10px; + } + `) + + renderer.update() + + expect(registry.toString()).to.equal(stripIndent` + .button-0 { + width: 10px; + } + .button-0-1 {} + `) + }) + + it('should unset values when null is returned from fn rule', () => { + const generateId = createGenerateId() + MyComponent = injectSheet({ + button0: { + width: 10 + }, + button1: ({height}) => ({ + height + }) + })(NoRenderer) + const Container = ({height}) => ( + + + + ) + + const renderer = TestRenderer.create() + + expect(registry.toString()).to.equal(stripIndent` + .button0-0 { + width: 10px; + } + .button1-1 {} + .button1-0-2 { + height: 10px; + } + `) + + renderer.update() + + expect(registry.toString()).to.equal(stripIndent` + .button0-0 { + width: 10px; + } + .button1-1 {} + .button1-0-2 {} + `) + }) + + it('should pass the props of the component', () => { + let passedProps + + const styles = { + a: { + color(props) { + passedProps = props + return 'rgb(255, 255, 255)' + } + } + } + const InnerComponent = () => null + InnerComponent.defaultProps = { + color: 'rgb(255, 0, 0)' + } + const StyledComponent = injectSheet(styles)(InnerComponent) + + TestRenderer.create() + + expect(passedProps.color).to.equal('rgb(255, 0, 0)') + expect(passedProps.height).to.equal(20) + }) + }) + + describe('function rules', () => { + let MyComponent + + beforeEach(() => { + MyComponent = injectSheet({ + button: ({height = 1}) => ({ + color: 'rgb(255, 255, 255)', + height: `${height}px` + }) + })(NoRenderer) + }) + + it('should attach and detach a sheet', () => { + const renderer = TestRenderer.create( + + + + ) + + expect(registry.registry.length).to.equal(1) + expect(registry.registry[0].attached).to.equal(true) + + renderer.unmount() + + expect(registry.registry[0].attached).to.equal(false) + }) + + it('should have correct meta attribute', () => { + TestRenderer.create( + + + + ) + + expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed') + }) + + it('should reuse static sheet, but generate separate dynamic once', () => { + TestRenderer.create( + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('should have dynamic and static styles', () => { + const renderer = TestRenderer.create( + + + + ) + const props = renderer.root.findByType(NoRenderer).props + + expect(props.classes.button).to.equal('button-0 button-0-1') + }) + + it('should generate different dynamic values', () => { + TestRenderer.create( + + + + + ) + + expect(registry.toString()).to.equal(stripIndent` + .button-0 {} + .button-0-1 { + color: rgb(255, 255, 255); + height: 10px; + } + .button-1-2 { + color: rgb(255, 255, 255); + height: 20px; + } + `) + }) + + it('should update dynamic values', () => { + const generateId = createGenerateId() + function Container({height}) { + return ( + + + + + ) + } + + const renderer = TestRenderer.create() + + expect(registry.toString()).to.equal(stripIndent` + .button-0 {} + .button-0-1 { + color: rgb(255, 255, 255); + height: 10px; + } + .button-1-2 { + color: rgb(255, 255, 255); + height: 20px; + } + `) + renderer.update() + + expect(registry.toString()).to.equal(stripIndent` + .button-0 {} + .button-0-1 { + color: rgb(255, 255, 255); + height: 20px; + } + .button-1-2 { + color: rgb(255, 255, 255); + height: 40px; + } + `) + }) + + it('should use the default props', () => { + let passedProps + + const styles = { + button(props) { + passedProps = props + return {color: 'rgb(255, 255, 255)'} + } + } + const InnerComponent = () => null + InnerComponent.defaultProps = { + color: 'rgb(255, 0, 0)' + } + const StyledComponent = injectSheet(styles)(InnerComponent) + + TestRenderer.create() + + expect(passedProps.color).to.equal('rgb(255, 0, 0)') + expect(passedProps.height).to.equal(20) + }) + }) +} diff --git a/packages/react-jss/tests/dynamicStyles.js b/packages/react-jss/tests/dynamicStyles.js index 43f8b1aca..19a6d2912 100644 --- a/packages/react-jss/tests/dynamicStyles.js +++ b/packages/react-jss/tests/dynamicStyles.js @@ -1,381 +1,20 @@ -/* eslint-disable global-require, react/prop-types, react/no-find-dom-node, react/no-multi-comp, react/prefer-stateless-function */ +/* eslint-disable react/prop-types */ -import expect from 'expect.js' -import React from 'react' -import TestRenderer from 'react-test-renderer' -import {stripIndent} from 'common-tags' +import {createUseStyles} from '../src' +import createDynamicStylesTests from '../test-utils/createDynamicStylesTests' -import injectSheet, {JssProvider, SheetsRegistry} from '../src' +const createStyledComponent = (styles, options = {}) => { + const useStyles = createUseStyles(styles, options) + const Comp = props => { + const classes = useStyles(props) + props.getClasses(classes) + return null + } + Comp.displayName = options.name -const createGenerateId = () => { - let counter = 0 - return rule => `${rule.key}-${counter++}` + return Comp } -describe('React-JSS: dynamic styles', () => { - const color = 'rgb(255, 255, 255)' - const NoRenderer = () => null - NoRenderer.displayName = 'NoRenderer' - let registry - - beforeEach(() => { - registry = new SheetsRegistry() - }) - - describe('function values', () => { - let MyComponent - - beforeEach(() => { - MyComponent = injectSheet({ - button: { - color, - height: ({height = 1}) => `${height}px` - } - })(NoRenderer) - }) - - it('should attach and detach a sheet', () => { - const renderer = TestRenderer.create( - - - - ) - - expect(registry.registry.length).to.equal(1) - expect(registry.registry[0].attached).to.equal(true) - - renderer.unmount() - - expect(registry.registry[0].attached).to.equal(false) - }) - - it('should have correct meta attribute', () => { - TestRenderer.create( - - - - ) - - expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed') - }) - - it('should reuse sheet between component instances', () => { - TestRenderer.create( - - - - - ) - - expect(registry.registry.length).to.equal(1) - }) - - it('should have dynamic and static styles', () => { - const renderer = TestRenderer.create( - - - - ) - const props = renderer.root.findByType(NoRenderer).props - - expect(props.classes.button).to.equal('button-0 button-0-1') - }) - - it('should generate different dynamic values', () => { - TestRenderer.create( - - - - - ) - - expect(registry.toString()).to.equal(stripIndent` - .button-0 { - color: ${color}; - } - .button-0-1 { - height: 10px; - } - .button-1-2 { - height: 20px; - } - `) - }) - - it('should update dynamic values', () => { - const generateId = createGenerateId() - const Container = ({height}) => ( - - - - - ) - - const renderer = TestRenderer.create() - - expect(registry.toString()).to.equal(stripIndent` - .button-0 { - color: ${color}; - } - .button-0-1 { - height: 10px; - } - .button-1-2 { - height: 20px; - } - `) - - renderer.update() - - expect(registry.toString()).to.equal(stripIndent` - .button-0 { - color: ${color}; - } - .button-0-1 { - height: 20px; - } - .button-1-2 { - height: 40px; - } - `) - }) - - it('should unset values when null is returned from fn value', () => { - const generateId = createGenerateId() - MyComponent = injectSheet({ - button: { - width: 10, - height: ({height}) => height - } - })(NoRenderer) - const Container = ({height}) => ( - - - - ) - - const renderer = TestRenderer.create() - - expect(registry.toString()).to.equal(stripIndent` - .button-0 { - width: 10px; - } - .button-0-1 { - height: 10px; - } - `) - - renderer.update() - - expect(registry.toString()).to.equal(stripIndent` - .button-0 { - width: 10px; - } - .button-0-1 {} - `) - }) - - it('should unset values when null is returned from fn rule', () => { - const generateId = createGenerateId() - MyComponent = injectSheet({ - button0: { - width: 10 - }, - button1: ({height}) => ({ - height - }) - })(NoRenderer) - const Container = ({height}) => ( - - - - ) - - const renderer = TestRenderer.create() - - expect(registry.toString()).to.equal(stripIndent` - .button0-0 { - width: 10px; - } - .button1-1 {} - .button1-0-2 { - height: 10px; - } - `) - - renderer.update() - - expect(registry.toString()).to.equal(stripIndent` - .button0-0 { - width: 10px; - } - .button1-1 {} - .button1-0-2 {} - `) - }) - - it('should pass the props of the component', () => { - let passedProps - - const styles = { - a: { - color(props) { - passedProps = props - return color - } - } - } - const InnerComponent = () => null - InnerComponent.defaultProps = { - color: 'rgb(255, 0, 0)' - } - const StyledComponent = injectSheet(styles)(InnerComponent) - - TestRenderer.create() - - expect(passedProps.color).to.equal('rgb(255, 0, 0)') - expect(passedProps.height).to.equal(20) - }) - }) - - describe('function rules', () => { - let MyComponent - - beforeEach(() => { - MyComponent = injectSheet({ - button: ({height = 1}) => ({ - color, - height: `${height}px` - }) - })(NoRenderer) - }) - - it('should attach and detach a sheet', () => { - const renderer = TestRenderer.create( - - - - ) - - expect(registry.registry.length).to.equal(1) - expect(registry.registry[0].attached).to.equal(true) - - renderer.unmount() - - expect(registry.registry[0].attached).to.equal(false) - }) - - it('should have correct meta attribute', () => { - TestRenderer.create( - - - - ) - - expect(registry.registry[0].options.meta).to.equal('NoRenderer, Unthemed') - }) - - it('should reuse static sheet, but generate separate dynamic once', () => { - TestRenderer.create( - - - - - ) - - expect(registry.registry.length).to.equal(1) - }) - - it('should have dynamic and static styles', () => { - const renderer = TestRenderer.create( - - - - ) - const props = renderer.root.findByType(NoRenderer).props - - expect(props.classes.button).to.equal('button-0 button-0-1') - }) - - it('should generate different dynamic values', () => { - TestRenderer.create( - - - - - ) - - expect(registry.toString()).to.equal(stripIndent` - .button-0 {} - .button-0-1 { - color: rgb(255, 255, 255); - height: 10px; - } - .button-1-2 { - color: rgb(255, 255, 255); - height: 20px; - } - `) - }) - - it('should update dynamic values', () => { - const generateId = createGenerateId() - function Container({height}) { - return ( - - - - - ) - } - - const renderer = TestRenderer.create() - - expect(registry.toString()).to.equal(stripIndent` - .button-0 {} - .button-0-1 { - color: ${color}; - height: 10px; - } - .button-1-2 { - color: ${color}; - height: 20px; - } - `) - renderer.update() - - expect(registry.toString()).to.equal(stripIndent` - .button-0 {} - .button-0-1 { - color: ${color}; - height: 20px; - } - .button-1-2 { - color: ${color}; - height: 40px; - } - `) - }) - - it('should use the default props', () => { - let passedProps - - const styles = { - button(props) { - passedProps = props - return {color} - } - } - const InnerComponent = () => null - InnerComponent.defaultProps = { - color: 'rgb(255, 0, 0)' - } - const StyledComponent = injectSheet(styles)(InnerComponent) - - TestRenderer.create() - - expect(passedProps.color).to.equal('rgb(255, 0, 0)') - expect(passedProps.height).to.equal(20) - }) - }) +describe('React-JSS: dynamic styles with createUseStyles', () => { + createDynamicStylesTests({createStyledComponent}) }) From 32bb698cbb4ba24f43b9da657974640bf9c94d6d Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 21:02:45 +0200 Subject: [PATCH 40/52] generate dynamic styles test using HOC --- packages/react-jss/tests/dynamicStyles.js | 40 +++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/react-jss/tests/dynamicStyles.js b/packages/react-jss/tests/dynamicStyles.js index 19a6d2912..b756b3627 100644 --- a/packages/react-jss/tests/dynamicStyles.js +++ b/packages/react-jss/tests/dynamicStyles.js @@ -1,20 +1,34 @@ /* eslint-disable react/prop-types */ -import {createUseStyles} from '../src' +import {createUseStyles, withStyles} from '../src' import createDynamicStylesTests from '../test-utils/createDynamicStylesTests' -const createStyledComponent = (styles, options = {}) => { - const useStyles = createUseStyles(styles, options) - const Comp = props => { - const classes = useStyles(props) - props.getClasses(classes) - return null - } - Comp.displayName = options.name +describe('React-JSS: dynamic styles', () => { + describe('using createUseStyles', () => { + const createStyledComponent = (styles, options = {}) => { + const useStyles = createUseStyles(styles, options) + const Comp = props => { + const classes = useStyles(props) + props.getClasses(classes) + return null + } + Comp.displayName = options.name + return Comp + } - return Comp -} + createDynamicStylesTests({createStyledComponent}) + }) -describe('React-JSS: dynamic styles with createUseStyles', () => { - createDynamicStylesTests({createStyledComponent}) + describe('using withStyles', () => { + const createStyledComponent = (styles, options = {}) => { + const Comp = props => { + props.getClasses(props.classes) + return null + } + Comp.displayName = options.name + return withStyles(styles, options)(Comp) + } + + createDynamicStylesTests({createStyledComponent}) + }) }) From 12b151c6cdbba0dcb87dcf29c4b6521e0740525f Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 21:24:10 +0200 Subject: [PATCH 41/52] migrate all dynamic styles tests to use createStyledComponent --- .../react-jss/src/createUseStyles.test.js | 4 +- packages/react-jss/src/withStyles.test.js | 4 +- ...ocAndHooksTests.js => createBasicTests.js} | 0 .../test-utils/createDynamicStylesTests.js | 59 +++++++++++-------- packages/react-jss/tests/dynamicStyles.js | 6 +- 5 files changed, 40 insertions(+), 33 deletions(-) rename packages/react-jss/test-utils/{createHocAndHooksTests.js => createBasicTests.js} (100%) diff --git a/packages/react-jss/src/createUseStyles.test.js b/packages/react-jss/src/createUseStyles.test.js index 79473c600..8017d28ce 100644 --- a/packages/react-jss/src/createUseStyles.test.js +++ b/packages/react-jss/src/createUseStyles.test.js @@ -1,7 +1,7 @@ /* eslint-disable react/prop-types */ import createUseStyles from './createUseStyles' -import createHocAndHooksTests from '../test-utils/createHocAndHooksTests' +import createBasicTests from '../test-utils/createBasicTests' const createStyledComponent = (styles, options) => { const useStyles = createUseStyles(styles, options) @@ -13,5 +13,5 @@ const createStyledComponent = (styles, options) => { } describe('React-JSS: createUseStyles', () => { - createHocAndHooksTests({createStyledComponent}) + createBasicTests({createStyledComponent}) }) diff --git a/packages/react-jss/src/withStyles.test.js b/packages/react-jss/src/withStyles.test.js index 725074484..553f737e6 100644 --- a/packages/react-jss/src/withStyles.test.js +++ b/packages/react-jss/src/withStyles.test.js @@ -6,7 +6,7 @@ import {spy} from 'sinon' import TestRenderer from 'react-test-renderer' import {withStyles, JssProvider} from '.' -import createHocAndHooksTests from '../test-utils/createHocAndHooksTests' +import createBasicTests from '../test-utils/createBasicTests' const createGenerateId = () => { let counter = 0 @@ -20,7 +20,7 @@ const createStyledComponent = (styles, options = {}) => { } describe('React-JSS: withStyles', () => { - createHocAndHooksTests({createStyledComponent}) + createBasicTests({createStyledComponent}) describe('should merge the classes', () => { const styles = { diff --git a/packages/react-jss/test-utils/createHocAndHooksTests.js b/packages/react-jss/test-utils/createBasicTests.js similarity index 100% rename from packages/react-jss/test-utils/createHocAndHooksTests.js rename to packages/react-jss/test-utils/createBasicTests.js diff --git a/packages/react-jss/test-utils/createDynamicStylesTests.js b/packages/react-jss/test-utils/createDynamicStylesTests.js index b47bbbdfa..d8d745d79 100644 --- a/packages/react-jss/test-utils/createDynamicStylesTests.js +++ b/packages/react-jss/test-utils/createDynamicStylesTests.js @@ -5,7 +5,7 @@ import React from 'react' import TestRenderer from 'react-test-renderer' import {stripIndent} from 'common-tags' -import injectSheet, {JssProvider, SheetsRegistry} from '../src' +import {JssProvider, SheetsRegistry} from '../src' const createGenerateId = () => { let counter = 0 @@ -13,8 +13,6 @@ const createGenerateId = () => { } export default ({createStyledComponent}) => { - const NoRenderer = () => null - NoRenderer.displayName = 'NoRenderer' let registry beforeEach(() => { @@ -151,12 +149,14 @@ export default ({createStyledComponent}) => { it('should unset values when null is returned from fn value', () => { const generateId = createGenerateId() - MyComponent = injectSheet({ + + MyComponent = createStyledComponent({ button: { width: 10, height: ({height}) => height } - })(NoRenderer) + }) + const Container = ({height}) => ( @@ -186,14 +186,15 @@ export default ({createStyledComponent}) => { it('should unset values when null is returned from fn rule', () => { const generateId = createGenerateId() - MyComponent = injectSheet({ + MyComponent = createStyledComponent({ button0: { width: 10 }, button1: ({height}) => ({ height }) - })(NoRenderer) + }) + const Container = ({height}) => ( @@ -234,13 +235,13 @@ export default ({createStyledComponent}) => { } } } - const InnerComponent = () => null - InnerComponent.defaultProps = { + + MyComponent = createStyledComponent(styles) + MyComponent.defaultProps = { color: 'rgb(255, 0, 0)' } - const StyledComponent = injectSheet(styles)(InnerComponent) - TestRenderer.create() + TestRenderer.create() expect(passedProps.color).to.equal('rgb(255, 0, 0)') expect(passedProps.height).to.equal(20) @@ -249,14 +250,23 @@ export default ({createStyledComponent}) => { describe('function rules', () => { let MyComponent + let classes beforeEach(() => { - MyComponent = injectSheet({ - button: ({height = 1}) => ({ - color: 'rgb(255, 255, 255)', - height: `${height}px` - }) - })(NoRenderer) + MyComponent = createStyledComponent( + { + button: ({height = 1}) => ({ + color: 'rgb(255, 255, 255)', + height: `${height}px` + }) + }, + {name: 'NoRenderer'} + ) + MyComponent.defaultProps = { + getClasses: cls => { + classes = cls + } + } }) it('should attach and detach a sheet', () => { @@ -296,14 +306,12 @@ export default ({createStyledComponent}) => { }) it('should have dynamic and static styles', () => { - const renderer = TestRenderer.create( + TestRenderer.create( ) - const props = renderer.root.findByType(NoRenderer).props - - expect(props.classes.button).to.equal('button-0 button-0-1') + expect(classes.button).to.equal('button-0 button-0-1') }) it('should generate different dynamic values', () => { @@ -375,13 +383,12 @@ export default ({createStyledComponent}) => { return {color: 'rgb(255, 255, 255)'} } } - const InnerComponent = () => null - InnerComponent.defaultProps = { + + MyComponent = createStyledComponent(styles) + MyComponent.defaultProps = { color: 'rgb(255, 0, 0)' } - const StyledComponent = injectSheet(styles)(InnerComponent) - - TestRenderer.create() + TestRenderer.create() expect(passedProps.color).to.equal('rgb(255, 0, 0)') expect(passedProps.height).to.equal(20) diff --git a/packages/react-jss/tests/dynamicStyles.js b/packages/react-jss/tests/dynamicStyles.js index b756b3627..43662efd9 100644 --- a/packages/react-jss/tests/dynamicStyles.js +++ b/packages/react-jss/tests/dynamicStyles.js @@ -9,7 +9,7 @@ describe('React-JSS: dynamic styles', () => { const useStyles = createUseStyles(styles, options) const Comp = props => { const classes = useStyles(props) - props.getClasses(classes) + if (props.getClasses) props.getClasses(classes) return null } Comp.displayName = options.name @@ -21,8 +21,8 @@ describe('React-JSS: dynamic styles', () => { describe('using withStyles', () => { const createStyledComponent = (styles, options = {}) => { - const Comp = props => { - props.getClasses(props.classes) + const Comp = ({getClasses, classes}) => { + if (getClasses) getClasses(classes) return null } Comp.displayName = options.name From 62252f12ccf9afe99489a6b7617fdf3c98812604 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 5 Jun 2019 22:15:08 +0200 Subject: [PATCH 42/52] refactor theming tests --- .../test-utils/createThemingTests.js | 402 +++++++++++++++++ packages/react-jss/tests/theming.js | 415 +----------------- 2 files changed, 423 insertions(+), 394 deletions(-) create mode 100644 packages/react-jss/test-utils/createThemingTests.js diff --git a/packages/react-jss/test-utils/createThemingTests.js b/packages/react-jss/test-utils/createThemingTests.js new file mode 100644 index 000000000..b457b0542 --- /dev/null +++ b/packages/react-jss/test-utils/createThemingTests.js @@ -0,0 +1,402 @@ +/* eslint-disable global-require, react/prop-types */ + +import expect from 'expect.js' +import React from 'react' +import TestRenderer from 'react-test-renderer' + +import {createTheming, ThemeProvider, JssProvider, SheetsRegistry} from '../src' + +export default ({createStyledComponent}) => { + const themedStaticStyles = theme => ({ + rule: { + color: theme.color + } + }) + const themedDynamicStyles = theme => ({ + rule: { + color: theme.color, + backgroundColor: props => props.backgroundColor + } + }) + const ThemeA = {color: '#aaa'} + const ThemeB = {color: '#bbb'} + + const ThemedStaticComponent = createStyledComponent(themedStaticStyles) + const ThemedDynamicComponent = createStyledComponent(themedDynamicStyles) + + describe('injecting the theme', () => { + let injectedTheme + const defaultProps = { + getTheme: theme => { + injectedTheme = theme + } + } + + it('should not inject theme with static classes', () => { + const StyledComponent = createStyledComponent({}) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(injectedTheme).to.be(undefined) + }) + + it('should not inject theme with themed classes', () => { + const StyledComponent = createStyledComponent(() => ({})) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(injectedTheme).to.be(undefined) + }) + + it('should inject theme with static classes and injectTheme option', () => { + const StyledComponent = createStyledComponent({}, {injectTheme: true}) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(injectedTheme).to.equal(ThemeA) + }) + + it('should inject theme with themed classes and injectTheme option', () => { + const StyledComponent = createStyledComponent(() => ({}), {injectTheme: true}) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(injectedTheme).to.equal(ThemeA) + }) + + it('should use the passed theme instead of the actual theme', () => { + const StyledComponent = createStyledComponent(() => ({}), {injectTheme: true}) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(injectedTheme).to.equal(ThemeB) + }) + }) + + it('should have correct meta attribute for themed styles', () => { + let sheet + const generateId = (rule, s) => { + sheet = s + return rule.key + } + TestRenderer.create( + + + + + + ) + + expect(sheet.options.meta.includes('Themed')).to.be(true) + }) + + it('one themed instance wo/ dynamic props = 1 style', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + ) + expect(registry.registry.length).to.equal(1) + }) + + it('one themed instance w/ dynamic props = 2 styles', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('one themed instance wo/ = 1 style, theme update = 1 style', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + ) + + expect(registry.registry[0].attached).to.be(false) + expect(registry.registry.length).to.equal(2) + }) + + it('one themed instance w/ dynamic props = 2 styles, theme update = 2 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + ) + + expect(registry.registry[0].attached).to.be(false) + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances wo/ dynamic props w/ same theme = 1 style', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('two themed instances w/ dynamic props w/ same theme = 3 styles', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('two themed instances w/ dynamic props w/ same theme = 3 styles, theme update = 3 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + + ) + + expect(registry.registry[0].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances wo/ dynamic props w/ same theme = 1 styles, different theme update = 2 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances w/ dynamic props w/ same theme = 3 styles, different theme update = 4 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances wo/ dynamic props w/ different themes = 2 styles, same theme update = 1 style', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry[1].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances w/ dynamic props w/ different themes = 4 styles, same theme update = 3 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry[1].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) + }) + + describe('when theming object returned from createTheming is provided to injectSheet options', () => { + it('allows nested ThemeProviders with custom namespace', () => { + const themingA = createTheming(React.createContext()) + const themingB = createTheming(React.createContext()) + const {ThemeProvider: ThemeProviderA} = themingA + const {ThemeProvider: ThemeProviderB} = themingB + + let colorReceivedInStyleA + let colorReceivedInStyleB + let themeReceivedInComponentA + let themeReceivedInComponentB + + const styleA = theme => { + colorReceivedInStyleA = theme.color + } + const styleB = theme => { + colorReceivedInStyleB = theme.color + } + + const ComponentA = createStyledComponent(styleA, {theming: themingA, injectTheme: true}) + ComponentA.defaultProps = { + getTheme: theme => { + themeReceivedInComponentA = theme + } + } + const ComponentB = createStyledComponent(styleB, {theming: themingB, injectTheme: true}) + ComponentB.defaultProps = { + getTheme: theme => { + themeReceivedInComponentB = theme + } + } + + TestRenderer.create( + + +
+ + +
+
+
+ ) + + expect(themeReceivedInComponentA).to.eql(ThemeA) + expect(themeReceivedInComponentB).to.eql(ThemeB) + expect(colorReceivedInStyleA).to.eql(ThemeA.color) + expect(colorReceivedInStyleB).to.eql(ThemeB.color) + }) + }) +} diff --git a/packages/react-jss/tests/theming.js b/packages/react-jss/tests/theming.js index 8619cc597..aa6c7b375 100644 --- a/packages/react-jss/tests/theming.js +++ b/packages/react-jss/tests/theming.js @@ -1,406 +1,33 @@ -/* eslint-disable global-require, react/prop-types */ +/* eslint-disable react/prop-types */ -import expect from 'expect.js' -import React from 'react' -import TestRenderer from 'react-test-renderer' - -import injectSheet, {createTheming, ThemeProvider, JssProvider, SheetsRegistry} from '../src' +import {createUseStyles, withStyles} from '../src' +import createThemingTests from '../test-utils/createThemingTests' describe('React-JSS: theming', () => { - const themedStaticStyles = theme => ({ - rule: { - color: theme.color - } - }) - const themedDynamicStyles = theme => ({ - rule: { - color: theme.color, - backgroundColor: props => props.backgroundColor - } - }) - const ThemeA = {color: '#aaa'} - const ThemeB = {color: '#bbb'} - - const ThemedStaticComponent = injectSheet(themedStaticStyles)() - const ThemedDynamicComponent = injectSheet(themedDynamicStyles)() - - describe('injecting the theme', () => { - const Comp = () => null - - it('should not inject theme with static classes', () => { - const StyledComponent = injectSheet({})(Comp) - const renderer = TestRenderer.create( - - - - ) - const injectedTheme = renderer.root.findByType(Comp).props.theme - - expect(injectedTheme).to.be(undefined) - }) - - it('should not inject theme with themed classes', () => { - const StyledComponent = injectSheet(() => ({}))(Comp) - const renderer = TestRenderer.create( - - - - ) - const injectedTheme = renderer.root.findByType(Comp).props.theme - - expect(injectedTheme).to.be(undefined) - }) - - it('should inject theme with static classes and injectTheme option', () => { - const StyledComponent = injectSheet({}, {injectTheme: true})(Comp) - const renderer = TestRenderer.create( - - - - ) - const injectedTheme = renderer.root.findByType(Comp).props.theme - - expect(injectedTheme).to.equal(ThemeA) - }) - - it('should inject theme with themed classes and injectTheme option', () => { - const StyledComponent = injectSheet(() => ({}), {injectTheme: true})(Comp) - const renderer = TestRenderer.create( - - - - ) - const injectedTheme = renderer.root.findByType(Comp).props.theme - - expect(injectedTheme).to.equal(ThemeA) - }) - - it('should use the passed theme instead of the actual theme', () => { - const StyledComponent = injectSheet(() => ({}), {injectTheme: true})(Comp) - const renderer = TestRenderer.create( - - - - ) - const injectedTheme = renderer.root.findByType(Comp).props.theme - - expect(injectedTheme).to.equal(ThemeB) - }) - }) - - it('should have correct meta attribute for themed styles', () => { - let sheet - const generateId = (rule, s) => { - sheet = s - return rule.key + describe.skip('using createUseStyles', () => { + const createStyledComponent = (styles, options = {}) => { + const useStyles = createUseStyles(styles, options) + const Comp = props => { + const {theme} = useStyles(props) + if (props.getTheme) props.getTheme(theme) + return null + } + Comp.displayName = options.name + return Comp } - TestRenderer.create( - - - - - - ) - - expect(sheet.options.meta.includes('Themed')).to.be(true) - }) - - it('one themed instance wo/ dynamic props = 1 style', () => { - const registry = new SheetsRegistry() - TestRenderer.create( - - - - - - ) - expect(registry.registry.length).to.equal(1) - }) - - it('one themed instance w/ dynamic props = 2 styles', () => { - const registry = new SheetsRegistry() - TestRenderer.create( - - - - - - ) - - expect(registry.registry.length).to.equal(1) - }) - - it('one themed instance wo/ = 1 style, theme update = 1 style', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - ) - - expect(registry.registry.length).to.equal(1) - - renderer.update( - - - - - - ) - - expect(registry.registry[0].attached).to.be(false) - expect(registry.registry.length).to.equal(2) - }) - - it('one themed instance w/ dynamic props = 2 styles, theme update = 2 styles', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - ) - - expect(registry.registry.length).to.equal(1) - - renderer.update( - - - - - - ) - - expect(registry.registry[0].attached).to.be(false) - expect(registry.registry.length).to.equal(2) - }) - - it('two themed instances wo/ dynamic props w/ same theme = 1 style', () => { - const registry = new SheetsRegistry() - TestRenderer.create( - - - - - - - ) - expect(registry.registry.length).to.equal(1) + createThemingTests({createStyledComponent}) }) - it('two themed instances w/ dynamic props w/ same theme = 3 styles', () => { - const registry = new SheetsRegistry() - TestRenderer.create( - - - - - - - ) - - expect(registry.registry.length).to.equal(1) - }) - - it('two themed instances w/ dynamic props w/ same theme = 3 styles, theme update = 3 styles', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - - ) - - expect(registry.registry.length).to.equal(1) - - renderer.update( - - - - - - - ) - - expect(registry.registry[0].attached).to.equal(false) - expect(registry.registry.length).to.equal(2) - }) - - it('two themed instances wo/ dynamic props w/ same theme = 1 styles, different theme update = 2 styles', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - - - - ) - - expect(registry.registry.length).to.equal(1) - - renderer.update( - - - - - - - - - ) - - expect(registry.registry.length).to.equal(2) - }) - - it('two themed instances w/ dynamic props w/ same theme = 3 styles, different theme update = 4 styles', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - - - - ) - - expect(registry.registry.length).to.equal(1) - - renderer.update( - - - - - - - - - ) - - expect(registry.registry.length).to.equal(2) - }) - - it('two themed instances wo/ dynamic props w/ different themes = 2 styles, same theme update = 1 style', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - - - - ) - - expect(registry.registry.length).to.equal(2) - - renderer.update( - - - - - - - - - ) - - expect(registry.registry[1].attached).to.equal(false) - expect(registry.registry.length).to.equal(2) - }) - - it('two themed instances w/ dynamic props w/ different themes = 4 styles, same theme update = 3 styles', () => { - const registry = new SheetsRegistry() - const renderer = TestRenderer.create( - - - - - - - - - ) - - expect(registry.registry.length).to.equal(2) - - renderer.update( - - - - - - - - - ) - - expect(registry.registry[1].attached).to.equal(false) - expect(registry.registry.length).to.equal(2) - }) - - describe('when theming object returned from createTheming is provided to injectSheet options', () => { - it('allows nested ThemeProviders with custom namespace', () => { - const themingA = createTheming(React.createContext()) - const themingB = createTheming(React.createContext()) - const {ThemeProvider: ThemeProviderA} = themingA - const {ThemeProvider: ThemeProviderB} = themingB - - let colorReceivedInStyleA - let colorReceivedInStyleB - let themeReceivedInComponentA - let themeReceivedInComponentB - - const styleA = theme => { - colorReceivedInStyleA = theme.color - } - const styleB = theme => { - colorReceivedInStyleB = theme.color - } - - const InnerComponentA = ({theme}) => { - themeReceivedInComponentA = theme + describe('using withStyles', () => { + const createStyledComponent = (styles, options = {}) => { + const Comp = ({getTheme, theme}) => { + if (getTheme) getTheme(theme) return null } + return withStyles(styles, options)(Comp) + } - const InnerComponentB = ({theme}) => { - themeReceivedInComponentB = theme - return null - } - - const ComponentA = injectSheet(styleA, {theming: themingA, injectTheme: true})( - InnerComponentA - ) - const ComponentB = injectSheet(styleB, {theming: themingB, injectTheme: true})( - InnerComponentB - ) - - TestRenderer.create( - - -
- - -
-
-
- ) - - expect(themeReceivedInComponentA).to.eql(ThemeA) - expect(themeReceivedInComponentB).to.eql(ThemeB) - expect(colorReceivedInStyleA).to.eql(ThemeA.color) - expect(colorReceivedInStyleB).to.eql(ThemeB.color) - }) + createThemingTests({createStyledComponent}) }) }) From 73964b6b88c297164dadde9fd5f2f76f4d159c4d Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Thu, 6 Jun 2019 21:12:55 +0200 Subject: [PATCH 43/52] Rewrite to useReducer --- packages/react-jss/.size-snapshot.json | 24 +++--- packages/react-jss/src/createUseStyles.js | 97 ++++++++++++----------- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index d8b415844..4a07e3a05 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 127825, - "minified": 43890, - "gzipped": 13755 + "bundled": 127727, + "minified": 44060, + "gzipped": 13778 }, "dist/react-jss.min.js": { - "bundled": 95438, - "minified": 33998, - "gzipped": 10967 + "bundled": 95340, + "minified": 34168, + "gzipped": 10984 }, "dist/react-jss.cjs.js": { - "bundled": 20366, - "minified": 9353, - "gzipped": 3036 + "bundled": 20270, + "minified": 9497, + "gzipped": 3066 }, "dist/react-jss.esm.js": { - "bundled": 19524, - "minified": 8619, - "gzipped": 2916, + "bundled": 19446, + "minified": 8781, + "gzipped": 2951, "treeshaked": { "rollup": { "code": 2016, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index f2e0b43bb..184f9cf9c 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -35,72 +35,72 @@ const createUseStyles = (styles: Styles, options?: HookOptions const context = React.useContext(JssContext) const theme = useTheme() - const [staticSheet, setStaticSheet] = React.useState(() => { - const sheet = createStaticSheet({ - context, - styles, - name, - theme, - index, - sheetOptions - }) - - if (context.registry && sheet) { - context.registry.add(sheet) - } - - return sheet - }) + const [state, dispatch] = React.useReducer( + (prevState, action) => { + if (action.type === 'updateSheet') { + return action.payload + } - const [dynamicRules, setDynamicRules] = React.useState(() => { - if (staticSheet) { - return addDynamicRules(staticSheet, data) - } + return prevState + }, + null, + () => { + const sheet = createStaticSheet({ + context, + styles, + name, + theme, + index, + sheetOptions + }) + + if (context.registry && sheet) { + context.registry.add(sheet) + } - return undefined - }) + const dynamicRules = sheet && addDynamicRules(sheet, data) - const [classes, setClasses] = React.useState(() => { - if (staticSheet) { - return getSheetClasses(staticSheet, dynamicRules) + return { + sheet, + dynamicRules, + classes: sheet ? getSheetClasses(sheet, dynamicRules) : {} + } } - - return {} - }) + ) useEffectOrLayoutEffect( () => { - if (staticSheet) { + if (state.sheet) { manageSheet({ index, context, - sheet: staticSheet, + sheet: state.sheet, theme }) } return () => { - if (staticSheet) { + if (state.sheet) { unmanageSheet({ index, context, - sheet: staticSheet, + sheet: state.sheet, theme }) - if (dynamicRules) { - removeDynamicRules(staticSheet, dynamicRules) + if (state.dynamicRules && state.sheet) { + removeDynamicRules(state.sheet, state.dynamicRules) } } } }, - [staticSheet] + [state.sheet] ) useEffectOrLayoutEffect( () => { - if (dynamicRules && staticSheet) { - updateDynamicRules(data, staticSheet, dynamicRules) + if (state.sheet && state.dynamicRules) { + updateDynamicRules(data, state.sheet, state.dynamicRules) } }, [data] @@ -109,7 +109,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions useEffectOrLayoutEffect( () => { if (!isFirstMount.current) { - const newStaticSheet = createStaticSheet({ + const newSheet = createStaticSheet({ context, styles, name, @@ -117,19 +117,24 @@ const createUseStyles = (styles: Styles, options?: HookOptions index, sheetOptions }) - const newDynamicRules = staticSheet ? addDynamicRules(staticSheet, data) : undefined - const newClasses = staticSheet ? getSheetClasses(staticSheet, dynamicRules) : undefined - - setStaticSheet(newStaticSheet) - setDynamicRules(newDynamicRules) - setClasses(newClasses) + const newDynamicRules = newSheet && addDynamicRules(newSheet, data) + const newClasses = newSheet ? getSheetClasses(newSheet, newDynamicRules) : {} + + dispatch({ + type: 'updateSheet', + payload: { + sheet: newSheet, + dynamicRules: newDynamicRules, + classes: newClasses + } + }) } }, [theme, context] ) // $FlowFixMe - React.useDebugValue(classes) + React.useDebugValue(state.classes) // $FlowFixMe React.useDebugValue(theme === noTheme ? 'No theme' : theme) @@ -137,7 +142,7 @@ const createUseStyles = (styles: Styles, options?: HookOptions isFirstMount.current = false }) - return classes + return state.classes } } From 3dc8d2ed44d46b66306770ddc7dc41d117095659 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Thu, 6 Jun 2019 21:49:23 +0200 Subject: [PATCH 44/52] Fix JssProvider --- packages/react-jss/.size-snapshot.json | 28 +++--- packages/react-jss/src/JssProvider.js | 90 ++++++++++--------- packages/react-jss/src/utils/shallow-equal.js | 29 ++++++ 3 files changed, 91 insertions(+), 56 deletions(-) create mode 100644 packages/react-jss/src/utils/shallow-equal.js diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index 4a07e3a05..73eb697ca 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "dist/react-jss.js": { - "bundled": 127727, - "minified": 44060, - "gzipped": 13778 + "bundled": 128456, + "minified": 44338, + "gzipped": 13862 }, "dist/react-jss.min.js": { - "bundled": 95340, - "minified": 34168, - "gzipped": 10984 + "bundled": 96069, + "minified": 34446, + "gzipped": 11069 }, "dist/react-jss.cjs.js": { - "bundled": 20270, - "minified": 9497, - "gzipped": 3066 + "bundled": 20945, + "minified": 9804, + "gzipped": 3177 }, "dist/react-jss.esm.js": { - "bundled": 19446, - "minified": 8781, - "gzipped": 2951, + "bundled": 20121, + "minified": 9088, + "gzipped": 3060, "treeshaked": { "rollup": { - "code": 2016, + "code": 2040, "import_statements": 439 }, "webpack": { - "code": 3446 + "code": 3470 } } } diff --git a/packages/react-jss/src/JssProvider.js b/packages/react-jss/src/JssProvider.js index ae7bf526c..7a2cd310f 100644 --- a/packages/react-jss/src/JssProvider.js +++ b/packages/react-jss/src/JssProvider.js @@ -10,7 +10,7 @@ import defaultJss, { } from 'jss' import type {Context, Managers} from './types' import JssContext from './JssContext' -import memoize from './utils/memoizeOne' +import shallowEqualObjects from './utils/shallow-equal' /* eslint-disable react/require-default-props, react/no-unused-prop-types */ @@ -41,55 +41,62 @@ export default class JssProvider extends Component { managers: Managers = {} - createContext = memoize( - (outerContext: Context, props: Props): Context => { - const {registry, classNamePrefix, jss, generateId, disableStylesGeneration, media} = props - // Clone the outer context - const context = {...outerContext} - - if (registry) { - context.registry = 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 - } - } + createContext = (outerContext: Context) => { + const {registry, classNamePrefix, jss, generateId, disableStylesGeneration, media} = this.props - context.managers = this.managers + // Clone the outer context + const context = {...outerContext} - if (generateId) { - context.sheetOptions.generateId = generateId - } else if (!context.sheetOptions.generateId) { - if (!this.generateId) { - this.generateId = createGenerateId(this.props.id) - } - context.sheetOptions.generateId = this.generateId - } + if (registry) { + context.registry = registry - // Merge the classname prefix - if (classNamePrefix) { - context.sheetOptions.classNamePrefix += classNamePrefix + // 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 } + } - if (media !== undefined) { - context.sheetOptions.media = media - } + context.managers = this.managers - if (jss) { - context.jss = jss + if (generateId) { + context.sheetOptions.generateId = generateId + } else if (!context.sheetOptions.generateId) { + if (!this.generateId) { + this.generateId = createGenerateId(this.props.id) } + context.sheetOptions.generateId = this.generateId + } - if (disableStylesGeneration !== undefined) { - context.disableStylesGeneration = disableStylesGeneration - } + // Merge the classname prefix + if (classNamePrefix) { + context.sheetOptions.classNamePrefix += classNamePrefix + } + + if (media !== undefined) { + context.sheetOptions.media = media + } - return context + if (jss) { + context.jss = jss } - ) + + if (disableStylesGeneration !== undefined) { + context.disableStylesGeneration = disableStylesGeneration + } + + if (this.prevContext && shallowEqualObjects(this.prevContext, context)) { + return this.prevContext + } + + this.prevContext = context + + return context + } + + prevContext: Context generateId: ?GenerateId @@ -97,8 +104,7 @@ export default class JssProvider extends Component { renderProvider = (outerContext: Context) => { const {children} = this.props - // $FlowFixMe - const context: Context = this.createContext(outerContext, this.props) + const context: Context = this.createContext(outerContext) return {children} } diff --git a/packages/react-jss/src/utils/shallow-equal.js b/packages/react-jss/src/utils/shallow-equal.js new file mode 100644 index 000000000..88bc0c9f7 --- /dev/null +++ b/packages/react-jss/src/utils/shallow-equal.js @@ -0,0 +1,29 @@ +const shallowEqualObjects = (objA, objB) => { + if (objA === objB) { + return true + } + + if (!objA || !objB) { + return false + } + + const aKeys = Object.keys(objA) + const bKeys = Object.keys(objB) + const len = aKeys.length + + if (bKeys.length !== len) { + return false + } + + for (let i = 0; i < len; i++) { + const key = aKeys[i] + + if (objA[key] !== objB[key]) { + return false + } + } + + return true +} + +export default shallowEqualObjects From e46bde61eac03ae82ff4ed0093c187d605e7f132 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 6 Jun 2019 22:58:02 +0200 Subject: [PATCH 45/52] port theming tests for hooks --- packages/react-jss/.size-snapshot.json | 24 +- packages/react-jss/src/index.js | 3 +- packages/react-jss/src/index.test.js | 7 +- packages/react-jss/tests/theming.js | 33 -- packages/react-jss/tests/useStylesTheming.js | 414 ++++++++++++++++++ .../withStylesTheming.js} | 164 +++---- 6 files changed, 517 insertions(+), 128 deletions(-) delete mode 100644 packages/react-jss/tests/theming.js create mode 100644 packages/react-jss/tests/useStylesTheming.js rename packages/react-jss/{test-utils/createThemingTests.js => tests/withStylesTheming.js} (72%) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index d8b415844..ac46f3698 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 127825, - "minified": 43890, - "gzipped": 13755 + "bundled": 127898, + "minified": 43919, + "gzipped": 13762 }, "dist/react-jss.min.js": { - "bundled": 95438, - "minified": 33998, - "gzipped": 10967 + "bundled": 95511, + "minified": 34026, + "gzipped": 10981 }, "dist/react-jss.cjs.js": { - "bundled": 20366, - "minified": 9353, - "gzipped": 3036 + "bundled": 20403, + "minified": 9387, + "gzipped": 3044 }, "dist/react-jss.esm.js": { - "bundled": 19524, - "minified": 8619, - "gzipped": 2916, + "bundled": 19534, + "minified": 8628, + "gzipped": 2921, "treeshaked": { "rollup": { "code": 2016, diff --git a/packages/react-jss/src/index.js b/packages/react-jss/src/index.js index 4e411ce0e..62ee72721 100644 --- a/packages/react-jss/src/index.js +++ b/packages/react-jss/src/index.js @@ -1,13 +1,12 @@ // @flow import withStyles from './withStyles' +export {ThemeProvider, withTheme, createTheming, useTheme} from 'theming' export {default as createUseStyles} from './createUseStyles' -export {ThemeProvider, withTheme, createTheming} from 'theming' export {default as JssProvider} from './JssProvider' export {default as jss} from './jss' export {SheetsRegistry, createGenerateId} from 'jss' export {default as JssContext} from './JssContext' - export {withStyles} // Kept for backwards compatibility. diff --git a/packages/react-jss/src/index.test.js b/packages/react-jss/src/index.test.js index fe11f12f1..cd1acb01d 100644 --- a/packages/react-jss/src/index.test.js +++ b/packages/react-jss/src/index.test.js @@ -8,7 +8,8 @@ import { SheetsRegistry, withTheme, createTheming, - createUseStyles + createUseStyles, + useTheme } from '.' describe('React-JSS: exports', () => { @@ -47,4 +48,8 @@ describe('React-JSS: exports', () => { it('should export createUseStyles', () => { expect(createUseStyles).to.be.a(Function) }) + + it('should export useTheme', () => { + expect(useTheme).to.be.a(Function) + }) }) diff --git a/packages/react-jss/tests/theming.js b/packages/react-jss/tests/theming.js deleted file mode 100644 index aa6c7b375..000000000 --- a/packages/react-jss/tests/theming.js +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable react/prop-types */ - -import {createUseStyles, withStyles} from '../src' -import createThemingTests from '../test-utils/createThemingTests' - -describe('React-JSS: theming', () => { - describe.skip('using createUseStyles', () => { - const createStyledComponent = (styles, options = {}) => { - const useStyles = createUseStyles(styles, options) - const Comp = props => { - const {theme} = useStyles(props) - if (props.getTheme) props.getTheme(theme) - return null - } - Comp.displayName = options.name - return Comp - } - - createThemingTests({createStyledComponent}) - }) - - describe('using withStyles', () => { - const createStyledComponent = (styles, options = {}) => { - const Comp = ({getTheme, theme}) => { - if (getTheme) getTheme(theme) - return null - } - return withStyles(styles, options)(Comp) - } - - createThemingTests({createStyledComponent}) - }) -}) diff --git a/packages/react-jss/tests/useStylesTheming.js b/packages/react-jss/tests/useStylesTheming.js new file mode 100644 index 000000000..0f9b662de --- /dev/null +++ b/packages/react-jss/tests/useStylesTheming.js @@ -0,0 +1,414 @@ +/* eslint-disable react/prop-types */ + +import expect from 'expect.js' +import React from 'react' +import TestRenderer from 'react-test-renderer' + +import { + createUseStyles, + useTheme, + createTheming, + ThemeProvider, + JssProvider, + SheetsRegistry +} from '../src' + +const createStyledComponent = (styles, options = {}) => { + const useStyles = createUseStyles(styles, options) + const Comp = props => { + useStyles(props) + + const theme = props.theme || (options.theming ? options.theming.useTheme() : useTheme()) + if (props.getTheme) props.getTheme(theme) + return null + } + Comp.displayName = options.name + return Comp +} + +describe('React-JSS: theming useStyles()', () => { + const themedStaticStyles = theme => ({ + rule: { + color: theme.color + } + }) + const themedDynamicStyles = theme => ({ + rule: { + color: theme.color, + backgroundColor: props => props.backgroundColor + } + }) + const themeA = {color: '#aaa'} + const themeB = {color: '#bbb'} + + const ThemedStaticComponent = createStyledComponent(themedStaticStyles) + const ThemedDynamicComponent = createStyledComponent(themedDynamicStyles) + + describe('injecting the theme', () => { + let themeFromUseTheme + let themeFromStylesFn + + const defaultProps = { + getTheme: theme => { + themeFromUseTheme = theme + } + } + + beforeEach(() => { + themeFromUseTheme = {} + themeFromStylesFn = {} + }) + + it('should subscribe theme with useTheme, but not with useStyles', () => { + const StyledComponent = createStyledComponent({}) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(themeFromUseTheme).to.be(themeA) + expect(themeFromStylesFn).to.eql({}) + }) + + it('should warn when styles function has no arguments', () => {}) + + it('should subscribe theme with useTheme and with useStyles', () => { + const StyledComponent = createStyledComponent(theme => { + themeFromStylesFn = theme + return {} + }) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(themeFromUseTheme).to.be(themeA) + expect(themeFromStylesFn).to.eql(themeA) + }) + + it('should use the theme from props instead of the one from provider', () => { + const StyledComponent = createStyledComponent({}) + StyledComponent.defaultProps = defaultProps + TestRenderer.create( + + + + ) + expect(themeFromUseTheme).to.equal(themeB) + }) + }) + + it('should have correct meta attribute for themed styles', () => { + let sheet + const generateId = (rule, s) => { + sheet = s + return rule.key + } + TestRenderer.create( + + + + + + ) + + expect(sheet.options.meta.includes('Themed')).to.be(true) + }) + + it('one themed instance wo/ dynamic props = 1 style', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + ) + expect(registry.registry.length).to.equal(1) + }) + + it('one themed instance w/ dynamic props = 2 styles', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('one themed instance wo/ = 1 style, theme update = 1 style', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + ) + + expect(registry.registry[0].attached).to.be(false) + expect(registry.registry.length).to.equal(2) + }) + + it('one themed instance w/ dynamic props = 2 styles, theme update = 2 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + ) + + expect(registry.registry[0].attached).to.be(false) + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances wo/ dynamic props w/ same theme = 1 style', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('two themed instances w/ dynamic props w/ same theme = 3 styles', () => { + const registry = new SheetsRegistry() + TestRenderer.create( + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + }) + + it('two themed instances w/ dynamic props w/ same theme = 3 styles, theme update = 3 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + + ) + + expect(registry.registry[0].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances wo/ dynamic props w/ same theme = 1 styles, different theme update = 2 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances w/ dynamic props w/ same theme = 3 styles, different theme update = 4 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(1) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances wo/ dynamic props w/ different themes = 2 styles, same theme update = 1 style', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry[1].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) + }) + + it('two themed instances w/ dynamic props w/ different themes = 4 styles, same theme update = 3 styles', () => { + const registry = new SheetsRegistry() + const renderer = TestRenderer.create( + + + + + + + + + ) + + expect(registry.registry.length).to.equal(2) + + renderer.update( + + + + + + + + + ) + + expect(registry.registry[1].attached).to.equal(false) + expect(registry.registry.length).to.equal(2) + }) + + describe('when theming object returned from createTheming is provided to injectSheet options', () => { + it('allows nested ThemeProviders with custom namespace', () => { + const themingA = createTheming(React.createContext()) + const themingB = createTheming(React.createContext()) + const {ThemeProvider: ThemeProviderA} = themingA + const {ThemeProvider: ThemeProviderB} = themingB + + let colorReceivedInStylesA + let colorReceivedInStylesB + let themeReceivedInComponentA + let themeReceivedInComponentB + + const stylesA = theme => { + colorReceivedInStylesA = theme.color + } + const stylesB = theme => { + colorReceivedInStylesB = theme.color + } + + const ComponentA = createStyledComponent(stylesA, {theming: themingA}) + ComponentA.defaultProps = { + getTheme: theme => { + themeReceivedInComponentA = theme + } + } + const ComponentB = createStyledComponent(stylesB, {theming: themingB}) + ComponentB.defaultProps = { + getTheme: theme => { + themeReceivedInComponentB = theme + } + } + + TestRenderer.create( + + +
+ + +
+
+
+ ) + + expect(themeReceivedInComponentA).to.eql(themeA) + expect(themeReceivedInComponentB).to.eql(themeB) + expect(colorReceivedInStylesA).to.eql(themeA.color) + expect(colorReceivedInStylesB).to.eql(themeB.color) + }) + }) +}) diff --git a/packages/react-jss/test-utils/createThemingTests.js b/packages/react-jss/tests/withStylesTheming.js similarity index 72% rename from packages/react-jss/test-utils/createThemingTests.js rename to packages/react-jss/tests/withStylesTheming.js index b457b0542..d074d4467 100644 --- a/packages/react-jss/test-utils/createThemingTests.js +++ b/packages/react-jss/tests/withStylesTheming.js @@ -4,9 +4,9 @@ import expect from 'expect.js' import React from 'react' import TestRenderer from 'react-test-renderer' -import {createTheming, ThemeProvider, JssProvider, SheetsRegistry} from '../src' +import injectSheet, {createTheming, ThemeProvider, JssProvider, SheetsRegistry} from '../src' -export default ({createStyledComponent}) => { +describe('React-JSS: theming withStyles()', () => { const themedStaticStyles = theme => ({ rule: { color: theme.color @@ -18,73 +18,73 @@ export default ({createStyledComponent}) => { backgroundColor: props => props.backgroundColor } }) - const ThemeA = {color: '#aaa'} - const ThemeB = {color: '#bbb'} + const themeA = {color: '#aaa'} + const themeB = {color: '#bbb'} - const ThemedStaticComponent = createStyledComponent(themedStaticStyles) - const ThemedDynamicComponent = createStyledComponent(themedDynamicStyles) + const ThemedStaticComponent = injectSheet(themedStaticStyles)() + const ThemedDynamicComponent = injectSheet(themedDynamicStyles)() describe('injecting the theme', () => { - let injectedTheme - const defaultProps = { - getTheme: theme => { - injectedTheme = theme - } - } + const Comp = () => null it('should not inject theme with static classes', () => { - const StyledComponent = createStyledComponent({}) - StyledComponent.defaultProps = defaultProps - TestRenderer.create( - + const StyledComponent = injectSheet({})(Comp) + const renderer = TestRenderer.create( + ) + const injectedTheme = renderer.root.findByType(Comp).props.theme + expect(injectedTheme).to.be(undefined) }) it('should not inject theme with themed classes', () => { - const StyledComponent = createStyledComponent(() => ({})) - StyledComponent.defaultProps = defaultProps - TestRenderer.create( - + const StyledComponent = injectSheet(() => ({}))(Comp) + const renderer = TestRenderer.create( + ) + const injectedTheme = renderer.root.findByType(Comp).props.theme + expect(injectedTheme).to.be(undefined) }) it('should inject theme with static classes and injectTheme option', () => { - const StyledComponent = createStyledComponent({}, {injectTheme: true}) - StyledComponent.defaultProps = defaultProps - TestRenderer.create( - + const StyledComponent = injectSheet({}, {injectTheme: true})(Comp) + const renderer = TestRenderer.create( + ) - expect(injectedTheme).to.equal(ThemeA) + const injectedTheme = renderer.root.findByType(Comp).props.theme + + expect(injectedTheme).to.equal(themeA) }) it('should inject theme with themed classes and injectTheme option', () => { - const StyledComponent = createStyledComponent(() => ({}), {injectTheme: true}) - StyledComponent.defaultProps = defaultProps - TestRenderer.create( - + const StyledComponent = injectSheet(() => ({}), {injectTheme: true})(Comp) + const renderer = TestRenderer.create( + ) - expect(injectedTheme).to.equal(ThemeA) + const injectedTheme = renderer.root.findByType(Comp).props.theme + + expect(injectedTheme).to.equal(themeA) }) it('should use the passed theme instead of the actual theme', () => { - const StyledComponent = createStyledComponent(() => ({}), {injectTheme: true}) - StyledComponent.defaultProps = defaultProps - TestRenderer.create( - - + const StyledComponent = injectSheet(() => ({}), {injectTheme: true})(Comp) + const renderer = TestRenderer.create( + + ) - expect(injectedTheme).to.equal(ThemeB) + const injectedTheme = renderer.root.findByType(Comp).props.theme + + expect(injectedTheme).to.equal(themeB) }) }) @@ -96,7 +96,7 @@ export default ({createStyledComponent}) => { } TestRenderer.create( - + @@ -109,7 +109,7 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() TestRenderer.create( - + @@ -121,7 +121,7 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() TestRenderer.create( - + @@ -133,7 +133,7 @@ export default ({createStyledComponent}) => { it('one themed instance wo/ = 1 style, theme update = 1 style', () => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + @@ -143,7 +143,7 @@ export default ({createStyledComponent}) => { expect(registry.registry.length).to.equal(1) renderer.update( - + @@ -157,7 +157,7 @@ export default ({createStyledComponent}) => { it('one themed instance w/ dynamic props = 2 styles, theme update = 2 styles', () => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + @@ -167,7 +167,7 @@ export default ({createStyledComponent}) => { expect(registry.registry.length).to.equal(1) renderer.update( - + @@ -182,7 +182,7 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() TestRenderer.create( - + @@ -196,7 +196,7 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() TestRenderer.create( - + @@ -209,7 +209,7 @@ export default ({createStyledComponent}) => { it('two themed instances w/ dynamic props w/ same theme = 3 styles, theme update = 3 styles', () => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + @@ -220,7 +220,7 @@ export default ({createStyledComponent}) => { expect(registry.registry.length).to.equal(1) renderer.update( - + @@ -236,10 +236,10 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + - + @@ -249,10 +249,10 @@ export default ({createStyledComponent}) => { renderer.update( - + - + @@ -265,10 +265,10 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + - + @@ -278,10 +278,10 @@ export default ({createStyledComponent}) => { renderer.update( - + - + @@ -294,10 +294,10 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + - + @@ -307,10 +307,10 @@ export default ({createStyledComponent}) => { renderer.update( - + - + @@ -324,10 +324,10 @@ export default ({createStyledComponent}) => { const registry = new SheetsRegistry() const renderer = TestRenderer.create( - + - + @@ -337,10 +337,10 @@ export default ({createStyledComponent}) => { renderer.update( - + - + @@ -369,22 +369,26 @@ export default ({createStyledComponent}) => { colorReceivedInStyleB = theme.color } - const ComponentA = createStyledComponent(styleA, {theming: themingA, injectTheme: true}) - ComponentA.defaultProps = { - getTheme: theme => { - themeReceivedInComponentA = theme - } + const InnerComponentA = ({theme}) => { + themeReceivedInComponentA = theme + return null } - const ComponentB = createStyledComponent(styleB, {theming: themingB, injectTheme: true}) - ComponentB.defaultProps = { - getTheme: theme => { - themeReceivedInComponentB = theme - } + + const InnerComponentB = ({theme}) => { + themeReceivedInComponentB = theme + return null } + const ComponentA = injectSheet(styleA, {theming: themingA, injectTheme: true})( + InnerComponentA + ) + const ComponentB = injectSheet(styleB, {theming: themingB, injectTheme: true})( + InnerComponentB + ) + TestRenderer.create( - - + +
@@ -393,10 +397,10 @@ export default ({createStyledComponent}) => { ) - expect(themeReceivedInComponentA).to.eql(ThemeA) - expect(themeReceivedInComponentB).to.eql(ThemeB) - expect(colorReceivedInStyleA).to.eql(ThemeA.color) - expect(colorReceivedInStyleB).to.eql(ThemeB.color) + expect(themeReceivedInComponentA).to.eql(themeA) + expect(themeReceivedInComponentB).to.eql(themeB) + expect(colorReceivedInStyleA).to.eql(themeA.color) + expect(colorReceivedInStyleB).to.eql(themeB.color) }) }) -} +}) From 76d096471ed153629253db7d0b226574393ef0b5 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 6 Jun 2019 23:18:24 +0200 Subject: [PATCH 46/52] move reducer to the module scope, since it doesn't need to be recreated --- packages/react-jss/.size-snapshot.json | 24 +++++----- packages/react-jss/src/createUseStyles.js | 55 +++++++++++------------ 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index fe51a4b30..caf4f548c 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,23 +1,23 @@ { "dist/react-jss.js": { - "bundled": 128529, - "minified": 44367, - "gzipped": 13869 + "bundled": 128542, + "minified": 44373, + "gzipped": 13874 }, "dist/react-jss.min.js": { - "bundled": 96142, - "minified": 34474, - "gzipped": 11084 + "bundled": 96155, + "minified": 34480, + "gzipped": 11091 }, "dist/react-jss.cjs.js": { - "bundled": 20982, - "minified": 9838, - "gzipped": 3185 + "bundled": 20993, + "minified": 9854, + "gzipped": 3193 }, "dist/react-jss.esm.js": { - "bundled": 20131, - "minified": 9097, - "gzipped": 3064, + "bundled": 20142, + "minified": 9113, + "gzipped": 3072, "treeshaked": { "rollup": { "code": 2040, diff --git a/packages/react-jss/src/createUseStyles.js b/packages/react-jss/src/createUseStyles.js index 184f9cf9c..62e9f9cbe 100644 --- a/packages/react-jss/src/createUseStyles.js +++ b/packages/react-jss/src/createUseStyles.js @@ -20,6 +20,13 @@ const useEffectOrLayoutEffect = isInBrowser ? React.useLayoutEffect : React.useE const noTheme = {} +const reducer = (prevState, action) => { + if (action.type === 'updateSheet') { + return action.payload + } + return prevState +} + const createUseStyles = (styles: Styles, options?: HookOptions = {}) => { const {index = getSheetIndex(), theming, name = 'Hook', ...sheetOptions} = options const ThemeContext = (theming && theming.context) || DefaultThemeContext @@ -35,38 +42,28 @@ const createUseStyles = (styles: Styles, options?: HookOptions const context = React.useContext(JssContext) const theme = useTheme() - const [state, dispatch] = React.useReducer( - (prevState, action) => { - if (action.type === 'updateSheet') { - return action.payload - } - - return prevState - }, - null, - () => { - const sheet = createStaticSheet({ - context, - styles, - name, - theme, - index, - sheetOptions - }) - - if (context.registry && sheet) { - context.registry.add(sheet) - } + const [state, dispatch] = React.useReducer(reducer, null, () => { + const sheet = createStaticSheet({ + context, + styles, + name, + theme, + index, + sheetOptions + }) + + if (context.registry && sheet) { + context.registry.add(sheet) + } - const dynamicRules = sheet && addDynamicRules(sheet, data) + const dynamicRules = sheet && addDynamicRules(sheet, data) - return { - sheet, - dynamicRules, - classes: sheet ? getSheetClasses(sheet, dynamicRules) : {} - } + return { + sheet, + dynamicRules, + classes: sheet ? getSheetClasses(sheet, dynamicRules) : {} } - ) + }) useEffectOrLayoutEffect( () => { From 1fd87da907205e1c94b36f62cf86aa1e13cad642 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 7 Jun 2019 11:38:49 +0200 Subject: [PATCH 47/52] reset module Id --- packages/jss/tests/unit/createGenerateId.js | 15 +++++++++------ tests/utils.js | 5 +++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/jss/tests/unit/createGenerateId.js b/packages/jss/tests/unit/createGenerateId.js index 30c514b79..ca0d1c11c 100644 --- a/packages/jss/tests/unit/createGenerateId.js +++ b/packages/jss/tests/unit/createGenerateId.js @@ -2,7 +2,7 @@ import expect from 'expect.js' import {createGenerateId} from '../../src' -import {resetSheets} from '../../../../tests/utils' +import {resetSheets, resetModuleId} from '../../../../tests/utils' const sheetMock = { options: { @@ -12,7 +12,10 @@ const sheetMock = { } describe('Unit: jss - createGenerateId', () => { - beforeEach(resetSheets()) + beforeEach(() => { + resetSheets() + resetModuleId() + }) it('should return a function', () => { expect(createGenerateId()).to.be.a(Function) @@ -20,12 +23,12 @@ describe('Unit: jss - createGenerateId', () => { it('should generate a non-production class name', () => { const generate = createGenerateId() - expect(generate({key: 'a'})).to.be('a-14-1') + expect(generate({key: 'a'})).to.be('a-0-1') }) it('should add prefix a non-production class name', () => { const generate = createGenerateId() - expect(generate({key: 'a'}, sheetMock)).to.be('pa-14-0-1') + expect(generate({key: 'a'}, sheetMock)).to.be('pa-0-0-1') }) it.skip('should increment jss lib version', () => { @@ -35,11 +38,11 @@ describe('Unit: jss - createGenerateId', () => { it('should generate a minified class name', () => { const generate = createGenerateId({minify: true}) - expect(generate()).to.be('c141') + expect(generate()).to.be('c01') }) it('should add prefix a minified class name', () => { const generate = createGenerateId({minify: true}) - expect(generate({key: 'a'}, sheetMock)).to.be('p1401') + expect(generate({key: 'a'}, sheetMock)).to.be('p001') }) }) diff --git a/tests/utils.js b/tests/utils.js index dd4dc7566..fe757670d 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -1,4 +1,9 @@ import {sheets as defaultSheets} from '../packages/jss/src' +import * as moduleIdExports from '../packages/jss/src/utils/moduleId' + +export function resetModuleId() { + moduleIdExports.default = 0 +} export function resetSheets(sheets = defaultSheets) { return () => { From 11725ec4f4288947839e6c30b847875d160e86ed Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 7 Jun 2019 12:49:11 +0200 Subject: [PATCH 48/52] rename shallow-equal, add a note --- packages/react-jss/.size-snapshot.json | 8 ++++---- packages/react-jss/src/JssProvider.js | 2 +- .../utils/{shallow-equal.js => shallowEqualObjects.js} | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) rename packages/react-jss/src/utils/{shallow-equal.js => shallowEqualObjects.js} (68%) diff --git a/packages/react-jss/.size-snapshot.json b/packages/react-jss/.size-snapshot.json index caf4f548c..569d9df62 100644 --- a/packages/react-jss/.size-snapshot.json +++ b/packages/react-jss/.size-snapshot.json @@ -1,21 +1,21 @@ { "dist/react-jss.js": { - "bundled": 128542, + "bundled": 128759, "minified": 44373, "gzipped": 13874 }, "dist/react-jss.min.js": { - "bundled": 96155, + "bundled": 96372, "minified": 34480, "gzipped": 11091 }, "dist/react-jss.cjs.js": { - "bundled": 20993, + "bundled": 21204, "minified": 9854, "gzipped": 3193 }, "dist/react-jss.esm.js": { - "bundled": 20142, + "bundled": 20353, "minified": 9113, "gzipped": 3072, "treeshaked": { diff --git a/packages/react-jss/src/JssProvider.js b/packages/react-jss/src/JssProvider.js index 7a2cd310f..218cee12b 100644 --- a/packages/react-jss/src/JssProvider.js +++ b/packages/react-jss/src/JssProvider.js @@ -10,7 +10,7 @@ import defaultJss, { } from 'jss' import type {Context, Managers} from './types' import JssContext from './JssContext' -import shallowEqualObjects from './utils/shallow-equal' +import shallowEqualObjects from './utils/shallowEqualObjects' /* eslint-disable react/require-default-props, react/no-unused-prop-types */ diff --git a/packages/react-jss/src/utils/shallow-equal.js b/packages/react-jss/src/utils/shallowEqualObjects.js similarity index 68% rename from packages/react-jss/src/utils/shallow-equal.js rename to packages/react-jss/src/utils/shallowEqualObjects.js index 88bc0c9f7..241ce17dc 100644 --- a/packages/react-jss/src/utils/shallow-equal.js +++ b/packages/react-jss/src/utils/shallowEqualObjects.js @@ -1,3 +1,7 @@ +// Original code is https://github.com/moroshko/shallow-equal/blob/master/src/objects.js +// Created issue https://github.com/moroshko/shallow-equal/issues/7 +// We had to copy that because we need an ESM module. + const shallowEqualObjects = (objA, objB) => { if (objA === objB) { return true From 86e5742f20695b28f9c16e8fd17b37d5d6c6f5e5 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 7 Jun 2019 13:59:25 +0200 Subject: [PATCH 49/52] hooks docs --- docs/react-jss-hoc.md | 608 ++++++++++++++++++++++++++++++++++++++++++ docs/react-jss.md | 335 ++++++++--------------- 2 files changed, 722 insertions(+), 221 deletions(-) create mode 100644 docs/react-jss-hoc.md diff --git a/docs/react-jss-hoc.md b/docs/react-jss-hoc.md new file mode 100644 index 000000000..bf7183ac4 --- /dev/null +++ b/docs/react-jss-hoc.md @@ -0,0 +1,608 @@ +## JSS integration with React + +React-JSS provides components for [JSS](https://github.com/cssinjs/jss) as a layer of abstraction. JSS and the [default preset](https://github.com/cssinjs/jss-preset-default) are already built in! Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). + +Benefits compared to the lower level core: + +- Dynamic Theming - allows context based theme propagation and runtime updates. +- Critical CSS extraction - only CSS from rendered components gets extracted. +- Lazy evaluation - Style Sheets are created when a component mounts and removed when it's unmounted. +- The static part of a Style Sheet will be shared between all elements. +- Function values and rules are updated automatically with props as an argument. + +### Table of Contents + +- [Install](#install) +- [Usage](#usage) + - [Basic](#basic) + - [Dynamic Values](#dynamic-values) + - [Theming](#theming) + - [Server-side rendering](#server-side-rendering) + - [React tree traversing](#react-tree-traversing) + - [Reuse styles in different components](#reuse-styles-in-different-components) + - [The inner component](#the-inner-component) + - [The inner ref](#the-inner-ref) + - [Custom setup](#custom-setup) + - [Decorators](#decorators) + - [Usage with TypeScript](#usage-with-typescript) + +### Install + +``` +yarn add react-jss +``` + +### Usage + +React-JSS wraps your component with a [higher-order component](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750). +It injects a `classes` prop, which is a simple map of rule names and generated class names. + +Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). + +#### Basic + +```javascript +import React from 'react' +import {render} from 'react-dom' +import withStyles from 'react-jss' + +// Create your Styles. Remember, since React-JSS uses the default preset, +// most plugins are available without further configuration needed. +const styles = { + myButton: { + color: 'green', + margin: { + // jss-plugin-expand gives more readable syntax + top: 5, // jss-plugin-default-unit makes this 5px + right: 0, + bottom: 0, + left: '1rem' + }, + '& span': { + // jss-plugin-nested applies this to a child span + fontWeight: 'bold' // jss-plugin-camel-case turns this into 'font-weight' + } + }, + myLabel: { + fontStyle: 'italic' + } +} + +// Define the component using these styles and pass it the 'classes' prop. +// Use this to assign scoped class names. +const Button = ({classes, children}) => ( + +) + +// Finally, inject the stylesheet into the component. +const StyledButton = withStyles(styles)(Button) +// You can also export the component with +// export default withStyles(styles)(Button) + +const App = () => Submit + +render(, document.getElementById('root')) +``` + +The above code will compile to + +```html +
+ +
+``` + +and + +```css +.Button-myButton-1-25 { + color: green; + margin: 5px 0 0 1rem; +} +.Button-myButton-1-25 span { + font-weight: bold; +} +.Button-myLabel-1-26 { + font-style: italic; +} +``` + +#### Dynamic values + +You can use [function values](jss-syntax.md#function-values), Function rules and observables out of the box. Function values and function rules will receive a props object once the component receives new props or mounts for the first time. + +Caveats: + +Static properties being rendered first so that function values will have higher source order specificity. + +```javascript +import React from 'react' +import withStyles from 'react-jss' + +const styles = { + myButton: { + padding: props => props.spacing + }, + myLabel: props => ({ + display: 'block', + color: props.labelColor, + fontWeight: props.fontWeight, + fontStyle: props.fontStyle + }) +} + +const Button = ({classes, children}) => ( + +) + +Button.defaultProps = { + spacing: 10, + fontWeight: 'bold', + labelColor: 'red' +} + +const StyledButton = withStyles(styles)(Button) + +const App = () => Submit +``` + +The above code will compile to + +```html +
+ +
+``` + +and + +```css +.Button-myButton-1-25 { + padding: 10px; +} +.Button-myLabel-1-26 { + display: block; + color: red; + font-weight: bold; + font-style: italic; +} +``` + +#### Theming + +The idea is that you define a theme, wrap your application with `ThemeProvider` and pass the `theme` to `ThemeProvider`. ThemeProvider will pass it over `context` to your styles creator function and your props. After that, you may change your theme, and all your components will get the new theme automatically. + +Under the hood `react-jss` uses the unified CSSinJS `theming` solution for React. You can find [full docs in its repo](https://github.com/iamstarkov/theming). + +Usage of `ThemeProvider`: + +- It has a `theme` prop which should be an `object` or `function`: + - If it is an `Object` and used in a root `ThemeProvider`, then it's intact and being passed down the React Tree. + - If it is `Object` and used in a nested `ThemeProvider`, then it gets merged with the theme from a parent `ThemeProvider` and passed down the react tree. + - If it is `Function` and used in a nested `ThemeProvider`, then it's being applied to the theme from a parent `ThemeProvider`. If the result is an `Object` it will be passed down the react tree, throws otherwise. +- `ThemeProvider` as every other component can render only a single child because it uses `React.Children.only` in render and throws otherwise. +- [Read more about `ThemeProvider` in `theming`'s documentation.](https://github.com/cssinjs/theming#themeprovider) + +```javascript +import React from 'react' +import withStyles, {ThemeProvider} from 'react-jss' + +const Button = ({classes, children}) => ( + +) + +const styles = theme => ({ + button: { + background: theme.colorPrimary + }, + label: { + fontWeight: 'bold' + } +}) + +const StyledButton = withStyles(styles)(Button) + +const theme = { + colorPrimary: 'green' +} + +const App = () => ( + + I am a button with green background + +) +``` + +#### Accessing the theme inside the styled component + +The theme will not be injecting into the wrapped component. +To inject the theme into the wrapped component, pass the `injectTheme` option to `withStyles`. + +```javascript +import React from 'react' +import withStyles from 'react-jss' + +const DeleteIcon = () => null + +const Button = ({classes, children, theme}) => ( + +) + +const styles = theme => ({ + button: { + background: theme.colorPrimary + }, + label: { + fontWeight: 'bold' + } +}) + +const StyledButton = withStyles(styles, {injectTheme: true})(Button) +``` + +#### Accessing the theme without a styled component + +In case you need to access the theme but not render any CSS, you can also use `withTheme`. It is a Higher-order Component factory which takes a `React.Component` and maps the theme object from context to props. [Read more about `withTheme` in `theming`'s documentation.](https://github.com/cssinjs/theming#withthemecomponent) + +```javascript +import React from 'react' +import {withTheme} from 'react-jss' + +const Button = withTheme(({theme}) => ) +``` + +#### Using custom Theming Context + +Use _namespaced_ themes so that a set of UI components gets no conflicts with another set of UI components from a different library also using `react-jss`. + +```javascript +import React from 'react' +import withStyles, {createTheming} from 'react-jss' + +const ThemeContext = React.createContext({}) + +// Creating a namespaced theming object. +const theming = createTheming(ThemeContext) + +const {ThemeProvider} = theming + +const styles = theme => ({ + button: { + background: theme.colorPrimary + } +}) + +const theme = { + colorPrimary: 'green' +} + +const Button = ({classes, children}) => + +// Passing namespaced theming object inside withStyles options. +const StyledButton = withStyles(styles, {theming})(Button) +const OtherLibraryThemeProvider = () => null +const OtherLibraryComponent = () => null +const otherLibraryTheme = {} + +// Using namespaced ThemeProviders - they can be nested in any order +const App = () => ( + + + + Green Button + + +) +``` + +#### Server-side rendering + +After the application is mounted, you should remove the style tag used by critical CSS rendered server-side. + +```javascript +import React from 'react' +import {renderToString} from 'react-dom/server' +import {JssProvider, SheetsRegistry, createGenerateId} from 'react-jss' +import MyApp from './MyApp' + +export default function render(req, res) { + const sheets = new SheetsRegistry() + const generateId = createGenerateId() + + const body = renderToString( + + + + ) + + // Any instances of `withStyles` within `` will have gotten sheets + // from `context` and added their Style Sheets to it by now. + + return res.send( + renderToString( + + + + + {body} + + ) + ) +} +``` + +#### React tree traversing + +For traversing the React tree outside of the HTML rendering, you should add `disableStylesGeneration` property. + +```javascript +import React from 'react' +import ReactDOM from 'react-dom' +import bootstrapper from 'react-async-bootstrapper' + +import {JssProvider} from 'react-jss' +import MyApp from './MyApp' + +const App = ({disableStylesGeneration}) => ( + + + +) + +async function main() { + await bootstrapper() + ReactDOM.render(, document.getElementById('root')) +} + +main() +``` + +#### Reuse styles in different components + +To reuse the same styles **and** the same generated style sheet between 2 entirely different and unrelated components, we suggest extracting a renderer component and reusing that. + +```javascript +import React from 'react' +import withStyles from 'react-jss' + +const styles = { + button: { + color: 'red' + } +} +const RedButton = withStyles(styles)(({classes, children}) => ( + +)) + +const SomeComponent1 = () => ( +
+ My red button 1 +
+) + +const SomeComponent2 = () => ( +
+ My red button 2 +
+) +``` + +Alternatively, you can create own Style Sheet and use the `composes` feature. Also, you can mix in a common styles object but take into account that it can increase the overall CSS size. + +#### The inner component + +```javascript +import withStyles from 'react-jss' + +const InnerComponent = () => null +const StyledComponent = withStyles({})(InnerComponent) +console.log(StyledComponent.InnerComponent) // Prints out the inner component. +``` + +#### The inner ref + +To get a `ref` to the inner element, use the `ref` prop. +We will forward the ref to the inner component. + +```javascript +import React from 'react' +import withStyles from 'react-jss' + +const InnerComponent = () => null +const StyledComponent = withStyles({})(InnerComponent) + +const App = ( + { + console.log(ref) + }} + /> +) +``` + +#### Custom setup + +If you want to specify a JSS version and plugins to use, you should create your [own JSS instance](https://github.com/cssinjs/jss/blob/master/docs/jss-api.md#create-an-own-jss-instance), [setup plugins](https://github.com/cssinjs/jss/blob/master/docs/setup.md#setup-with-custom-plugins) and pass it to `JssProvider`. + +```javascript +import React from 'react' +import {create as createJss} from 'jss' +import {JssProvider} from 'react-jss' +import vendorPrefixer from 'jss-plugin-vendor-prefixer' + +const jss = createJss() +jss.use(vendorPrefixer()) + +const App = () => null +const Component = () => ( + + + +) +``` + +You can also access the default JSS instance. + +```javascript +import {jss} from 'react-jss' +``` + +#### Multi-tree setup + +In case you render multiple react rendering trees in one application, you will get class name collisions because every JssProvider rerender will reset the class names generator. If you want to avoid this, you can share the class names generator between multiple JssProvider instances. + +**Note**: in case of SSR, make sure to create a new generator for **each** request. Otherwise, class names will become indeterministic, and at some point, you may run out of max safe integer numbers. + +```javascript +import React from 'react' +import {createGenerateId, JssProvider} from 'react-jss' + +const generateId = createGenerateId() +const App1 = () => null +const App2 = () => null + +const Component = () => ( +
+ + + + + + +
+) +``` + +You can also additionally use the `classNamePrefix` prop to add the app/subtree name to each class name. +This way you can see which app generated a class name in the DOM view. + +```javascript +import React from 'react' +import {JssProvider} from 'react-jss' + +const App1 = () => null +const App2 = () => null + +const Component = () => ( +
+ + + + + + +
+) +``` + +#### Decorators + +_Beware that [decorators are stage-2 proposal](https://tc39.github.io/proposal-decorators/), so there are [no guarantees that decorators will make its way into language specification](https://tc39.github.io/process-document/). Do not use it in production. Use it at your own risk and only if you know what you are doing._ + +You will need [babel-plugin-transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy). + +```javascript +import React, {Component} from 'react' +import withStyles from 'react-jss' + +const styles = { + button: { + backgroundColor: 'yellow' + }, + label: { + fontWeight: 'bold' + } +} + +@withStyles(styles) +class Button extends Component { + render() { + const {classes, children} = this.props + return ( + + ) + } +} + +export default Button +``` + +### Injection order + +Injection of style tags happens in the same order as the `withStyles()` invocation. +Source order specificity is higher the lower style tag is in the tree. Therefore you should call `withStyles` of components you want to override first. + +Example + +```javascript +import React from 'react' +import withStyles from 'react-jss' + +const labelStyles = {} +const buttonStyles = {} + +// Will render labelStyles first. +const Label = withStyles(labelStyles)(({children}) => ) +const Button = withStyles(buttonStyles)(() => ( + +)) +``` + +### Usage with TypeScript + +React JSS includes first class support for TypeScript. React JSS provides +a `WithStyles` type which adds types for all of the injected props. +To use it, simply extend your existing props interface with +`WithStyles`, where `styles` is your styles object. + +> Note: To use WithStyles you must use react-jss version 10 or higher. + +Example + +```typescript +import * as React from 'react' +import withStyles, {WithStyles} from 'react-jss' + +const styles = { + button: { + backgroundColor: 'yellow' + }, + label: { + fontWeight: 'bold' + } +} + +interface IProps extends WithStyles { + children: React.ReactNode +} + +const Button: React.FunctionComponent = ({classes, children}) => ( + +) + +export default withStyles(styles)(Button) +``` diff --git a/docs/react-jss.md b/docs/react-jss.md index 845228c1a..8776db47d 100644 --- a/docs/react-jss.md +++ b/docs/react-jss.md @@ -19,14 +19,8 @@ Benefits compared to the lower level core: - [Theming](#theming) - [Server-side rendering](#server-side-rendering) - [React tree traversing](#react-tree-traversing) - - [Reuse styles in different components](#reuse-styles-in-different-components) - - [The inner component](#the-inner-component) - - [The inner ref](#the-inner-ref) - [Custom setup](#custom-setup) - - [Decorators](#decorators) - - [Usage with TypeScript](#usage-with-typescript) -- [Contributing](#contributing) -- [License](#license) + - [TypeScript](#typescript) ### Install @@ -36,8 +30,7 @@ yarn add react-jss ### Usage -React-JSS wraps your component with a [higher-order component](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750). -It injects a `classes` prop, which is a simple map of rule names and generated class names. +React-JSS integrates with React using the new Hooks API as well as a Styled Component API. HOC based API is deprecated as of v10 and will be removed in v11. Old docs are available [here](./react-jss-hoc.md). Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). @@ -46,11 +39,11 @@ Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). ```javascript import React from 'react' import {render} from 'react-dom' -import withStyles from 'react-jss' +import {createUseStyles} from 'react-jss' // Create your Styles. Remember, since React-JSS uses the default preset, // most plugins are available without further configuration needed. -const styles = { +const useStyles = createUseStyles({ myButton: { color: 'green', margin: { @@ -68,22 +61,20 @@ const styles = { myLabel: { fontStyle: 'italic' } -} +}) // Define the component using these styles and pass it the 'classes' prop. // Use this to assign scoped class names. -const Button = ({classes, children}) => ( - -) - -// Finally, inject the stylesheet into the component. -const StyledButton = withStyles(styles)(Button) -// You can also export the component with -// export default withStyles(styles)(Button) +const Button = ({children}) => { + const classes = useStyles() + return ( + + ) +} -const App = () => Submit +const App = () => render(, document.getElementById('root')) ``` @@ -125,9 +116,9 @@ Static properties being rendered first so that function values will have higher ```javascript import React from 'react' -import withStyles from 'react-jss' +import {createUseStyles} from 'react-jss' -const styles = { +const useStyles = createUseStyles({ myButton: { padding: props => props.spacing }, @@ -137,13 +128,16 @@ const styles = { fontWeight: props.fontWeight, fontStyle: props.fontStyle }) -} +}) -const Button = ({classes, children}) => ( - -) +const Button = ({children, ...props}) => { + const classes = useStyles(props) + return ( + + ) +} Button.defaultProps = { spacing: 10, @@ -151,9 +145,7 @@ Button.defaultProps = { labelColor: 'red' } -const StyledButton = withStyles(styles)(Button) - -const App = () => Submit +const App = () => ``` The above code will compile to @@ -184,9 +176,9 @@ and #### Theming -The idea is that you define a theme, wrap your application with `ThemeProvider` and pass the `theme` to `ThemeProvider`. ThemeProvider will pass it over `context` to your styles creator function and your props. After that, you may change your theme, and all your components will get the new theme automatically. +The idea is that you define a theme, wrap your application with `ThemeProvider` and pass the `theme` object to `ThemeProvider`. Later you can access theme in your styles creator function and using a `useTheme()` hook. After that, you may change your theme, and all your components will get the new theme automatically. -Under the hood `react-jss` uses the unified CSSinJS `theming` solution for React. You can find [full docs in its repo](https://github.com/iamstarkov/theming). +Under the hood `react-jss` uses a standalone `theming` solution for React. You can find [full docs in its repo](https://github.com/cssinjs/theming). Usage of `ThemeProvider`: @@ -199,24 +191,25 @@ Usage of `ThemeProvider`: ```javascript import React from 'react' -import withStyles, {ThemeProvider} from 'react-jss' +import {createUseStyles, useTheme, ThemeProvider} from 'react-jss' -const Button = ({classes, children}) => ( - -) - -const styles = theme => ({ +const useStyles = createUseStyles(theme => ({ button: { background: theme.colorPrimary }, label: { fontWeight: 'bold' } -}) - -const StyledButton = withStyles(styles)(Button) +})) + +const Button = ({children, ...props}) => { + const classes = useStyles(props) + return ( + + ) +} const theme = { colorPrimary: 'green' @@ -224,82 +217,92 @@ const theme = { const App = () => ( - I am a button with green background + ) ``` #### Accessing the theme inside the styled component -The theme will not be injecting into the wrapped component. -To inject the theme into the wrapped component, pass the `injectTheme` option to `withStyles`. +Use `useTheme()` hook to access the theme inside of the function component. ```javascript import React from 'react' -import withStyles from 'react-jss' - -const DeleteIcon = () => null - -const Button = ({classes, children, theme}) => ( - -) - -const styles = theme => ({ +const useStyles = createUseStyles(theme => ({ button: { background: theme.colorPrimary }, label: { fontWeight: 'bold' } -}) +})) + +const DeleteIcon = () => null -const StyledButton = withStyles(styles, {injectTheme: true})(Button) +const Button = ({children, ...props}) => { + const classes = useStyles(props) + const theme = useTheme() + return ( + + ) +} ``` -#### Accessing the theme without a styled component +#### Accessing the theme without styles -In case you need to access the theme but not render any CSS, you can also use `withTheme`. It is a Higher-order Component factory which takes a `React.Component` and maps the theme object from context to props. [Read more about `withTheme` in `theming`'s documentation.](https://github.com/cssinjs/theming#withthemecomponent) +In case you need to access the theme without rendering any CSS, you can also use `useTheme()` standalone. ```javascript import React from 'react' -import {withTheme} from 'react-jss' +import {useTheme} from 'react-jss' -const Button = withTheme(({theme}) => ) +const Button = () => { + const theme = useTheme() + return +} ``` #### Using custom Theming Context -Use _namespaced_ themes so that a set of UI components gets no conflicts with another set of UI components from a different library also using `react-jss`. +Use _namespaced_ themes so that a set of UI components gets no conflicts with another set of UI components from a different library also using `react-jss` or in case you want to use the same theme from another context that is already used in your app. ```javascript import React from 'react' -import withStyles, {createTheming} from 'react-jss' +import {createUseStyles, createTheming} from 'react-jss' const ThemeContext = React.createContext({}) // Creating a namespaced theming object. const theming = createTheming(ThemeContext) -const {ThemeProvider} = theming +// Note that `useTheme` here comes from the `theming` object, NOT from `react-jss` import. +const {ThemeProvider, useTheme} = theming -const styles = theme => ({ - button: { - background: theme.colorPrimary - } -}) +const useStyles = createUseStyles( + theme => ({ + button: { + background: theme.colorPrimary + } + // Passing theming object to `createUseStyles()` + }), + {theming} +) const theme = { colorPrimary: 'green' } -const Button = ({classes, children}) => +const Button = ({children, ...props}) => { + const classes = useStyles(props) + const themeOverContext = useTheme() // In case you need to access the theme here. + return +} -// Passing namespaced theming object inside withStyles options. -const StyledButton = withStyles(styles, {theming})(Button) const OtherLibraryThemeProvider = () => null const OtherLibraryComponent = () => null const otherLibraryTheme = {} @@ -309,7 +312,7 @@ const App = () => ( - Green Button + ) @@ -335,7 +338,7 @@ export default function render(req, res) { ) - // Any instances of `withStyles` within `` will have gotten sheets + // Any instances using `useStyles` within `` will have gotten sheets // from `context` and added their Style Sheets to it by now. return res.send( @@ -377,69 +380,6 @@ async function main() { main() ``` -#### Reuse styles in different components - -To reuse the same styles **and** the same generated style sheet between 2 entirely different and unrelated components, we suggest extracting a renderer component and reusing that. - -```javascript -import React from 'react' -import withStyles from 'react-jss' - -const styles = { - button: { - color: 'red' - } -} -const RedButton = withStyles(styles)(({classes, children}) => ( - -)) - -const SomeComponent1 = () => ( -
- My red button 1 -
-) - -const SomeComponent2 = () => ( -
- My red button 2 -
-) -``` - -Alternatively, you can create own Style Sheet and use the `composes` feature. Also, you can mix in a common styles object but take into account that it can increase the overall CSS size. - -#### The inner component - -```javascript -import withStyles from 'react-jss' - -const InnerComponent = () => null -const StyledComponent = withStyles({})(InnerComponent) -console.log(StyledComponent.InnerComponent) // Prints out the inner component. -``` - -#### The inner ref - -To get a `ref` to the inner element, use the `ref` prop. -We will forward the ref to the inner component. - -```javascript -import React from 'react' -import withStyles from 'react-jss' - -const InnerComponent = () => null -const StyledComponent = withStyles({})(InnerComponent) - -const App = ( - { - console.log(ref) - }} - /> -) -``` - #### Custom setup If you want to specify a JSS version and plugins to use, you should create your [own JSS instance](https://github.com/cssinjs/jss/blob/master/docs/jss-api.md#create-an-own-jss-instance), [setup plugins](https://github.com/cssinjs/jss/blob/master/docs/setup.md#setup-with-custom-plugins) and pass it to `JssProvider`. @@ -515,96 +455,49 @@ const Component = () => ( ) ``` -#### Decorators - -_Beware that [decorators are stage-2 proposal](https://tc39.github.io/proposal-decorators/), so there are [no guarantees that decorators will make its way into language specification](https://tc39.github.io/process-document/). Do not use it in production. Use it at your own risk and only if you know what you are doing._ - -You will need [babel-plugin-transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy). - -```javascript -import React, {Component} from 'react' -import withStyles from 'react-jss' - -const styles = { - button: { - backgroundColor: 'yellow' - }, - label: { - fontWeight: 'bold' - } -} - -@withStyles(styles) -class Button extends Component { - render() { - const {classes, children} = this.props - return ( - - ) - } -} - -export default Button -``` - ### Injection order -Injection of style tags happens in the same order as the `withStyles()` invocation. -Source order specificity is higher the lower style tag is in the tree. Therefore you should call `withStyles` of components you want to override first. +Injection of style tags happens in the same order as the `createUseStyles()` invocation. +Source order specificity is higher the lower style tag is in the tree. Therefore you should call `createUseStyles` of components you want to override first. Example ```javascript import React from 'react' -import withStyles from 'react-jss' - -const labelStyles = {} -const buttonStyles = {} +import {createUseStyles} from 'react-jss' -// Will render labelStyles first. -const Label = withStyles(labelStyles)(({children}) => ) -const Button = withStyles(buttonStyles)(() => ( - -)) -``` - -### Usage with TypeScript - -React JSS includes first class support for TypeScript. React JSS provides -a `WithStyles` type which adds types for all of the injected props. -To use it, simply extend your existing props interface with -`WithStyles`, where `styles` is your styles object. - -> Note: To use WithStyles you must use react-jss version 10 or higher. - -Example - -```typescript -import * as React from 'react' -import withStyles, {WithStyles} from 'react-jss' +// Will render first once component mounts, because `createUseStyles()` call order matters. +const useLabelStyles = createUseStyles({ + label: { + color: 'red' + } +}) -const styles = { +const useButtonStyles = createUseStyles({ button: { - backgroundColor: 'yellow' - }, - label: { - fontWeight: 'bold' + color: 'red' } +}) + +// Will render styles first. +const Label = ({children}) => { + const classes = useLabelStyles() + return } -interface IProps extends WithStyles { - children: React.ReactNode +const Button = () => { + const classes = useButtonStyles() + // The order in which we render those components doesn't matter. + // What matters is the order of `createUseStyles()` calls. + return ( + <> + -) +### TypeScript -export default withStyles(styles)(Button) -``` +TODO hooks support From 5b0af838b905fb58ce36c1d684e7a343bef13ba6 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 7 Jun 2019 14:07:21 +0200 Subject: [PATCH 50/52] better description --- docs/react-jss.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/react-jss.md b/docs/react-jss.md index 8776db47d..70cbea3ec 100644 --- a/docs/react-jss.md +++ b/docs/react-jss.md @@ -1,6 +1,10 @@ ## JSS integration with React -React-JSS provides components for [JSS](https://github.com/cssinjs/jss) as a layer of abstraction. JSS and the [default preset](https://github.com/cssinjs/jss-preset-default) are already built in! Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). +React-JSS integrates [JSS](https://github.com/cssinjs/jss) with React using the new Hooks API as well as a Styled Component API. JSS and the [default preset](https://github.com/cssinjs/jss-preset-default) are already built in. + +Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). + +**HOC based API is deprecated as of v10 and will be removed in v11. Old docs are available [here](./react-jss-hoc.md).** Benefits compared to the lower level core: @@ -30,10 +34,6 @@ yarn add react-jss ### Usage -React-JSS integrates with React using the new Hooks API as well as a Styled Component API. HOC based API is deprecated as of v10 and will be removed in v11. Old docs are available [here](./react-jss-hoc.md). - -Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). - #### Basic ```javascript From 95bef20e1041894bdf1976b83b4d5c2a761edad3 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 7 Jun 2019 14:13:45 +0200 Subject: [PATCH 51/52] better wording --- docs/react-jss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/react-jss.md b/docs/react-jss.md index 70cbea3ec..7b6e6f6c4 100644 --- a/docs/react-jss.md +++ b/docs/react-jss.md @@ -6,7 +6,7 @@ Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw). **HOC based API is deprecated as of v10 and will be removed in v11. Old docs are available [here](./react-jss-hoc.md).** -Benefits compared to the lower level core: +Benefits compared to using the core JSS package directly: - Dynamic Theming - allows context based theme propagation and runtime updates. - Critical CSS extraction - only CSS from rendered components gets extracted. From 68bbae37935d008cecca971c8de4c46f0df89e5a Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 7 Jun 2019 16:06:37 +0200 Subject: [PATCH 52/52] fix link --- docs/react-jss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/react-jss.md b/docs/react-jss.md index 7b6e6f6c4..0382c07cd 100644 --- a/docs/react-jss.md +++ b/docs/react-jss.md @@ -1,6 +1,6 @@ ## JSS integration with React -React-JSS integrates [JSS](https://github.com/cssinjs/jss) with React using the new Hooks API as well as a Styled Component API. JSS and the [default preset](https://github.com/cssinjs/jss-preset-default) are already built in. +React-JSS integrates [JSS](https://github.com/cssinjs/jss) with React using the new Hooks API as well as a Styled Component API. JSS and the [default preset](https://github.com/cssinjs/jss/tree/master/packages/jss-preset-default) are already built in. Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw).