mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Allow resolving an arbitrary number of stacked config files
This commit is contained in:
parent
5ba0cc1e1d
commit
e7b831fc09
@ -1234,3 +1234,133 @@ test('custom properties are multiplied by -1 for negative values', () => {
|
||||
variants: {},
|
||||
})
|
||||
})
|
||||
|
||||
test('more than two config objects can be resolved', () => {
|
||||
const firstConfig = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: () => ({
|
||||
code: ['Menlo', 'monospace'],
|
||||
}),
|
||||
colors: {
|
||||
red: 'red',
|
||||
},
|
||||
backgroundColor: {
|
||||
customBackgroundOne: '#bada55',
|
||||
},
|
||||
textDecorationColor: {
|
||||
orange: 'orange'
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const secondConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
quote: ['Helvetica', 'serif'],
|
||||
},
|
||||
colors: {
|
||||
green: 'green',
|
||||
},
|
||||
backgroundColor: {
|
||||
customBackgroundTwo: '#facade',
|
||||
},
|
||||
textDecorationColor: theme => theme('colors')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const thirdConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
hero: ['Futura', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
pink: 'pink',
|
||||
},
|
||||
backgroundColor: () => ({
|
||||
customBackgroundThree: '#c0ffee',
|
||||
}),
|
||||
textDecorationColor: {
|
||||
lime: 'lime',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
fontFamily: {
|
||||
body: ['Arial', 'sans-serif'],
|
||||
display: ['Georgia', 'serif'],
|
||||
},
|
||||
colors: {
|
||||
blue: 'blue',
|
||||
},
|
||||
backgroundColor: theme => theme('colors'),
|
||||
},
|
||||
variants: {
|
||||
backgroundColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
}
|
||||
|
||||
const result = resolveConfig([
|
||||
firstConfig,
|
||||
secondConfig,
|
||||
thirdConfig,
|
||||
defaultConfig
|
||||
])
|
||||
|
||||
expect(result).toEqual({
|
||||
prefix: '-',
|
||||
important: false,
|
||||
separator: ':',
|
||||
theme: {
|
||||
fontFamily: {
|
||||
body: ['Arial', 'sans-serif'],
|
||||
display: ['Georgia', 'serif'],
|
||||
code: ['Menlo', 'monospace'],
|
||||
quote: ['Helvetica', 'serif'],
|
||||
hero: ['Futura', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
pink: 'pink',
|
||||
},
|
||||
backgroundColor: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
pink: 'pink',
|
||||
customBackgroundOne: '#bada55',
|
||||
customBackgroundTwo: '#facade',
|
||||
customBackgroundThree: '#c0ffee',
|
||||
},
|
||||
textDecorationColor: {
|
||||
red: 'red',
|
||||
green: 'green',
|
||||
blue: 'blue',
|
||||
pink: 'pink',
|
||||
orange: 'orange',
|
||||
lime: 'lime',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
backgroundColor: ['responsive', 'hover', 'focus'],
|
||||
},
|
||||
})
|
||||
})
|
||||
@ -1,7 +1,11 @@
|
||||
import some from 'lodash/some'
|
||||
import mergeWith from 'lodash/mergeWith'
|
||||
import assignWith from 'lodash/assignWith'
|
||||
import isFunction from 'lodash/isFunction'
|
||||
import isUndefined from 'lodash/isUndefined'
|
||||
import defaults from 'lodash/defaults'
|
||||
import map from 'lodash/map'
|
||||
import reduce from 'lodash/reduce'
|
||||
import toPath from 'lodash/toPath'
|
||||
import negateValue from './negateValue'
|
||||
|
||||
@ -23,18 +27,46 @@ function value(valueToResolve, ...args) {
|
||||
return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve
|
||||
}
|
||||
|
||||
function mergeThemes(themes) {
|
||||
const theme = (({ extend, ...t }) => t)(themes.reduce((merged, t) => {
|
||||
return defaults(merged, t)
|
||||
}, {}))
|
||||
|
||||
// In order to resolve n config objects, we combine all of their `extend` properties
|
||||
// into arrays instead of objects so they aren't overridden.
|
||||
const extend = themes.reduce((merged, { extend }) => {
|
||||
return mergeWith(merged, extend, (mergedValue, extendValue) => {
|
||||
if (isUndefined(mergedValue)) {
|
||||
return [extendValue]
|
||||
}
|
||||
|
||||
if (Array.isArray(mergedValue)) {
|
||||
return [...mergedValue, extendValue]
|
||||
}
|
||||
|
||||
return [mergedValue, extendValue]
|
||||
})
|
||||
}, {})
|
||||
|
||||
return {
|
||||
...theme,
|
||||
extend,
|
||||
}
|
||||
}
|
||||
|
||||
function mergeExtensions({ extend, ...theme }) {
|
||||
return mergeWith(theme, extend, (themeValue, extensions) => {
|
||||
if (!isFunction(themeValue) && !isFunction(extensions)) {
|
||||
// The `extend` property is an array, so we need to check if it contains any functions
|
||||
if (!isFunction(themeValue) && !some(extensions, isFunction)) {
|
||||
return {
|
||||
...themeValue,
|
||||
...extensions,
|
||||
...Object.assign({}, ...extensions),
|
||||
}
|
||||
}
|
||||
|
||||
return (resolveThemePath, utils) => ({
|
||||
...value(themeValue, resolveThemePath, utils),
|
||||
...value(extensions, resolveThemePath, utils),
|
||||
...Object.assign({}, ...extensions.map(e => value(e, resolveThemePath, utils))),
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -65,7 +97,7 @@ function resolveFunctionKeys(object) {
|
||||
export default function resolveConfig(configs) {
|
||||
return defaults(
|
||||
{
|
||||
theme: resolveFunctionKeys(mergeExtensions(defaults({}, ...map(configs, 'theme')))),
|
||||
theme: resolveFunctionKeys(mergeExtensions(mergeThemes(map(configs, 'theme')))),
|
||||
variants: (firstVariants => {
|
||||
return Array.isArray(firstVariants)
|
||||
? firstVariants
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user