@@ -43,162 +43,174 @@ export default (ComponentStyle: Function, constructWithOptions: Function) => {
43
43
: componentId
44
44
}
45
45
46
- class BaseStyledComponent extends Component {
47
- static target : Target
48
- static styledComponentId : string
49
- static attrs : Object
50
- static componentStyle : Object
51
- static warnTooManyClasses : Function
52
-
53
- attrs = { }
54
- state = {
55
- theme : null ,
56
- generatedClassName : '' ,
57
- }
58
- unsubscribeId : number = - 1
59
-
60
- unsubscribeFromContext ( ) {
61
- if ( this . unsubscribeId !== - 1 ) {
62
- this . context [ CHANNEL_NEXT ] . unsubscribe ( this . unsubscribeId )
46
+ const createBaseStyledComponent = ( options : Object ) => {
47
+ class BaseStyledComponent extends Component {
48
+ static target : Target
49
+ static styledComponentId : string
50
+ static attrs : Object
51
+ static componentStyle : Object
52
+ static warnTooManyClasses : Function
53
+
54
+ attrs = { }
55
+ state = {
56
+ theme : null ,
57
+ generatedClassName : '' ,
63
58
}
64
- }
59
+ unsubscribeId : number = - 1
65
60
66
- buildExecutionContext ( theme : any , props : any ) {
67
- const { attrs } = this . constructor
68
- const context = { ...props , theme }
69
- if ( attrs === undefined ) {
70
- return context
61
+ unsubscribeFromContext ( ) {
62
+ if ( this . unsubscribeId !== - 1 ) {
63
+ this . context [ CHANNEL_NEXT ] . unsubscribe ( this . unsubscribeId )
64
+ }
71
65
}
72
66
73
- this . attrs = Object . keys ( attrs ) . reduce ( ( acc , key ) => {
74
- const attr = attrs [ key ]
75
- // eslint-disable-next-line no-param-reassign
76
- acc [ key ] = typeof attr === 'function' ? attr ( context ) : attr
77
- return acc
78
- } , { } )
79
-
80
- return { ...context , ...this . attrs }
81
- }
82
-
83
- generateAndInjectStyles ( theme : any , props : any ) {
84
- const { attrs, componentStyle, warnTooManyClasses } = this . constructor
85
- const styleSheet = this . context [ CONTEXT_KEY ] || StyleSheet . instance
86
-
87
- // staticaly styled-components don't need to build an execution context object,
88
- // and shouldn't be increasing the number of class names
89
- if ( componentStyle . isStatic && attrs === undefined ) {
90
- return componentStyle . generateAndInjectStyles ( STATIC_EXECUTION_CONTEXT , styleSheet )
91
- } else {
92
- const executionContext = this . buildExecutionContext ( theme , props )
93
- const className = componentStyle . generateAndInjectStyles ( executionContext , styleSheet )
67
+ buildExecutionContext ( theme : any , props : any ) {
68
+ const { attrs } = this . constructor
69
+ const context = { ...props , theme }
70
+ if ( attrs === undefined ) {
71
+ return context
72
+ }
94
73
95
- if ( warnTooManyClasses !== undefined ) warnTooManyClasses ( className )
74
+ this . attrs = Object . keys ( attrs ) . reduce ( ( acc , key ) => {
75
+ const attr = attrs [ key ]
76
+ // eslint-disable-next-line no-param-reassign
77
+ acc [ key ] = typeof attr === 'function' ? attr ( context ) : attr
78
+ return acc
79
+ } , { } )
96
80
97
- return className
81
+ return { ... context , ... this . attrs }
98
82
}
99
- }
100
83
101
- componentWillMount ( ) {
102
- const { componentStyle } = this . constructor
103
- const styledContext = this . context [ CHANNEL_NEXT ]
104
-
105
- // If this is a staticaly-styled component, we don't need to the theme
106
- // to generate or build styles.
107
- if ( componentStyle . isStatic ) {
108
- const generatedClassName = this . generateAndInjectStyles (
109
- STATIC_EXECUTION_CONTEXT ,
110
- this . props ,
111
- )
112
- this . setState ( { generatedClassName } )
113
- // If there is a theme in the context, subscribe to the event emitter. This
114
- // is necessary due to pure components blocking context updates, this circumvents
115
- // that by updating when an event is emitted
116
- } else if ( styledContext !== undefined ) {
117
- const { subscribe } = styledContext
118
- this . unsubscribeId = subscribe ( nextTheme => {
119
- // This will be called once immediately
120
- const theme = determineTheme ( this . props , nextTheme , this . constructor . defaultProps )
121
- const generatedClassName = this . generateAndInjectStyles ( theme , this . props )
122
-
123
- this . setState ( { theme, generatedClassName } )
124
- } )
125
- } else {
126
- // eslint-disable-next-line react/prop-types
127
- const theme = this . props . theme || { }
128
- const generatedClassName = this . generateAndInjectStyles (
129
- theme ,
130
- this . props ,
131
- )
132
- this . setState ( { theme, generatedClassName } )
84
+ generateAndInjectStyles ( theme : any , props : any ) {
85
+ const { attrs, componentStyle, warnTooManyClasses } = this . constructor
86
+ const styleSheet = this . context [ CONTEXT_KEY ] || StyleSheet . instance
87
+
88
+ // staticaly styled-components don't need to build an execution context object,
89
+ // and shouldn't be increasing the number of class names
90
+ if ( componentStyle . isStatic && attrs === undefined ) {
91
+ return componentStyle . generateAndInjectStyles (
92
+ STATIC_EXECUTION_CONTEXT ,
93
+ styleSheet ,
94
+ options ,
95
+ )
96
+ } else {
97
+ const executionContext = this . buildExecutionContext ( theme , props )
98
+ const className = componentStyle . generateAndInjectStyles (
99
+ executionContext ,
100
+ styleSheet ,
101
+ options ,
102
+ )
103
+
104
+ if ( warnTooManyClasses !== undefined ) warnTooManyClasses ( className )
105
+
106
+ return className
107
+ }
133
108
}
134
- }
135
109
136
- componentWillReceiveProps ( nextProps : { theme ?: Theme , [ key : string ] : any } ) {
137
- // If this is a staticaly-styled component, we don't need to listen to
138
- // props changes to update styles
139
- const { componentStyle } = this . constructor
140
- if ( componentStyle . isStatic ) {
141
- return
110
+ componentWillMount ( ) {
111
+ const { componentStyle } = this . constructor
112
+ const styledContext = this . context [ CHANNEL_NEXT ]
113
+
114
+ // If this is a staticaly-styled component, we don't need to the theme
115
+ // to generate or build styles.
116
+ if ( componentStyle . isStatic ) {
117
+ const generatedClassName = this . generateAndInjectStyles (
118
+ STATIC_EXECUTION_CONTEXT ,
119
+ this . props ,
120
+ )
121
+ this . setState ( { generatedClassName } )
122
+ // If there is a theme in the context, subscribe to the event emitter. This
123
+ // is necessary due to pure components blocking context updates, this circumvents
124
+ // that by updating when an event is emitted
125
+ } else if ( styledContext !== undefined ) {
126
+ const { subscribe } = styledContext
127
+ this . unsubscribeId = subscribe ( nextTheme => {
128
+ // This will be called once immediately
129
+ const theme = determineTheme ( this . props , nextTheme , this . constructor . defaultProps )
130
+ const generatedClassName = this . generateAndInjectStyles ( theme , this . props )
131
+
132
+ this . setState ( { theme, generatedClassName } )
133
+ } )
134
+ } else {
135
+ // eslint-disable-next-line react/prop-types
136
+ const theme = this . props . theme || { }
137
+ const generatedClassName = this . generateAndInjectStyles (
138
+ theme ,
139
+ this . props ,
140
+ )
141
+ this . setState ( { theme, generatedClassName } )
142
+ }
142
143
}
143
144
144
- this . setState ( ( oldState ) => {
145
- const theme = determineTheme ( nextProps , oldState . theme , this . constructor . defaultProps )
146
- const generatedClassName = this . generateAndInjectStyles ( theme , nextProps )
147
-
148
- return { theme, generatedClassName }
149
- } )
150
- }
151
-
152
- componentWillUnmount ( ) {
153
- this . unsubscribeFromContext ( )
154
- }
155
-
156
- render ( ) {
157
- // eslint-disable-next-line react/prop-types
158
- const { innerRef } = this . props
159
- const { generatedClassName } = this . state
160
- const { styledComponentId , target } = this . constructor
145
+ componentWillReceiveProps ( nextProps : { theme ?: Theme , [ key : string ] : any } ) {
146
+ // If this is a staticaly-styled component, we don't need to listen to
147
+ // props changes to update styles
148
+ const { componentStyle } = this . constructor
149
+ if ( componentStyle . isStatic ) {
150
+ return
151
+ }
161
152
162
- const isTargetTag = isTag ( target )
153
+ this . setState ( ( oldState ) => {
154
+ const theme = determineTheme ( nextProps , oldState . theme , this . constructor . defaultProps )
155
+ const generatedClassName = this . generateAndInjectStyles ( theme , nextProps )
163
156
164
- const className = [
165
- // eslint-disable-next-line react/prop-types
166
- this . props . className ,
167
- styledComponentId ,
168
- this . attrs . className ,
169
- generatedClassName ,
170
- ] . filter ( Boolean ) . join ( ' ' )
171
-
172
- const baseProps = {
173
- ...this . attrs ,
174
- className,
157
+ return { theme, generatedClassName }
158
+ } )
175
159
}
176
160
177
- if ( isStyledComponent ( target ) ) {
178
- baseProps . innerRef = innerRef
179
- } else {
180
- baseProps . ref = innerRef
161
+ componentWillUnmount ( ) {
162
+ this . unsubscribeFromContext ( )
181
163
}
182
164
183
- const propsForElement = Object
184
- . keys ( this . props )
185
- . reduce ( ( acc , propName ) => {
186
- // Don't pass through non HTML tags through to HTML elements
187
- // always omit innerRef
188
- if (
189
- propName !== 'innerRef' &&
190
- propName !== 'className' &&
191
- ( ! isTargetTag || validAttr ( propName ) )
192
- ) {
193
- // eslint-disable-next-line no-param-reassign
194
- acc [ propName ] = this . props [ propName ]
195
- }
165
+ render ( ) {
166
+ // eslint-disable-next-line react/prop-types
167
+ const { innerRef } = this . props
168
+ const { generatedClassName } = this . state
169
+ const { styledComponentId , target } = this . constructor
170
+
171
+ const isTargetTag = isTag ( target )
172
+
173
+ const className = [
174
+ // eslint-disable-next-line react/prop-types
175
+ this . props . className ,
176
+ styledComponentId ,
177
+ this . attrs . className ,
178
+ generatedClassName ,
179
+ ] . filter ( Boolean ) . join ( ' ' )
180
+
181
+ const baseProps = {
182
+ ...this . attrs ,
183
+ className,
184
+ }
196
185
197
- return acc
198
- } , baseProps )
186
+ if ( isStyledComponent ( target ) ) {
187
+ baseProps . innerRef = innerRef
188
+ } else {
189
+ baseProps . ref = innerRef
190
+ }
199
191
200
- return createElement ( target , propsForElement )
192
+ const propsForElement = Object
193
+ . keys ( this . props )
194
+ . reduce ( ( acc , propName ) => {
195
+ // Don't pass through non HTML tags through to HTML elements
196
+ // always omit innerRef
197
+ if (
198
+ propName !== 'innerRef' &&
199
+ propName !== 'className' &&
200
+ ( ! isTargetTag || validAttr ( propName ) )
201
+ ) {
202
+ // eslint-disable-next-line no-param-reassign
203
+ acc [ propName ] = this . props [ propName ]
204
+ }
205
+
206
+ return acc
207
+ } , baseProps )
208
+
209
+ return createElement ( target , propsForElement )
210
+ }
201
211
}
212
+
213
+ return BaseStyledComponent
202
214
}
203
215
204
216
const createStyledComponent = (
@@ -209,7 +221,7 @@ export default (ComponentStyle: Function, constructWithOptions: Function) => {
209
221
const {
210
222
displayName = isTag ( target ) ? `styled.${ target } ` : `Styled(${ getComponentName ( target ) } )` ,
211
223
componentId = generateId ( options . displayName , options . parentComponentId ) ,
212
- ParentComponent = BaseStyledComponent ,
224
+ ParentComponent = createBaseStyledComponent ( options ) ,
213
225
rules : extendingRules ,
214
226
attrs,
215
227
} = options
0 commit comments