kitchensink
Version:
Dispatch's awesome components and style guide
50 lines (42 loc) • 1.42 kB
JavaScript
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;
while (true) { // eslint-disable-line no-constant-condition
newKey += ' ';
if (!result[newKey]) {
result[newKey] = style[key];
return;
}
}
}
// Merge all other nested styles recursively
result[key] = mergeStyles([result[key], style[key]]);
});
});
return result;
}