-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathstyled.js
More file actions
99 lines (75 loc) · 2.77 KB
/
styled.js
File metadata and controls
99 lines (75 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import {Component, createElement} from 'react'
import filterProps from './utils/filterProps'
import composeClasses from './utils/composeClasses'
import generateTagName from './utils/generateTagName'
import getSeparatedStyles from './utils/getSeparatedStyles'
import type {
JssSheet,
ComponentStyleType,
StyledElementPropsType
} from './types'
type StyledArgs = {
tagName: string,
elementStyle: ComponentStyleType,
mountSheet: Function
}
const styled = ({tagName, elementStyle, mountSheet}: StyledArgs) => {
const {dynamicStyle, staticStyle} = getSeparatedStyles(elementStyle)
const staticTagName = staticStyle && generateTagName(tagName)
const availableDynamicTagNames = []
const classMap = {}
return class StyledElement extends Component {
static tagName: string = tagName
static style: ComponentStyleType = elementStyle
props: StyledElementPropsType
dynamicTagName = ''
sheet: JssSheet
constructor(props: StyledElementPropsType) {
super(props)
if (!this.dynamicTagName && dynamicStyle) {
this.dynamicTagName = availableDynamicTagNames.pop() || generateTagName(tagName)
}
}
componentWillMount() {
this.sheet = this.sheet || mountSheet()
const rulesIndex = this.sheet.rules.index
const rulesTotal = rulesIndex.length
if (staticStyle && !this.sheet.getRule(staticTagName)) {
this.sheet.addRule(staticTagName, staticStyle)
}
if (!dynamicStyle) return
if (!this.sheet.getRule(this.dynamicTagName)) {
this.sheet.addRule(this.dynamicTagName, dynamicStyle)
}
classMap[this.dynamicTagName] = classMap[this.dynamicTagName] || rulesIndex.slice(rulesTotal)
this.updateSheet(this.props)
}
componentWillReceiveProps(nextProps: StyledElementPropsType) {
if (dynamicStyle) this.updateSheet(nextProps)
}
componentWillUnmount() {
availableDynamicTagNames.push(this.dynamicTagName)
}
updateSheet(props: StyledElementPropsType) {
let rule
let ruleIndex = 0
// nested styles become to flatten rules, so we need to update each nested rule
for (ruleIndex; ruleIndex < classMap[this.dynamicTagName].length; ruleIndex++) {
rule = classMap[this.dynamicTagName][ruleIndex]
if (rule.name) this.sheet.update(rule.name, props)
if (rule.rules) rule.rules.update(props)
}
}
render() {
const {children, className, ...attrs} = this.props
const props = filterProps(attrs)
const tagClass = composeClasses([
staticTagName && this.sheet.classes[staticTagName],
this.dynamicTagName && this.sheet.classes[this.dynamicTagName],
className
])
return createElement(tagName, {...props, className: tagClass}, children)
}
}
}
export default styled