Skip to content
This repository was archived by the owner on Aug 19, 2022. It is now read-only.

Commit 8a2f7d7

Browse files
Merge pull request #1004 from stevenmusumeche/task/refactor-enhancer
Refactor enhancer
2 parents 9d102f6 + 12f9b09 commit 8a2f7d7

File tree

2 files changed

+120
-88
lines changed

2 files changed

+120
-88
lines changed

src/.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"bracketSpacing": false,
3+
"singleQuote": true
4+
}

src/enhancer.js

Lines changed: 116 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -52,61 +52,40 @@ function isNativeClass(component: Function): boolean {
5252
/^\s*class\s+/.test(component.toString());
5353
}
5454

55-
export default function enhanceWithRadium(
56-
configOrComposedComponent: Class<any> | constructor | Function | Object,
57-
config?: Object = {}
58-
): constructor {
59-
if (typeof configOrComposedComponent !== 'function') {
60-
const newConfig = {...config, ...configOrComposedComponent};
61-
return function(configOrComponent) {
62-
return enhanceWithRadium(configOrComponent, newConfig);
63-
};
64-
}
65-
66-
const component: Function = configOrComposedComponent;
67-
let ComposedComponent: constructor = component;
68-
69-
// Radium is transpiled in npm, so it isn't really using es6 classes at
70-
// runtime. However, the user of Radium might be. In this case we have
71-
// to maintain forward compatibility with native es classes.
72-
if (isNativeClass(ComposedComponent)) {
73-
ComposedComponent = (function(OrigComponent): constructor {
74-
function NewComponent() {
75-
// Use Reflect.construct to simulate 'new'
76-
const obj = Reflect.construct(
77-
OrigComponent,
78-
arguments,
79-
this.constructor
80-
);
81-
82-
return obj;
83-
}
84-
85-
// $FlowFixMe
86-
Reflect.setPrototypeOf(NewComponent.prototype, OrigComponent.prototype);
87-
// $FlowFixMe
88-
Reflect.setPrototypeOf(NewComponent, OrigComponent);
89-
90-
return NewComponent;
91-
})(ComposedComponent);
92-
}
93-
94-
// Handle stateless components
95-
if (isStateless(ComposedComponent)) {
96-
ComposedComponent = class extends Component<any, Object> {
97-
render() {
98-
return component(this.props, this.context);
99-
}
100-
};
101-
102-
ComposedComponent.displayName = component.displayName || component.name;
103-
}
104-
105-
// Shallow copy composed if still original (we may mutate later).
106-
if (ComposedComponent === component) {
107-
ComposedComponent = class extends ComposedComponent {};
108-
}
55+
// Handle es7 arrow functions on React class method names by detecting
56+
// and transfering the instance method to original class prototype.
57+
// (Using a copy of the class).
58+
// See: https://github.com/FormidableLabs/radium/issues/738
59+
function copyArrowFuncs(enhancedSelf: Object, ComposedComponent: constructor) {
60+
RADIUM_METHODS.forEach(name => {
61+
const thisDesc = Object.getOwnPropertyDescriptor(enhancedSelf, name);
62+
const thisMethod = (thisDesc || {}).value;
63+
// Only care if have instance method.
64+
if (!thisMethod) {
65+
return;
66+
}
67+
const radiumDesc = Object.getOwnPropertyDescriptor(RADIUM_PROTO, name);
68+
const radiumProtoMethod = (radiumDesc || {}).value;
69+
const superProtoMethod = ComposedComponent.prototype[name];
70+
// Allow transfer when:
71+
// 1. have an instance method
72+
// 2. the super class prototype doesn't have any method
73+
// 3. it is not already the radium prototype's
74+
if (!superProtoMethod && thisMethod !== radiumProtoMethod) {
75+
// Transfer dynamic render component to Component prototype (copy).
76+
Object.defineProperty(ComposedComponent.prototype, name, thisDesc);
77+
// Remove instance property, leaving us to have a contrived
78+
// inheritance chain of (1) radium, (2) superclass.
79+
delete enhancedSelf[name];
80+
}
81+
});
82+
}
10983

84+
function createEnhancedComponent(
85+
origComponent: Function,
86+
ComposedComponent: constructor,
87+
config?: Object
88+
) {
11089
class RadiumEnhancer extends ComposedComponent {
11190
static _isRadiumEnhanced = true;
11291

@@ -129,36 +108,8 @@ export default function enhanceWithRadium(
129108

130109
const self: Object = this;
131110

132-
// Handle es7 arrow functions on React class method names by detecting
133-
// and transfering the instance method to original class prototype.
134-
// (Using a copy of the class).
135-
// See: https://github.com/FormidableLabs/radium/issues/738
136-
RADIUM_METHODS.forEach(name => {
137-
const thisDesc = Object.getOwnPropertyDescriptor(self, name);
138-
const thisMethod = (thisDesc || {}).value;
139-
140-
// Only care if have instance method.
141-
if (!thisMethod) {
142-
return;
143-
}
144-
145-
const radiumDesc = Object.getOwnPropertyDescriptor(RADIUM_PROTO, name);
146-
const radiumProtoMethod = radiumDesc.value;
147-
const superProtoMethod = ComposedComponent.prototype[name];
148-
149-
// Allow transfer when:
150-
// 1. have an instance method
151-
// 2. the super class prototype doesn't have any method
152-
// 3. it is not already the radium prototype's
153-
if (!superProtoMethod && thisMethod !== radiumProtoMethod) {
154-
// Transfer dynamic render component to Component prototype (copy).
155-
Object.defineProperty(ComposedComponent.prototype, name, thisDesc);
156-
157-
// Remove instance property, leaving us to have a contrived
158-
// inheritance chain of (1) radium, (2) superclass.
159-
delete self[name];
160-
}
161-
});
111+
// Handle es7 arrow functions on React class method
112+
copyArrowFuncs(self, ComposedComponent);
162113
}
163114

164115
componentWillUnmount() {
@@ -191,7 +142,7 @@ export default function enhanceWithRadium(
191142
return superChildContext;
192143
}
193144

194-
const newContext = {...superChildContext};
145+
const newContext: Object = {...superChildContext};
195146

196147
if (this.props.radiumConfig) {
197148
newContext._radiumConfig = this.props.radiumConfig;
@@ -213,6 +164,7 @@ export default function enhanceWithRadium(
213164
};
214165
}
215166

167+
// do the style and interaction work
216168
const {extraStateKeyMap, element} = resolveStyles(
217169
this,
218170
renderedElement,
@@ -255,7 +207,7 @@ export default function enhanceWithRadium(
255207
// with IE <10 any static properties of the superclass aren't inherited and
256208
// so need to be manually populated.
257209
// See http://babeljs.io/docs/advanced/caveats/#classes-10-and-below-
258-
copyProperties(component, RadiumEnhancer);
210+
copyProperties(origComponent, RadiumEnhancer);
259211

260212
if (process.env.NODE_ENV !== 'production') {
261213
// This also fixes React Hot Loader by exposing the original components top
@@ -264,17 +216,20 @@ export default function enhanceWithRadium(
264216
copyProperties(ComposedComponent.prototype, RadiumEnhancer.prototype);
265217
}
266218

219+
// add Radium propTypes to enhanced component's propTypes
267220
if (RadiumEnhancer.propTypes && RadiumEnhancer.propTypes.style) {
268221
RadiumEnhancer.propTypes = {
269222
...RadiumEnhancer.propTypes,
270223
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
271224
};
272225
}
273226

274-
RadiumEnhancer.displayName = component.displayName ||
275-
component.name ||
227+
// copy display name to enhanced component
228+
RadiumEnhancer.displayName = origComponent.displayName ||
229+
origComponent.name ||
276230
'Component';
277231

232+
// handle context
278233
RadiumEnhancer.contextTypes = {
279234
...RadiumEnhancer.contextTypes,
280235
_radiumConfig: PropTypes.object,
@@ -289,3 +244,76 @@ export default function enhanceWithRadium(
289244

290245
return RadiumEnhancer;
291246
}
247+
248+
function createComposedFromStatelessFunc(
249+
ComposedComponent: constructor,
250+
component: Function
251+
) {
252+
ComposedComponent = class extends Component<any, Object> {
253+
render() {
254+
return component(this.props, this.context);
255+
}
256+
};
257+
ComposedComponent.displayName = component.displayName || component.name;
258+
return ComposedComponent;
259+
}
260+
261+
function createComposedFromNativeClass(ComposedComponent: constructor) {
262+
ComposedComponent = (function(OrigComponent): constructor {
263+
function NewComponent() {
264+
// Use Reflect.construct to simulate 'new'
265+
const obj = Reflect.construct(OrigComponent, arguments, this.constructor);
266+
return obj;
267+
}
268+
// $FlowFixMe
269+
Reflect.setPrototypeOf(NewComponent.prototype, OrigComponent.prototype);
270+
// $FlowFixMe
271+
Reflect.setPrototypeOf(NewComponent, OrigComponent);
272+
return NewComponent;
273+
})(ComposedComponent);
274+
return ComposedComponent;
275+
}
276+
277+
export default function enhanceWithRadium(
278+
configOrComposedComponent: Class<any> | constructor | Function | Object,
279+
config?: Object = {}
280+
): constructor {
281+
if (typeof configOrComposedComponent !== 'function') {
282+
return createFactoryFromConfig(config, configOrComposedComponent);
283+
}
284+
285+
const origComponent: Function = configOrComposedComponent;
286+
let ComposedComponent: constructor = origComponent;
287+
288+
// Radium is transpiled in npm, so it isn't really using es6 classes at
289+
// runtime. However, the user of Radium might be. In this case we have
290+
// to maintain forward compatibility with native es classes.
291+
if (isNativeClass(ComposedComponent)) {
292+
ComposedComponent = createComposedFromNativeClass(ComposedComponent);
293+
}
294+
295+
// Handle stateless components
296+
if (isStateless(ComposedComponent)) {
297+
ComposedComponent = createComposedFromStatelessFunc(
298+
ComposedComponent,
299+
origComponent
300+
);
301+
}
302+
303+
// Shallow copy composed if still original (we may mutate later).
304+
if (ComposedComponent === origComponent) {
305+
ComposedComponent = class extends ComposedComponent {};
306+
}
307+
308+
return createEnhancedComponent(origComponent, ComposedComponent, config);
309+
}
310+
311+
function createFactoryFromConfig(
312+
config: Object,
313+
configOrComposedComponent: Object
314+
) {
315+
const newConfig = {...config, ...configOrComposedComponent};
316+
return function(configOrComponent) {
317+
return enhanceWithRadium(configOrComponent, newConfig);
318+
};
319+
}

0 commit comments

Comments
 (0)