-
-
Notifications
You must be signed in to change notification settings - Fork 130
/
Copy pathsheet.js
124 lines (110 loc) · 3.03 KB
/
sheet.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import {StyleSheet} from 'react-native';
import Style from './style';
import utils from './utils';
import vars from './replacers/vars';
import mediaQueries from './replacers/media-queries';
export default class {
/**
* Constructor
* @param {Object} source
*/
constructor(source) {
this.source = source;
this.result = {};
this.cache = new Map(); // cache result for each theme
this.nativeSheet = {};
this.globalVars = null;
this.localVars = null;
this.allVars = null;
this.processedSource = null;
}
/**
* Calculates sheet and update result
* @param {Object} globalVars
*/
calc(globalVars) {
this.globalVars = globalVars;
this.clearResult();
if (this.hasCache()) {
this.applyCache();
} else {
this.processMediaQueries();
this.calcVars();
this.calcStyles();
this.calcNative();
this.storeCache();
}
return this.getResult();
}
processMediaQueries() {
this.processedSource = mediaQueries.process(this.source);
}
calcVars() {
const rawLocalVars = vars.extract(this.processedSource);
if (rawLocalVars) {
this.localVars = new Style(rawLocalVars, [rawLocalVars, this.globalVars]).calc().calculatedVars;
Object.assign(this.result, this.localVars);
} else {
this.localVars = null;
}
this.allVars = [this.localVars, this.globalVars].filter(Boolean);
}
calcStyles() {
const extractedStyles = utils.excludeKeys(this.processedSource, this.localVars);
Object.keys(extractedStyles).forEach(key => {
let styles = extractedStyles[key];
if (typeof styles === 'function') {
styles = styles();
}
if (styles && typeof styles === 'object') {
this.calcStyle(key, styles);
} else {
// copy primitive values to result as-is
this.result[key] = styles;
}
});
}
calcStyle(key, styleProps) {
const style = new Style(styleProps, this.allVars);
const {calculatedProps, calculatedVars} = style.calc();
const merged = Object.assign({}, calculatedVars, calculatedProps);
if (key.charAt(0) === '_') {
this.result[key] = merged;
} else {
this.result['_' + key] = merged;
this.nativeSheet[key] = calculatedProps;
}
}
calcNative() {
if (Object.keys(this.nativeSheet).length) {
const rnStyleSheet = StyleSheet.create(this.nativeSheet);
Object.assign(this.result, rnStyleSheet);
}
}
getResult() {
return this.result;
}
clearResult() {
Object.keys(this.result).forEach(key => delete this.result[key]);
}
hasCache() {
const key = this.getCacheKey();
return key && this.cache.has(key);
}
applyCache() {
const cachedResult = this.cache.get(this.getCacheKey());
Object.assign(this.result, cachedResult);
}
storeCache() {
const key = this.getCacheKey();
if (key) {
this.cache.set(key, Object.assign({}, this.result));
}
}
clearCache() {
this.cache.clear();
}
getCacheKey() {
return this.globalVars && this.globalVars.$theme;
}
}