Skip to content

Commit 43523aa

Browse files
committed
Get rid from dynamicStyleSheet, fix nested dynamic rules
1 parent ac5cb91 commit 43523aa

11 files changed

Lines changed: 305 additions & 76 deletions

File tree

.flowconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
<PROJECT_ROOT>/lib/
77

8+
[libs]
9+
node_modules/jss/flow-typed
10+
811
[options]
912
all=true

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@
5454
"babel-plugin-transform-object-rest-spread": "^6.23.0",
5555
"babel-preset-es2015": "^6.24.1",
5656
"babel-preset-react": "^6.23.0",
57+
"common-tags": "^1.4.0",
5758
"copyfiles": "^1.2.0",
5859
"coveralls": "^2.13.0",
60+
"enzyme": "^2.8.2",
5961
"eslint": "^3.13.0",
6062
"eslint-config-airbnb": "^14.1.0",
6163
"eslint-config-jss": "^3.0.0",

src/createStyled.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,17 @@ const getStyledArgs = (
2121
}
2222

2323
const createStyled = (jss: Function) => (baseStyles: BaseStylesType = {}): StyledType => {
24-
let staticSheet
25-
let dynamicSheet
24+
let sheet
2625

27-
const mountSheets = () => {
28-
if (!staticSheet) {
29-
staticSheet = jss.createStyleSheet(baseStyles, {
30-
meta: 'StaticBaseSheet',
31-
}).attach()
32-
33-
dynamicSheet = jss.createStyleSheet({}, {
26+
const mountSheet = () => {
27+
if (!sheet) {
28+
sheet = jss.createStyleSheet(baseStyles, {
3429
link: true,
35-
meta: 'DynamicComponentSheet',
30+
meta: 'sheet',
3631
}).attach()
3732
}
3833

39-
return {staticSheet, dynamicSheet}
34+
return sheet
4035
}
4136

4237
return Object.assign((
@@ -47,8 +42,8 @@ const createStyled = (jss: Function) => (baseStyles: BaseStylesType = {}): Style
4742
const {tagName, style} = getStyledArgs(tagNameOrStyledElement)
4843
const elementStyle = {...style, ...ownStyle}
4944

50-
return styled({tagName, baseStyles, elementStyle, mountSheets})
51-
}, {mountSheets, styles: baseStyles})
45+
return styled({tagName, baseStyles, elementStyle, mountSheet})
46+
}, {mountSheet, styles: baseStyles})
5247
}
5348

5449
export default createStyled

src/injectStyled.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import composeClasses from './utils/composeClasses'
44
import type {StyledType} from './types'
55

66
const injectStyled = (styled: StyledType) => (InnerComponent: ReactClass<any>) => {
7-
const {staticSheet, dynamicSheet} = styled.mountSheets()
7+
const sheet = styled.mountSheet()
88

9-
const classNames = Object.keys({...staticSheet.classes, ...dynamicSheet.classes})
9+
const classNames = Object.keys(sheet.classes)
1010

1111
const classes = [...classNames]
1212
.reduce((acc, name) => ({
1313
...acc,
14-
[name]: composeClasses([staticSheet.classes[name], dynamicSheet.classes[name]]),
14+
[name]: composeClasses([sheet.classes[name]]),
1515
}), {})
1616

1717
return (props: Object) => createElement(InnerComponent, {classes, ...props})

src/styled.js

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
import {Component, createElement} from 'react'
22
import {getDynamicStyles} from 'jss'
3+
import type {
4+
Rule,
5+
} from 'jss/lib/types'
36

47
import filterProps from './utils/filterProps'
58
import composeClasses from './utils/composeClasses'
69
import generateTagName from './utils/generateTagName'
710

811
import type {
9-
JssStaticSheet,
10-
JssDynamicSheet,
12+
JssSheet,
1113
ComponentStyleType,
1214
StyledElementPropsType
1315
} from './types'
1416

1517
type StyledArgs = {
1618
tagName: string,
1719
elementStyle: ComponentStyleType,
18-
mountSheets: Function
20+
mountSheet: Function
1921
}
2022

21-
const styled = ({tagName, elementStyle, mountSheets}: StyledArgs) => {
23+
const styled = ({tagName, elementStyle, mountSheet}: StyledArgs) => {
2224
const dynamicStyle = getDynamicStyles(elementStyle)
2325
const staticTagName = generateTagName(tagName)
2426

2527
const availableDynamicTagNames = []
28+
const classMap = {}
2629

2730
return class StyledElement extends Component {
2831
static tagName: string = tagName
@@ -31,8 +34,10 @@ const styled = ({tagName, elementStyle, mountSheets}: StyledArgs) => {
3134
props: StyledElementPropsType
3235

3336
dynamicTagName = ''
34-
staticSheet: JssStaticSheet
35-
dynamicSheet: JssDynamicSheet
37+
38+
sheet: JssSheet
39+
cssRules: CSSStyleRule[]
40+
rulesIndex: Rule[]
3641

3742
constructor(props: StyledElementPropsType) {
3843
super(props)
@@ -42,24 +47,55 @@ const styled = ({tagName, elementStyle, mountSheets}: StyledArgs) => {
4247
}
4348

4449
componentWillMount() {
45-
Object.assign(this, mountSheets())
50+
this.sheet = this.sheet || mountSheet()
51+
this.rulesIndex = this.sheet.rules.index
52+
this.cssRules = this.cssRules || this.sheet.renderer.getRules() || []
53+
54+
const rulesTotal = this.rulesIndex.length
55+
const cssRulesTotal = this.cssRules.length
4656

47-
if (!this.staticSheet.getRule(staticTagName)) {
48-
this.staticSheet.addRule(staticTagName, elementStyle)
57+
if (!this.sheet.getRule(staticTagName)) {
58+
this.sheet.addRule(staticTagName, elementStyle)
4959
}
5060

5161
if (!dynamicStyle) return
5262

53-
if (!this.dynamicSheet.getRule(this.dynamicTagName)) {
54-
this.dynamicSheet.addRule(this.dynamicTagName, dynamicStyle)
63+
if (!this.sheet.getRule(this.dynamicTagName)) {
64+
this.sheet.addRule(this.dynamicTagName, dynamicStyle)
5565
}
5666

57-
this.dynamicSheet.update(this.dynamicTagName, this.props)
67+
classMap[this.dynamicTagName] = this.rulesIndex.slice(rulesTotal)
68+
69+
let cssRule
70+
let rule
71+
let cssRuleIndex = 0
72+
let ruleIndex = 0
73+
// nested styles become to flatten rules, so we need to update each nested rule
74+
for (ruleIndex; ruleIndex < classMap[this.dynamicTagName].length; ruleIndex++) {
75+
rule = classMap[this.dynamicTagName][ruleIndex]
76+
cssRule = this.cssRules[cssRulesTotal + cssRuleIndex]
77+
if (cssRule && cssRule.selectorText === rule.selectorText) {
78+
/**
79+
* we need to set cssRule in rule.renderable
80+
* @see {@link https://github.com/cssinjs/jss/issues/500}
81+
* and we don't want to use link(), because there is no need to iterate over all rules
82+
*/
83+
rule.renderable = cssRule
84+
cssRuleIndex++
85+
}
86+
this.sheet.update(rule.name, this.props)
87+
}
5888
}
5989

6090
componentWillReceiveProps(nextProps: StyledElementPropsType) {
6191
if (dynamicStyle) {
62-
this.dynamicSheet.update(this.dynamicTagName, nextProps)
92+
let rule
93+
let ruleIndex = 0
94+
// the same rules update as in constructor
95+
for (ruleIndex; ruleIndex < classMap[this.dynamicTagName].length; ruleIndex++) {
96+
rule = classMap[this.dynamicTagName][ruleIndex]
97+
this.sheet.update(rule.name, nextProps)
98+
}
6399
}
64100
}
65101

@@ -68,14 +104,12 @@ const styled = ({tagName, elementStyle, mountSheets}: StyledArgs) => {
68104
}
69105

70106
render() {
71-
if (!this.staticSheet) return null
72-
73107
const {children, className, ...attrs} = this.props
74108

75109
const props = filterProps(attrs)
76110
const tagClass = composeClasses([
77-
this.staticSheet.classes[staticTagName],
78-
this.dynamicSheet.classes[this.dynamicTagName],
111+
this.sheet.classes[staticTagName],
112+
this.sheet.classes[this.dynamicTagName],
79113
className
80114
])
81115

src/tests/.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ rules:
22
import/no-extraneous-dependencies:
33
- error
44
- devDependencies: true
5+
react/require-default-props: off

src/tests/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ export default (styled: StyledType) => {
3131
margin: ({margin = 0}) => margin,
3232
})
3333

34-
return () => (
34+
return ({margin = 10}: {margin?: number}) => (
3535
<App>
3636
<Header>
3737
<Title>Title</Title>
3838
</Header>
3939

4040
<Section data-name="content">
4141
<Button>primitive test</Button>
42-
<Button margin={10}>dynamic primitive test</Button>
42+
<Button margin={margin}>dynamic primitive test</Button>
4343
</Section>
4444

4545
<AnotherSection>Another section</AnotherSection>

src/tests/__snapshots__/index.spec.jsx.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
exports[`test renders correctly App with default Styled 1`] = `
1+
exports[`base rendering tests renders correctly App with default Styled 1`] = `
22
<div
33
className="div-9-0-9">
44
<header
@@ -27,7 +27,7 @@ exports[`test renders correctly App with default Styled 1`] = `
2727
</div>
2828
`;
2929

30-
exports[`test renders correctly App with default styled 1`] = `
30+
exports[`base rendering tests renders correctly App with default styled 1`] = `
3131
<div
3232
className="div-1-0-0">
3333
<header
@@ -56,7 +56,7 @@ exports[`test renders correctly App with default styled 1`] = `
5656
</div>
5757
`;
5858

59-
exports[`test renders correctly App with injectStyled 1`] = `
59+
exports[`base rendering tests renders correctly App with injectStyled 1`] = `
6060
<div
6161
className="root-0-17">
6262
<div

src/tests/index.spec.jsx

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,43 @@ import styled, {Styled, injectStyled} from '../'
66

77
import CreateApp from './App'
88

9+
describe('base rendering tests', () => {
10+
it('renders correctly App with default styled', () => {
11+
const App = CreateApp(styled)
12+
const tree = renderer.create(<App />).toJSON()
913

10-
it('renders correctly App with default styled', () => {
11-
const App = CreateApp(styled)
12-
const tree = renderer.create(<App />).toJSON()
13-
14-
expect(tree).toMatchSnapshot()
15-
})
16-
17-
it('renders correctly App with default Styled', () => {
18-
const customStyled = Styled({
19-
baseButton: {
20-
color: 'red',
21-
},
14+
expect(tree).toMatchSnapshot()
2215
})
2316

24-
const App = CreateApp(customStyled)
25-
const tree = renderer.create(<App />).toJSON()
17+
it('renders correctly App with default Styled', () => {
18+
const customStyled = Styled({
19+
baseButton: {
20+
color: 'red',
21+
},
22+
})
2623

27-
expect(tree).toMatchSnapshot()
28-
})
24+
const App = CreateApp(customStyled)
25+
const tree = renderer.create(<App />).toJSON()
2926

30-
it('renders correctly App with injectStyled', () => {
31-
const customStyled = Styled({
32-
root: {
33-
fontSize: 16
34-
},
35-
baseButton: {
36-
color: 'red',
37-
},
27+
expect(tree).toMatchSnapshot()
3828
})
3929

40-
const App = CreateApp(customStyled)
41-
const StyledApp = injectStyled(customStyled)(({classes}) => (
42-
<div className={classes.root}><App /></div>
43-
))
44-
const tree = renderer.create(<StyledApp />).toJSON()
45-
46-
expect(tree).toMatchSnapshot()
30+
it('renders correctly App with injectStyled', () => {
31+
const customStyled = Styled({
32+
root: {
33+
fontSize: 16
34+
},
35+
baseButton: {
36+
color: 'red',
37+
},
38+
})
39+
40+
const App = CreateApp(customStyled)
41+
const StyledApp = injectStyled(customStyled)(({classes}) => (
42+
<div className={classes.root}><App /></div>
43+
))
44+
const tree = renderer.create(<StyledApp />).toJSON()
45+
46+
expect(tree).toMatchSnapshot()
47+
})
4748
})

src/types/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
export type JssStyles = Object
22
export type JssStyle = Object
3-
export type JssStaticSheet = Object
4-
export type JssDynamicSheet = JssStaticSheet
3+
export type JssSheet = Object
54

65
export type BaseStylesType = JssStyles
76
export type ComponentStyleType = JssStyle
87
export type StyledType = Function & {
9-
mountSheets: Function,
8+
mountSheet: Function,
109
styles: JssStyles
1110
}
1211
export type StyledElementAttrsType = {tagName: string, style: ComponentStyleType}

0 commit comments

Comments
 (0)