Skip to content

Commit

Permalink
Add dynamic rules to static sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
Henri Beck committed Mar 2, 2019
1 parent e6bf06a commit c3cdfb4
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 57 deletions.
26 changes: 13 additions & 13 deletions packages/react-jss/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
"dist/react-jss.js": {
"bundled": 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
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion packages/react-jss/src/types.js
Original file line number Diff line number Diff line change
@@ -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'

Expand Down Expand Up @@ -32,5 +32,9 @@ export type InnerProps = {
classes: {}
}

export type DynamicRules = {
[key: string]: BaseRule,
};

export type ThemedStyles<Theme> = (theme: Theme) => StaticStyles
export type Styles<Theme> = StaticStyles | ThemedStyles<Theme>
116 changes: 73 additions & 43 deletions packages/react-jss/src/withStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {}
}

Expand Down Expand Up @@ -64,6 +62,8 @@ export default function withStyles<Theme: {}, S: Styles<Theme>>(
return <Props: InnerProps>(
InnerComponent: ComponentType<Props> = NoRenderer
): ComponentType<Props> => {
let instanceCounter = 0;

const displayName = getDisplayName(InnerComponent)
const defaultClassNamePrefix = process.env.NODE_ENV === 'production' ? '' : `${displayName}-`
const managerId = managersCounter++
Expand All @@ -84,6 +84,8 @@ export default function withStyles<Theme: {}, S: Styles<Theme>>(
classesProp ? mergeClasses(sheetClasses, classesProp) : sheetClasses
)

instanceId = instanceCounter++

constructor(props: HOCProps<Theme, Props>) {
super(props)

Expand All @@ -96,8 +98,7 @@ export default function withStyles<Theme: {}, S: Styles<Theme>>(
}

componentDidUpdate(prevProps: HOCProps<Theme, Props>, 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()
Expand Down Expand Up @@ -132,7 +133,7 @@ export default function withStyles<Theme: {}, S: Styles<Theme>>(
return manager
}

getStaticSheet(): StyleSheet {
getSheet(): StyleSheet {
const theme = getTheme(this.props)
let staticSheet = this.manager.get(theme)

Expand All @@ -141,85 +142,114 @@ export default function withStyles<Theme: {}, S: Styles<Theme>>(
}

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 {
if (this.props.jssContext.disableStylesGeneration) {
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),
}
}

Expand Down

0 comments on commit c3cdfb4

Please sign in to comment.