/
ThemeProvider.tsx
92 lines (76 loc) · 2.23 KB
/
ThemeProvider.tsx
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
import * as React from 'react';
import isEqual from 'lodash/isEqual';
import {autobind} from '@shopify/javascript-utilities/decorators';
import {setColors} from './utils';
import {Theme, ThemeProviderContext, THEME_CONTEXT_TYPES} from './types';
export interface Props {
/** Custom logos and colors provided to select components */
theme: Theme;
/** The content to display */
children?: React.ReactNode;
}
const defaultTheme = {
'--top-bar-background': '#00848e',
'--top-bar-color': '#f9fafb',
'--top-bar-background-lighter': '#1d9ba4',
};
export default class ThemeProvider extends React.Component<Props> {
static childContextTypes = THEME_CONTEXT_TYPES;
public themeContext: ThemeProviderContext;
private subscriptions: {(): void}[] = [];
private colors: string[][] | undefined;
constructor(props: Props) {
super(props);
this.themeContext = setThemeContext(
this.props.theme,
this.subscribe,
this.unsubscribe,
);
this.colors = setColors(props.theme);
}
componentWillReceiveProps({theme}: Props) {
if (isEqual(theme, this.props.theme)) {
return;
}
this.themeContext = setThemeContext(
theme,
this.subscribe,
this.unsubscribe,
);
this.subscriptions.forEach((subscriberCallback) => subscriberCallback());
this.colors = setColors(theme);
}
getChildContext() {
return this.themeContext;
}
render() {
const styles = this.createStyles() || defaultTheme;
return <div style={styles}>{React.Children.only(this.props.children)}</div>;
}
@autobind
subscribe(callback: () => void) {
this.subscriptions.push(callback);
}
@autobind
unsubscribe(callback: () => void) {
this.subscriptions = this.subscriptions.filter(
(subscription) => subscription !== callback,
);
}
createStyles() {
return this.colors
? this.colors.reduce(
(state, [key, value]) => ({...state, [key]: value}),
{},
)
: null;
}
}
function setThemeContext(
ctx: Theme,
subscribe: (callback: () => void) => void,
unsubscribe: (callback: () => void) => void,
): ThemeProviderContext {
const {colors, logo = null, ...rest} = ctx;
return {polarisTheme: {logo, subscribe, unsubscribe, ...rest}};
}