forked from callstack/react-native-paper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwithTheme.js
94 lines (79 loc) · 2.23 KB
/
withTheme.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* @flow */
import React, {
PureComponent,
PropTypes,
} from 'react';
import { theme } from './ThemeProvider';
import type { Theme } from '../types/Theme';
type State = {
theme: Theme
}
export default function withTheme<T>(Comp: ReactClass<T>): ReactClass<T> {
class ThemedComponent extends PureComponent<void, *, State> {
static displayName = `withTheme(${Comp.displayName || Comp.name})`;
static propTypes = {
theme: PropTypes.object,
};
static contextTypes = {
[theme]: PropTypes.object,
};
constructor(props, context) {
super(props, context);
this.state = {
theme: this._merge(context[theme], props.theme),
};
}
state: State;
componentDidMount() {
if (typeof this.state.theme !== 'object' || this.state.theme === null) {
throw new Error(
'Couldn\'t find theme in the context or props. ' +
'You need to wrap your component in \'<ThemeProvider />\' or pass a \'theme\' prop'
);
}
}
componentWillReceiveProps(nextProps, nextContext: any) {
if (nextProps.theme !== this.props.theme || nextContext[theme] !== this.context[theme]) {
this.setState({
theme: this._merge(nextContext[theme], nextProps.theme),
});
}
}
setNativeProps(...args) {
return this._root.setNativeProps(...args);
}
_merge = (a, b) => {
if (a && b) {
return { ...a, ...b };
} else {
return a || b;
}
};
_root: any;
render() {
return (
<Comp
{...this.props}
ref={c => (this._root = c)}
theme={this.state.theme}
/>
);
}
}
// This is ugly, but we need to hoist static properties manually
for (const prop in Comp) {
if (prop !== 'displayName' && prop !== 'contextTypes') {
if (prop === 'propTypes') {
// Only the underlying component will receive the theme prop
// eslint-disable-next-line no-shadow, no-unused-vars
const { theme, ...propTypes } = Comp[prop];
/* $FlowFixMe */
ThemedComponent[prop] = propTypes;
} else {
/* $FlowFixMe */
ThemedComponent[prop] = Comp[prop];
}
}
}
return ThemedComponent;
}