@@ -84,7 +84,7 @@ export default (componentName, localTheme, options = {}) => (ThemedComponent) =>
84
84
getNamespacedTheme ( props ) {
85
85
const { themeNamespace, theme } = props
86
86
if ( ! themeNamespace ) return theme
87
- if ( themeNamespace && ! theme ) throw new Error ( 'Invalid themeNamespace use in react-css-themr. ' +
87
+ if ( themeNamespace && ! theme ) throw new Error ( 'Invalid themeNamespace use in react-css-themr. ' +
88
88
'themeNamespace prop should be used only with theme prop.' )
89
89
90
90
return Object . keys ( theme )
@@ -152,58 +152,85 @@ export default (componentName, localTheme, options = {}) => (ThemedComponent) =>
152
152
return Themed
153
153
}
154
154
155
- /**
156
- * Merges two themes by concatenating values with the same keys
157
- * @param {TReactCSSThemrTheme } [original] - Original theme object
158
- * @param {TReactCSSThemrTheme } [mixin] - Mixing theme object
159
- * @returns {TReactCSSThemrTheme } - Merged resulting theme
160
- */
161
- export function themeable ( original = { } , mixin ) {
162
- //don't merge if no mixin is passed
163
- if ( ! mixin ) return original
164
-
165
- //merge themes by concatenating values with the same keys
166
- return Object . keys ( mixin ) . reduce (
167
-
168
- //merging reducer
169
- ( result , key ) => {
170
-
171
- const originalValue = typeof original [ key ] !== 'function'
172
- ? ( original [ key ] || '' )
173
- : ''
174
- const mixinValue = typeof mixin [ key ] !== 'function'
175
- ? ( mixin [ key ] || '' )
176
- : ''
177
-
178
- let newValue
179
-
180
- //when you are mixing an string with a object it should fail
181
- invariant ( ! ( typeof originalValue === 'string' && typeof mixinValue === 'object' ) ,
182
- `You are merging a string "${ originalValue } " with an Object,` +
183
- 'Make sure you are passing the proper theme descriptors.'
184
- )
155
+ export function themeable ( original = { } , mixin = { } ) {
156
+ //make a copy to avoid mutations of nested objects
157
+ //also strip all functions injected by isomorphic-style-loader
158
+ const result = Object . keys ( original ) . reduce ( ( acc , key ) => {
159
+ const value = original [ key ]
160
+ if ( typeof value !== 'function' ) {
161
+ acc [ key ] = value
162
+ }
163
+ return acc
164
+ } , { } )
165
+
166
+ //traverse mixin keys and merge them to resulting theme
167
+ Object . keys ( mixin ) . forEach ( key => {
168
+ //there's no need to set any defaults here
169
+ const originalValue = result [ key ]
170
+ const mixinValue = mixin [ key ]
171
+
172
+ switch ( typeof mixinValue ) {
173
+ case 'object' : {
174
+ //possibly nested theme object
175
+ switch ( typeof originalValue ) {
176
+ case 'object' : {
177
+ //exactly nested theme object - go recursive
178
+ result [ key ] = themeable ( originalValue , mixinValue )
179
+ break
180
+ }
181
+
182
+ case 'undefined' : {
183
+ //original does not contain this nested key - just take it as is
184
+ result [ key ] = mixinValue
185
+ break
186
+ }
187
+
188
+ default : {
189
+ //can't merge an object with a non-object
190
+ throw new Error ( `You are merging object ${ key } with a non-object ${ originalValue } ` )
191
+ }
192
+ }
193
+ break
194
+ }
185
195
186
- //check if values are nested objects
187
- if ( typeof originalValue === 'object' && typeof mixinValue === 'object' ) {
188
- //go recursive
189
- newValue = themeable ( originalValue , mixinValue )
190
- } else {
191
- //either concat or take mixin value
192
- newValue = originalValue . split ( ' ' )
193
- . concat ( mixinValue . split ( ' ' ) )
194
- . filter ( ( item , pos , self ) => self . indexOf ( item ) === pos && item !== '' )
195
- . join ( ' ' )
196
+ case 'function' : {
197
+ //this handles issue when isomorphic-style-loader addes helper functions to css-module
198
+ break //just skip
196
199
}
197
200
198
- return {
199
- ...result ,
200
- [ key ] : newValue
201
+ default : {
202
+ //plain values
203
+ switch ( typeof originalValue ) {
204
+ case 'object' : {
205
+ //can't merge a non-object with an object
206
+ throw new Error ( `You are merging non-object ${ mixinValue } with an object ${ key } ` )
207
+ }
208
+
209
+ case 'undefined' : {
210
+ //mixin key is new to original theme - take it as is
211
+ result [ key ] = mixinValue
212
+ break
213
+ }
214
+ case 'function' : {
215
+ //this handles issue when isomorphic-style-loader addes helper functions to css-module
216
+ break //just skip
217
+ }
218
+
219
+ default : {
220
+ //finally we can merge
221
+ result [ key ] = originalValue . split ( ' ' )
222
+ . concat ( mixinValue . split ( ' ' ) )
223
+ . filter ( ( item , pos , self ) => self . indexOf ( item ) === pos && item !== '' )
224
+ . join ( ' ' )
225
+ break
226
+ }
227
+ }
228
+ break
201
229
}
202
- } ,
230
+ }
231
+ } )
203
232
204
- //use original theme as an acc
205
- original
206
- )
233
+ return result
207
234
}
208
235
209
236
/**
0 commit comments