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