1
+ 'use strict' ;
2
+
3
+ Object . defineProperty ( exports , "__esModule" , {
4
+ value : true
5
+ } ) ;
6
+
7
+ var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) { return typeof obj ; } : function ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ;
8
+
9
+ var _createClass = function ( ) { function defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } } return function ( Constructor , protoProps , staticProps ) { if ( protoProps ) defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) defineProperties ( Constructor , staticProps ) ; return Constructor ; } ; } ( ) ;
10
+
11
+ var _extends = Object . assign || function ( target ) { for ( var i = 1 ; i < arguments . length ; i ++ ) { var source = arguments [ i ] ; for ( var key in source ) { if ( Object . prototype . hasOwnProperty . call ( source , key ) ) { target [ key ] = source [ key ] ; } } } return target ; } ;
12
+
13
+ exports . themeable = themeable ;
14
+
15
+ var _react = require ( 'react' ) ;
16
+
17
+ var _react2 = _interopRequireDefault ( _react ) ;
18
+
19
+ var _invariant = require ( 'invariant' ) ;
20
+
21
+ var _invariant2 = _interopRequireDefault ( _invariant ) ;
22
+
23
+ function _interopRequireDefault ( obj ) { return obj && obj . __esModule ? obj : { default : obj } ; }
24
+
25
+ function _objectWithoutProperties ( obj , keys ) { var target = { } ; for ( var i in obj ) { if ( keys . indexOf ( i ) >= 0 ) continue ; if ( ! Object . prototype . hasOwnProperty . call ( obj , i ) ) continue ; target [ i ] = obj [ i ] ; } return target ; }
26
+
27
+ function _defineProperty ( obj , key , value ) { if ( key in obj ) { Object . defineProperty ( obj , key , { value : value , enumerable : true , configurable : true , writable : true } ) ; } else { obj [ key ] = value ; } return obj ; }
28
+
29
+ function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
30
+
31
+ function _possibleConstructorReturn ( self , call ) { if ( ! self ) { throw new ReferenceError ( "this hasn't been initialised - super() hasn't been called" ) ; } return call && ( typeof call === "object" || typeof call === "function" ) ? call : self ; }
32
+
33
+ function _inherits ( subClass , superClass ) { if ( typeof superClass !== "function" && superClass !== null ) { throw new TypeError ( "Super expression must either be null or a function, not " + typeof superClass ) ; } subClass . prototype = Object . create ( superClass && superClass . prototype , { constructor : { value : subClass , enumerable : false , writable : true , configurable : true } } ) ; if ( superClass ) Object . setPrototypeOf ? Object . setPrototypeOf ( subClass , superClass ) : subClass . __proto__ = superClass ; }
34
+
35
+ /**
36
+ * @typedef {Object.<string, TReactCSSThemrTheme> } TReactCSSThemrTheme
37
+ */
38
+
39
+ /**
40
+ * @typedef {{} } TReactCSSThemrOptions
41
+ * @property {String|Boolean } [composeTheme=COMPOSE_DEEPLY]
42
+ * @property {Boolean } [withRef=false]
43
+ */
44
+
45
+ var COMPOSE_DEEPLY = 'deeply' ;
46
+ var COMPOSE_SOFTLY = 'softly' ;
47
+ var DONT_COMPOSE = false ;
48
+
49
+ var DEFAULT_OPTIONS = {
50
+ composeTheme : COMPOSE_DEEPLY ,
51
+ withRef : false
52
+ } ;
53
+
54
+ var THEMR_CONFIG = typeof Symbol !== 'undefined' ? Symbol ( 'THEMR_CONFIG' ) : '__REACT_CSS_THEMR_CONFIG__' ;
55
+
56
+ /**
57
+ * Themr decorator
58
+ * @param {String|Number|Symbol } componentName - Component name
59
+ * @param {TReactCSSThemrTheme } [localTheme] - Base theme
60
+ * @param {{} } [options] - Themr options
61
+ * @returns {function(ThemedComponent:Function):Function } - ThemedComponent
62
+ */
63
+
64
+ exports . default = function ( componentName , localTheme ) {
65
+ var options = arguments . length > 2 && arguments [ 2 ] !== undefined ? arguments [ 2 ] : { } ;
66
+ return function ( ThemedComponent ) {
67
+ var _class , _temp ;
68
+
69
+ var _DEFAULT_OPTIONS$opti = _extends ( { } , DEFAULT_OPTIONS , options ) ,
70
+ optionComposeTheme = _DEFAULT_OPTIONS$opti . composeTheme ,
71
+ optionWithRef = _DEFAULT_OPTIONS$opti . withRef ;
72
+
73
+ validateComposeOption ( optionComposeTheme ) ;
74
+
75
+ var config = ThemedComponent [ THEMR_CONFIG ] ;
76
+ if ( config && config . componentName === componentName ) {
77
+ config . localTheme = themeable ( config . localTheme , localTheme ) ;
78
+ return ThemedComponent ;
79
+ }
80
+
81
+ config = {
82
+ componentName : componentName ,
83
+ localTheme : localTheme
84
+ } ;
85
+
86
+ /**
87
+ * @property {{wrappedInstance: *} } refs
88
+ */
89
+ var Themed = ( _temp = _class = function ( _Component ) {
90
+ _inherits ( Themed , _Component ) ;
91
+
92
+ function Themed ( props ) {
93
+ var _ref ;
94
+
95
+ _classCallCheck ( this , Themed ) ;
96
+
97
+ for ( var _len = arguments . length , args = Array ( _len > 1 ? _len - 1 : 0 ) , _key = 1 ; _key < _len ; _key ++ ) {
98
+ args [ _key - 1 ] = arguments [ _key ] ;
99
+ }
100
+
101
+ var _this = _possibleConstructorReturn ( this , ( _ref = Themed . __proto__ || Object . getPrototypeOf ( Themed ) ) . call . apply ( _ref , [ this , props ] . concat ( args ) ) ) ;
102
+
103
+ _this . theme_ = _this . calcTheme ( props ) ;
104
+ return _this ;
105
+ }
106
+
107
+ _createClass ( Themed , [ {
108
+ key : 'getWrappedInstance' ,
109
+ value : function getWrappedInstance ( ) {
110
+ ( 0 , _invariant2 . default ) ( optionWithRef , 'To access the wrapped instance, you need to specify ' + '{ withRef: true } as the third argument of the themr() call.' ) ;
111
+
112
+ return this . refs . wrappedInstance ;
113
+ }
114
+ } , {
115
+ key : 'getNamespacedTheme' ,
116
+ value : function getNamespacedTheme ( props ) {
117
+ var themeNamespace = props . themeNamespace ,
118
+ theme = props . theme ;
119
+
120
+ if ( ! themeNamespace ) return theme ;
121
+ if ( themeNamespace && ! theme ) throw new Error ( 'Invalid themeNamespace use in react-css-themr. ' + 'themeNamespace prop should be used only with theme prop.' ) ;
122
+
123
+ return Object . keys ( theme ) . filter ( function ( key ) {
124
+ return key . startsWith ( themeNamespace ) ;
125
+ } ) . reduce ( function ( result , key ) {
126
+ return _extends ( { } , result , _defineProperty ( { } , removeNamespace ( key , themeNamespace ) , theme [ key ] ) ) ;
127
+ } , { } ) ;
128
+ }
129
+ } , {
130
+ key : 'getThemeNotComposed' ,
131
+ value : function getThemeNotComposed ( props ) {
132
+ if ( props . theme ) return this . getNamespacedTheme ( props ) ;
133
+ if ( config . localTheme ) return config . localTheme ;
134
+ return this . getContextTheme ( ) ;
135
+ }
136
+ } , {
137
+ key : 'getContextTheme' ,
138
+ value : function getContextTheme ( ) {
139
+ return this . context . themr ? this . context . themr . theme [ config . componentName ] : { } ;
140
+ }
141
+ } , {
142
+ key : 'getTheme' ,
143
+ value : function getTheme ( props ) {
144
+ return props . composeTheme === COMPOSE_SOFTLY ? _extends ( { } , this . getContextTheme ( ) , config . localTheme , this . getNamespacedTheme ( props ) ) : themeable ( themeable ( this . getContextTheme ( ) , config . localTheme ) , this . getNamespacedTheme ( props ) ) ;
145
+ }
146
+ } , {
147
+ key : 'calcTheme' ,
148
+ value : function calcTheme ( props ) {
149
+ var composeTheme = props . composeTheme ;
150
+
151
+ return composeTheme ? this . getTheme ( props ) : this . getThemeNotComposed ( props ) ;
152
+ }
153
+ } , {
154
+ key : 'componentWillReceiveProps' ,
155
+ value : function componentWillReceiveProps ( nextProps ) {
156
+ if ( nextProps . composeTheme !== this . props . composeTheme || nextProps . theme !== this . props . theme || nextProps . themeNamespace !== this . props . themeNamespace ) {
157
+ this . theme_ = this . calcTheme ( nextProps ) ;
158
+ }
159
+ }
160
+ } , {
161
+ key : 'render' ,
162
+ value : function render ( ) {
163
+ var renderedElement = void 0 ;
164
+ //exclude themr-only props
165
+ //noinspection JSUnusedLocalSymbols
166
+
167
+ var _props = this . props ,
168
+ composeTheme = _props . composeTheme ,
169
+ themeNamespace = _props . themeNamespace ,
170
+ props = _objectWithoutProperties ( _props , [ 'composeTheme' , 'themeNamespace' ] ) ; //eslint-disable-line no-unused-vars
171
+
172
+ if ( optionWithRef ) {
173
+ renderedElement = _react2 . default . createElement ( ThemedComponent , _extends ( { } , props , {
174
+ ref : 'wrappedInstance' ,
175
+ theme : this . theme_
176
+ } ) ) ;
177
+ } else {
178
+ renderedElement = _react2 . default . createElement ( ThemedComponent , _extends ( { } , props , {
179
+ theme : this . theme_
180
+ } ) ) ;
181
+ }
182
+
183
+ return renderedElement ;
184
+ }
185
+ } ] ) ;
186
+
187
+ return Themed ;
188
+ } ( _react . Component ) , _class . displayName = 'Themed' + ThemedComponent . name , _class . contextTypes = {
189
+ themr : _react . PropTypes . object
190
+ } , _class . propTypes = _extends ( { } , ThemedComponent . propTypes , {
191
+ composeTheme : _react . PropTypes . oneOf ( [ COMPOSE_DEEPLY , COMPOSE_SOFTLY , DONT_COMPOSE ] ) ,
192
+ theme : _react . PropTypes . object ,
193
+ themeNamespace : _react . PropTypes . string
194
+ } ) , _class . defaultProps = _extends ( { } , ThemedComponent . defaultProps , {
195
+ composeTheme : optionComposeTheme
196
+ } ) , _temp ) ;
197
+
198
+
199
+ Themed [ THEMR_CONFIG ] = config ;
200
+
201
+ return Themed ;
202
+ } ;
203
+ } ;
204
+
205
+ /**
206
+ * Merges two themes by concatenating values with the same keys
207
+ * @param {TReactCSSThemrTheme } [original] - Original theme object
208
+ * @param {TReactCSSThemrTheme } [mixin] - Mixing theme object
209
+ * @returns {TReactCSSThemrTheme } - Merged resulting theme
210
+ */
211
+
212
+
213
+ function themeable ( ) {
214
+ var original = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : { } ;
215
+ var mixin = arguments [ 1 ] ;
216
+
217
+ //don't merge if no mixin is passed
218
+ if ( ! mixin ) return original ;
219
+
220
+ //merge themes by concatenating values with the same keys
221
+ return Object . keys ( mixin ) . reduce (
222
+
223
+ //merging reducer
224
+ function ( result , key ) {
225
+ var originalValue = original [ key ] ;
226
+ var mixinValue = mixin [ key ] ;
227
+
228
+ var newValue = void 0 ;
229
+
230
+ //check if values are nested objects
231
+ if ( ( typeof originalValue === 'undefined' ? 'undefined' : _typeof ( originalValue ) ) === 'object' && ( typeof mixinValue === 'undefined' ? 'undefined' : _typeof ( mixinValue ) ) === 'object' ) {
232
+ //go recursive
233
+ newValue = themeable ( originalValue , mixinValue ) ;
234
+ } else {
235
+ //either concat or take mixin value
236
+ newValue = originalValue ? originalValue + ' ' + mixinValue : mixinValue ;
237
+ }
238
+
239
+ return _extends ( { } , result , _defineProperty ( { } , key , newValue ) ) ;
240
+ } ,
241
+
242
+ //use original theme as an acc
243
+ original ) ;
244
+ }
245
+
246
+ /**
247
+ * Validates compose option
248
+ * @param {String|Boolean } composeTheme - Compose them option
249
+ * @throws
250
+ * @returns {undefined }
251
+ */
252
+ function validateComposeOption ( composeTheme ) {
253
+ if ( [ COMPOSE_DEEPLY , COMPOSE_SOFTLY , DONT_COMPOSE ] . indexOf ( composeTheme ) === - 1 ) {
254
+ throw new Error ( 'Invalid composeTheme option for react-css-themr. Valid composition options are ' + COMPOSE_DEEPLY + ', ' + COMPOSE_SOFTLY + ' and ' + DONT_COMPOSE + '. The given option was ' + composeTheme ) ;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Removes namespace from key
260
+ * @param {String } key - Key
261
+ * @param {String } themeNamespace - Theme namespace
262
+ * @returns {String } - Key
263
+ */
264
+ function removeNamespace ( key , themeNamespace ) {
265
+ var capitalized = key . substr ( themeNamespace . length ) ;
266
+ return capitalized . slice ( 0 , 1 ) . toLowerCase ( ) + capitalized . slice ( 1 ) ;
267
+ }
0 commit comments