forked from FormidableLabs/radium
-
Notifications
You must be signed in to change notification settings - Fork 1
/
merge-styles.js
53 lines (46 loc) · 1.41 KB
/
merge-styles.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
export function isNestedStyle(value) {
// Don't merge objects overriding toString, since they should be converted
// to string values.
return (
value &&
value.constructor === Object &&
value.toString === Object.prototype.toString
);
}
// Merge style objects. Deep merge plain object values.
export function mergeStyles(styles) {
const result = {};
styles.forEach(style => {
if (!style || typeof style !== 'object') {
return;
}
if (Array.isArray(style)) {
style = mergeStyles(style);
}
Object.keys(style).forEach(key => {
// Simple case, nothing nested
if (!isNestedStyle(style[key]) || !isNestedStyle(result[key])) {
result[key] = style[key];
return;
}
// If nested media, don't merge the nested styles, append a space to the
// end (benign when converted to CSS). This way we don't end up merging
// media queries that appear later in the chain with those that appear
// earlier.
if (key.indexOf('@media') === 0) {
let newKey = key;
// eslint-disable-next-line no-constant-condition
while (true) {
newKey += ' ';
if (!result[newKey]) {
result[newKey] = style[key];
return;
}
}
}
// Merge all other nested styles recursively
result[key] = mergeStyles([result[key], style[key]]);
});
});
return result;
}