diff --git a/__tests__/mergeConfigWithDefaults.test.js b/__tests__/resolveConfig.test.js similarity index 66% rename from __tests__/mergeConfigWithDefaults.test.js rename to __tests__/resolveConfig.test.js index f92bc94942ca..7ef2cbbe39e1 100644 --- a/__tests__/mergeConfigWithDefaults.test.js +++ b/__tests__/resolveConfig.test.js @@ -1,4 +1,4 @@ -import mergeConfigWithDefaults from '../src/util/mergeConfigWithDefaults' +import resolveConfig from '../src/util/resolveConfig' test('prefix key overrides default prefix', () => { const userConfig = { @@ -21,7 +21,7 @@ test('prefix key overrides default prefix', () => { }, } - const result = mergeConfigWithDefaults(userConfig, defaultConfig) + const result = resolveConfig([userConfig, defaultConfig]) expect(result).toEqual({ prefix: 'tw-', @@ -61,7 +61,7 @@ test('important key overrides default important', () => { }, } - const result = mergeConfigWithDefaults(userConfig, defaultConfig) + const result = resolveConfig([userConfig, defaultConfig]) expect(result).toEqual({ prefix: '', @@ -101,7 +101,7 @@ test('separator key overrides default separator', () => { }, } - const result = mergeConfigWithDefaults(userConfig, defaultConfig) + const result = resolveConfig([userConfig, defaultConfig]) expect(result).toEqual({ prefix: '', @@ -158,7 +158,7 @@ test('theme key is merged instead of replaced', () => { }, } - const result = mergeConfigWithDefaults(userConfig, defaultConfig) + const result = resolveConfig([userConfig, defaultConfig]) expect(result).toEqual({ prefix: '-', @@ -227,7 +227,7 @@ test('variants key is merged instead of replaced', () => { }, } - const result = mergeConfigWithDefaults(userConfig, defaultConfig) + const result = resolveConfig([userConfig, defaultConfig]) expect(result).toEqual({ prefix: '-', @@ -281,7 +281,7 @@ test('missing top level keys are pulled from the default config', () => { }, } - const result = mergeConfigWithDefaults(userConfig, defaultConfig) + const result = resolveConfig([userConfig, defaultConfig]) expect(result).toEqual({ prefix: '-', @@ -300,3 +300,133 @@ test('missing top level keys are pulled from the default config', () => { }, }) }) + +test('functions in the default theme section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + backgroundColors: ({ colors }) => colors, + textColors: ({ colors }) => colors, + }, + variants: { + backgroundColors: ['responsive', 'hover', 'focus'], + textColors: ['responsive', 'hover', 'focus'], + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toEqual({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + textColors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + variants: { + backgroundColors: ['responsive', 'hover', 'focus'], + textColors: ['responsive', 'hover', 'focus'], + }, + }) +}) + +test('functions in the user theme section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColors: ({ colors }) => ({ + ...colors, + customBackground: '#bada55', + }), + textColors: ({ colors }) => ({ + ...colors, + customText: '#facade', + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + backgroundColors: ({ colors }) => colors, + textColors: ({ colors }) => colors, + }, + variants: { + backgroundColors: ['responsive', 'hover', 'focus'], + textColors: ['responsive', 'hover', 'focus'], + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toEqual({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColors: { + red: 'red', + green: 'green', + blue: 'blue', + customBackground: '#bada55', + }, + textColors: { + red: 'red', + green: 'green', + blue: 'blue', + customText: '#facade', + }, + }, + variants: { + backgroundColors: ['responsive', 'hover', 'focus'], + textColors: ['responsive', 'hover', 'focus'], + }, + }) +}) diff --git a/defaultTheme.js b/defaultTheme.js index 791879b98ff3..a6ae404619ed 100644 --- a/defaultTheme.js +++ b/defaultTheme.js @@ -1,92 +1,90 @@ module.exports = function() { - const colors = { - transparent: 'transparent', - - black: '#22292f', - 'grey-darkest': '#3d4852', - 'grey-darker': '#606f7b', - 'grey-dark': '#8795a1', - grey: '#b8c2cc', - 'grey-light': '#dae1e7', - 'grey-lighter': '#f1f5f8', - 'grey-lightest': '#f8fafc', - white: '#ffffff', + return { + colors: { + transparent: 'transparent', - 'red-darkest': '#3b0d0c', - 'red-darker': '#621b18', - 'red-dark': '#cc1f1a', - red: '#e3342f', - 'red-light': '#ef5753', - 'red-lighter': '#f9acaa', - 'red-lightest': '#fcebea', + black: '#22292f', + 'grey-darkest': '#3d4852', + 'grey-darker': '#606f7b', + 'grey-dark': '#8795a1', + grey: '#b8c2cc', + 'grey-light': '#dae1e7', + 'grey-lighter': '#f1f5f8', + 'grey-lightest': '#f8fafc', + white: '#ffffff', - 'orange-darkest': '#462a16', - 'orange-darker': '#613b1f', - 'orange-dark': '#de751f', - orange: '#f6993f', - 'orange-light': '#faad63', - 'orange-lighter': '#fcd9b6', - 'orange-lightest': '#fff5eb', + 'red-darkest': '#3b0d0c', + 'red-darker': '#621b18', + 'red-dark': '#cc1f1a', + red: '#e3342f', + 'red-light': '#ef5753', + 'red-lighter': '#f9acaa', + 'red-lightest': '#fcebea', - 'yellow-darkest': '#453411', - 'yellow-darker': '#684f1d', - 'yellow-dark': '#f2d024', - yellow: '#ffed4a', - 'yellow-light': '#fff382', - 'yellow-lighter': '#fff9c2', - 'yellow-lightest': '#fcfbeb', + 'orange-darkest': '#462a16', + 'orange-darker': '#613b1f', + 'orange-dark': '#de751f', + orange: '#f6993f', + 'orange-light': '#faad63', + 'orange-lighter': '#fcd9b6', + 'orange-lightest': '#fff5eb', - 'green-darkest': '#0f2f21', - 'green-darker': '#1a4731', - 'green-dark': '#1f9d55', - green: '#38c172', - 'green-light': '#51d88a', - 'green-lighter': '#a2f5bf', - 'green-lightest': '#e3fcec', + 'yellow-darkest': '#453411', + 'yellow-darker': '#684f1d', + 'yellow-dark': '#f2d024', + yellow: '#ffed4a', + 'yellow-light': '#fff382', + 'yellow-lighter': '#fff9c2', + 'yellow-lightest': '#fcfbeb', - 'teal-darkest': '#0d3331', - 'teal-darker': '#20504f', - 'teal-dark': '#38a89d', - teal: '#4dc0b5', - 'teal-light': '#64d5ca', - 'teal-lighter': '#a0f0ed', - 'teal-lightest': '#e8fffe', + 'green-darkest': '#0f2f21', + 'green-darker': '#1a4731', + 'green-dark': '#1f9d55', + green: '#38c172', + 'green-light': '#51d88a', + 'green-lighter': '#a2f5bf', + 'green-lightest': '#e3fcec', - 'blue-darkest': '#12283a', - 'blue-darker': '#1c3d5a', - 'blue-dark': '#2779bd', - blue: '#3490dc', - 'blue-light': '#6cb2eb', - 'blue-lighter': '#bcdefa', - 'blue-lightest': '#eff8ff', + 'teal-darkest': '#0d3331', + 'teal-darker': '#20504f', + 'teal-dark': '#38a89d', + teal: '#4dc0b5', + 'teal-light': '#64d5ca', + 'teal-lighter': '#a0f0ed', + 'teal-lightest': '#e8fffe', - 'indigo-darkest': '#191e38', - 'indigo-darker': '#2f365f', - 'indigo-dark': '#5661b3', - indigo: '#6574cd', - 'indigo-light': '#7886d7', - 'indigo-lighter': '#b2b7ff', - 'indigo-lightest': '#e6e8ff', + 'blue-darkest': '#12283a', + 'blue-darker': '#1c3d5a', + 'blue-dark': '#2779bd', + blue: '#3490dc', + 'blue-light': '#6cb2eb', + 'blue-lighter': '#bcdefa', + 'blue-lightest': '#eff8ff', - 'purple-darkest': '#21183c', - 'purple-darker': '#382b5f', - 'purple-dark': '#794acf', - purple: '#9561e2', - 'purple-light': '#a779e9', - 'purple-lighter': '#d6bbfc', - 'purple-lightest': '#f3ebff', + 'indigo-darkest': '#191e38', + 'indigo-darker': '#2f365f', + 'indigo-dark': '#5661b3', + indigo: '#6574cd', + 'indigo-light': '#7886d7', + 'indigo-lighter': '#b2b7ff', + 'indigo-lightest': '#e6e8ff', - 'pink-darkest': '#451225', - 'pink-darker': '#6f213f', - 'pink-dark': '#eb5286', - pink: '#f66d9b', - 'pink-light': '#fa7ea8', - 'pink-lighter': '#ffbbca', - 'pink-lightest': '#ffebef', - } + 'purple-darkest': '#21183c', + 'purple-darker': '#382b5f', + 'purple-dark': '#794acf', + purple: '#9561e2', + 'purple-light': '#a779e9', + 'purple-lighter': '#d6bbfc', + 'purple-lightest': '#f3ebff', - return { - colors, + 'pink-darkest': '#451225', + 'pink-darker': '#6f213f', + 'pink-dark': '#eb5286', + pink: '#f66d9b', + 'pink-light': '#fa7ea8', + 'pink-lighter': '#ffbbca', + 'pink-lightest': '#ffebef', + }, screens: { sm: '576px', md: '768px', @@ -155,8 +153,8 @@ module.exports = function() { normal: '0', wide: '0.05em', }, - textColors: colors, - backgroundColors: colors, + textColors: theme => theme.colors, + backgroundColors: theme => theme.colors, backgroundSize: { auto: 'auto', cover: 'cover', @@ -169,7 +167,9 @@ module.exports = function() { '4': '4px', '8': '8px', }, - borderColors: global.Object.assign({ default: colors['grey-light'] }, colors), + borderColors: theme => { + return global.Object.assign({ default: theme.colors['grey-light'] }, theme.colors) + }, borderRadius: { none: '0', sm: '.125rem', diff --git a/src/index.js b/src/index.js index 1cdf2525661d..1985aee55391 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ import perfectionist from 'perfectionist' import registerConfigAsDependency from './lib/registerConfigAsDependency' import processTailwindFeatures from './processTailwindFeatures' -import mergeConfigWithDefaults from './util/mergeConfigWithDefaults' +import resolveConfig from './util/resolveConfig' const plugin = postcss.plugin('tailwind', config => { const plugins = [] @@ -17,17 +17,17 @@ const plugin = postcss.plugin('tailwind', config => { const getConfig = () => { if (_.isUndefined(config)) { - return require('../defaultConfig')() + return resolveConfig([require('../defaultConfig')()]) } if (!_.isObject(config)) { delete require.cache[require.resolve(path.resolve(config))] } - return mergeConfigWithDefaults( + return resolveConfig([ _.isObject(config) ? config : require(path.resolve(config)), - require('../defaultConfig')() - ) + require('../defaultConfig')(), + ]) } return postcss([ diff --git a/src/util/mergeConfigWithDefaults.js b/src/util/mergeConfigWithDefaults.js deleted file mode 100644 index fac9dbb32beb..000000000000 --- a/src/util/mergeConfigWithDefaults.js +++ /dev/null @@ -1,12 +0,0 @@ -import _ from 'lodash' - -export default function(userConfig, defaultConfig) { - return _.defaults( - { - theme: _.defaults(userConfig.theme, defaultConfig.theme), - variants: _.defaults(userConfig.variants, defaultConfig.variants), - }, - userConfig, - defaultConfig - ) -} diff --git a/src/util/resolveConfig.js b/src/util/resolveConfig.js new file mode 100644 index 000000000000..2f16773070f4 --- /dev/null +++ b/src/util/resolveConfig.js @@ -0,0 +1,20 @@ +import _ from 'lodash' + +function resolveFunctionKeys(object) { + return Object.keys(object).reduce((resolved, key) => { + return { + ...resolved, + [key]: _.isFunction(object[key]) ? object[key](object) : object[key], + } + }, {}) +} + +export default function(configs) { + return _.defaults( + { + theme: resolveFunctionKeys(_.defaults(..._.map(configs, 'theme'))), + variants: _.defaults(..._.map(configs, 'variants')), + }, + ...configs + ) +}