1 |
|
2 |
|
3 | import {Component, PropTypes} from 'react';
|
4 |
|
5 | import StyleKeeper from './style-keeper.js';
|
6 | import resolveStyles from './resolve-styles.js';
|
7 |
|
8 | const KEYS_TO_IGNORE_WHEN_COPYING_PROPERTIES = [
|
9 | 'arguments',
|
10 | 'callee',
|
11 | 'caller',
|
12 | 'length',
|
13 | 'name',
|
14 | 'prototype',
|
15 | 'type',
|
16 | ];
|
17 |
|
18 | function copyProperties(source, target) {
|
19 | Object.getOwnPropertyNames(source).forEach(key => {
|
20 | if (
|
21 | KEYS_TO_IGNORE_WHEN_COPYING_PROPERTIES.indexOf(key) < 0 &&
|
22 | !target.hasOwnProperty(key)
|
23 | ) {
|
24 | const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
25 | Object.defineProperty(target, key, descriptor);
|
26 | }
|
27 | });
|
28 | }
|
29 |
|
30 | function isStateless(component: Function): boolean {
|
31 | return !component.render &&
|
32 | !(component.prototype && component.prototype.render);
|
33 | }
|
34 |
|
35 | export default function enhanceWithRadium(
|
36 | configOrComposedComponent: Class<any> | constructor | Function | Object,
|
37 | config?: Object = {},
|
38 | ): constructor {
|
39 | if (typeof configOrComposedComponent !== 'function') {
|
40 | const newConfig = {...config, ...configOrComposedComponent};
|
41 | return function(configOrComponent) {
|
42 | return enhanceWithRadium(configOrComponent, newConfig);
|
43 | };
|
44 | }
|
45 |
|
46 | const component: Function = configOrComposedComponent;
|
47 | let ComposedComponent: constructor = component;
|
48 |
|
49 | // Handle stateless components
|
50 | if (isStateless(ComposedComponent)) {
|
51 | ComposedComponent = class extends Component {
|
52 | state: Object;
|
53 |
|
54 | render() {
|
55 | return component(this.props, this.context);
|
56 | }
|
57 | };
|
58 | ComposedComponent.displayName = component.displayName || component.name;
|
59 | }
|
60 |
|
61 | class RadiumEnhancer extends ComposedComponent {
|
62 | static _isRadiumEnhanced = true;
|
63 |
|
64 | state: Object;
|
65 |
|
66 | _radiumMediaQueryListenersByQuery: {
|
67 | [query: string]: {remove: () => void},
|
68 | };
|
69 | _radiumMouseUpListener: {remove: () => void};
|
70 | _radiumIsMounted: boolean;
|
71 |
|
72 | constructor() {
|
73 | super(...arguments);
|
74 |
|
75 | this.state = this.state || {};
|
76 | this.state._radiumStyleState = {};
|
77 | this._radiumIsMounted = true;
|
78 | }
|
79 |
|
80 | componentWillUnmount() {
|
81 | if (super.componentWillUnmount) {
|
82 | super.componentWillUnmount();
|
83 | }
|
84 |
|
85 | this._radiumIsMounted = false;
|
86 |
|
87 | if (this._radiumMouseUpListener) {
|
88 | this._radiumMouseUpListener.remove();
|
89 | }
|
90 |
|
91 | if (this._radiumMediaQueryListenersByQuery) {
|
92 | Object.keys(this._radiumMediaQueryListenersByQuery).forEach(
|
93 | function(query) {
|
94 | this._radiumMediaQueryListenersByQuery[query].remove();
|
95 | },
|
96 | this,
|
97 | );
|
98 | }
|
99 | }
|
100 |
|
101 | getChildContext() {
|
102 | const superChildContext = super.getChildContext
|
103 | ? super.getChildContext()
|
104 | : {};
|
105 |
|
106 | if (!this.props.radiumConfig) {
|
107 | return superChildContext;
|
108 | }
|
109 |
|
110 | const newContext = {...superChildContext};
|
111 |
|
112 | if (this.props.radiumConfig) {
|
113 | newContext._radiumConfig = this.props.radiumConfig;
|
114 | }
|
115 |
|
116 | return newContext;
|
117 | }
|
118 |
|
119 | render() {
|
120 | const renderedElement = super.render();
|
121 | let currentConfig = this.props.radiumConfig ||
|
122 | this.context._radiumConfig ||
|
123 | config;
|
124 |
|
125 | if (config && currentConfig !== config) {
|
126 | currentConfig = {
|
127 | ...config,
|
128 | ...currentConfig,
|
129 | };
|
130 | }
|
131 |
|
132 | return resolveStyles(this, renderedElement, currentConfig);
|
133 | }
|
134 | }
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | copyProperties(component, RadiumEnhancer);
|
141 |
|
142 | if (process.env.NODE_ENV !== 'production') {
|
143 |
|
144 |
|
145 |
|
146 | copyProperties(ComposedComponent.prototype, RadiumEnhancer.prototype);
|
147 | }
|
148 |
|
149 | if (RadiumEnhancer.propTypes && RadiumEnhancer.propTypes.style) {
|
150 | RadiumEnhancer.propTypes = {
|
151 | ...RadiumEnhancer.propTypes,
|
152 | style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
153 | };
|
154 | }
|
155 |
|
156 | RadiumEnhancer.displayName = component.displayName ||
|
157 | component.name ||
|
158 | 'Component';
|
159 |
|
160 | RadiumEnhancer.contextTypes = {
|
161 | ...RadiumEnhancer.contextTypes,
|
162 | _radiumConfig: PropTypes.object,
|
163 | _radiumStyleKeeper: PropTypes.instanceOf(StyleKeeper),
|
164 | };
|
165 |
|
166 | RadiumEnhancer.childContextTypes = {
|
167 | ...RadiumEnhancer.childContextTypes,
|
168 | _radiumConfig: PropTypes.object,
|
169 | _radiumStyleKeeper: PropTypes.instanceOf(StyleKeeper),
|
170 | };
|
171 |
|
172 | return RadiumEnhancer;
|
173 | }
|