2019-10-11 17:48:52 -04:00
|
|
|
import some from 'lodash/some'
|
2019-02-13 09:01:49 -05:00
|
|
|
import mergeWith from 'lodash/mergeWith'
|
|
|
|
|
import isFunction from 'lodash/isFunction'
|
2019-10-11 17:48:52 -04:00
|
|
|
import isUndefined from 'lodash/isUndefined'
|
2019-02-13 09:01:49 -05:00
|
|
|
import defaults from 'lodash/defaults'
|
|
|
|
|
import map from 'lodash/map'
|
2019-10-12 12:53:32 -04:00
|
|
|
import get from 'lodash/get'
|
2019-05-08 22:11:10 +02:00
|
|
|
import toPath from 'lodash/toPath'
|
2019-08-09 16:10:41 -04:00
|
|
|
import negateValue from './negateValue'
|
2017-11-24 12:34:09 -05:00
|
|
|
|
2019-04-27 16:55:21 -04:00
|
|
|
const configUtils = {
|
2019-04-24 16:37:13 -04:00
|
|
|
negative(scale) {
|
2019-04-24 15:15:30 -04:00
|
|
|
return Object.keys(scale)
|
|
|
|
|
.filter(key => scale[key] !== '0')
|
2019-04-24 16:37:13 -04:00
|
|
|
.reduce(
|
|
|
|
|
(negativeScale, key) => ({
|
|
|
|
|
...negativeScale,
|
2019-08-09 16:10:41 -04:00
|
|
|
[`-${key}`]: negateValue(scale[key]),
|
2019-04-24 16:37:13 -04:00
|
|
|
}),
|
|
|
|
|
{}
|
|
|
|
|
)
|
|
|
|
|
},
|
2019-04-24 15:15:30 -04:00
|
|
|
}
|
|
|
|
|
|
2019-03-18 11:42:56 -04:00
|
|
|
function value(valueToResolve, ...args) {
|
|
|
|
|
return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve
|
2019-02-05 20:18:19 -05:00
|
|
|
}
|
|
|
|
|
|
2019-10-11 17:48:52 -04:00
|
|
|
function mergeThemes(themes) {
|
2019-10-12 12:53:32 -04:00
|
|
|
const theme = (({ extend: _, ...t }) => t)(
|
|
|
|
|
themes.reduce((merged, t) => {
|
|
|
|
|
return defaults(merged, t)
|
|
|
|
|
}, {})
|
|
|
|
|
)
|
2019-10-11 17:48:52 -04:00
|
|
|
|
2019-10-12 12:53:32 -04:00
|
|
|
return {
|
|
|
|
|
...theme,
|
2019-10-11 17:48:52 -04:00
|
|
|
|
2019-10-12 12:53:32 -04:00
|
|
|
// In order to resolve n config objects, we combine all of their `extend` properties
|
|
|
|
|
// into arrays instead of objects so they aren't overridden.
|
|
|
|
|
extend: themes.reduce((merged, { extend }) => {
|
|
|
|
|
return mergeWith(merged, extend, (mergedValue, extendValue) => {
|
|
|
|
|
if (isUndefined(mergedValue)) {
|
|
|
|
|
return [extendValue]
|
|
|
|
|
}
|
2019-10-11 17:48:52 -04:00
|
|
|
|
2019-10-12 12:53:32 -04:00
|
|
|
if (Array.isArray(mergedValue)) {
|
|
|
|
|
return [...mergedValue, extendValue]
|
|
|
|
|
}
|
2019-10-11 17:48:52 -04:00
|
|
|
|
2019-10-12 12:53:32 -04:00
|
|
|
return [mergedValue, extendValue]
|
|
|
|
|
})
|
|
|
|
|
}, {}),
|
2019-10-11 17:48:52 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-14 07:47:32 -05:00
|
|
|
function mergeExtensions({ extend, ...theme }) {
|
2019-03-18 11:42:56 -04:00
|
|
|
return mergeWith(theme, extend, (themeValue, extensions) => {
|
2019-10-11 17:48:52 -04:00
|
|
|
// The `extend` property is an array, so we need to check if it contains any functions
|
|
|
|
|
if (!isFunction(themeValue) && !some(extensions, isFunction)) {
|
2019-03-17 05:14:11 +01:00
|
|
|
return {
|
2019-03-18 11:21:32 -04:00
|
|
|
...themeValue,
|
2019-10-11 17:48:52 -04:00
|
|
|
...Object.assign({}, ...extensions),
|
2019-03-17 05:14:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-03-18 11:21:32 -04:00
|
|
|
|
2019-04-27 16:55:21 -04:00
|
|
|
return (resolveThemePath, utils) => ({
|
|
|
|
|
...value(themeValue, resolveThemePath, utils),
|
2019-10-11 17:48:52 -04:00
|
|
|
...Object.assign({}, ...extensions.map(e => value(e, resolveThemePath, utils))),
|
2019-03-18 11:21:32 -04:00
|
|
|
})
|
2019-02-13 09:01:49 -05:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-18 11:21:32 -04:00
|
|
|
function resolveFunctionKeys(object) {
|
2019-04-27 16:55:21 -04:00
|
|
|
const resolveThemePath = (key, defaultValue) => {
|
2019-05-08 22:11:10 +02:00
|
|
|
const path = toPath(key)
|
|
|
|
|
|
|
|
|
|
let index = 0
|
|
|
|
|
let val = object
|
|
|
|
|
|
|
|
|
|
while (val !== undefined && val !== null && index < path.length) {
|
|
|
|
|
val = val[path[index++]]
|
|
|
|
|
val = isFunction(val) ? val(resolveThemePath) : val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return val === undefined ? defaultValue : val
|
2019-03-24 20:10:15 +00:00
|
|
|
}
|
2019-03-18 11:21:32 -04:00
|
|
|
|
|
|
|
|
return Object.keys(object).reduce((resolved, key) => {
|
|
|
|
|
return {
|
|
|
|
|
...resolved,
|
2019-04-27 16:55:21 -04:00
|
|
|
[key]: isFunction(object[key]) ? object[key](resolveThemePath, configUtils) : object[key],
|
2019-03-18 11:21:32 -04:00
|
|
|
}
|
|
|
|
|
}, {})
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-18 11:42:56 -04:00
|
|
|
export default function resolveConfig(configs) {
|
|
|
|
|
return defaults(
|
|
|
|
|
{
|
2019-10-12 12:53:32 -04:00
|
|
|
// Need to get a default empty object if the config has no theme
|
|
|
|
|
theme: resolveFunctionKeys(
|
|
|
|
|
mergeExtensions(mergeThemes(map(configs, t => get(t, 'theme', {}))))
|
|
|
|
|
),
|
2019-05-13 12:44:19 -04:00
|
|
|
variants: (firstVariants => {
|
|
|
|
|
return Array.isArray(firstVariants)
|
|
|
|
|
? firstVariants
|
|
|
|
|
: defaults({}, ...map(configs, 'variants'))
|
|
|
|
|
})(defaults({}, ...map(configs)).variants),
|
2019-03-18 11:42:56 -04:00
|
|
|
},
|
|
|
|
|
...configs
|
|
|
|
|
)
|
2017-11-24 12:34:09 -05:00
|
|
|
}
|