From 16a5bd61142986df8294529d03529ad8d93c684d Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Sat, 2 Sep 2017 07:35:32 -0400 Subject: [PATCH 1/3] Add support for merging and replacing config keys from a single config file --- __tests__/mergeConfig.test.js | 86 +++++++++ dist/tailwind.css | 2 +- docs/mix-manifest.json | 4 +- docs/tailwind-config.js | 334 ---------------------------------- docs/tailwind.json | 10 + docs/webpack.mix.js | 4 +- src/index.js | 15 +- src/util/mergeConfig.js | 119 ++++++++++++ 8 files changed, 227 insertions(+), 347 deletions(-) create mode 100644 __tests__/mergeConfig.test.js delete mode 100644 docs/tailwind-config.js create mode 100644 docs/tailwind.json create mode 100644 src/util/mergeConfig.js diff --git a/__tests__/mergeConfig.test.js b/__tests__/mergeConfig.test.js new file mode 100644 index 000000000..7d62b62c8 --- /dev/null +++ b/__tests__/mergeConfig.test.js @@ -0,0 +1,86 @@ +import mergeConfig from '../src/util/mergeConfig' + +/** + * Tests + */ +it('replaces simple top level keys', () => { + const defaultConfig = { + colors: { + 'red': '#f25451', + 'green-light': '#b1f3be', + 'blue-dark': '#3687c8', + 'indigo': '#6574cd', + } + } + const userConfig = { + colors: { + 'orange': '#ffb82b', + 'green': '#57d06f', + 'blue': '#4aa2ea', + 'indigo-dark': '#4957a5', + } + } + expect(mergeConfig(defaultConfig, userConfig)).toMatchObject(userConfig) +}) + +it('merges keys found in the "extend" section', () => { + const defaultConfig = { + colors: { + 'red': '#f25451', + }, + text: { + sizes: { + 'base': '1rem', + 'lg': '1.25rem', + } + }, + spacing: { + common: { + '0': '0', + '1': '0.25rem', + '2': '0.5rem', + }, + padding: {} + } + } + const userConfig = { + extend: { + colors: { + 'blue': '#4aa2ea', + }, + text: { + sizes: { + 'xl': '1.5rem' + } + }, + spacing: { + padding: { + '10': '2.5rem' + } + } + } + } + expect(mergeConfig(defaultConfig, userConfig)).toMatchObject({ + colors: { + 'red': '#f25451', + 'blue': '#4aa2ea', + }, + text: { + sizes: { + 'base': '1rem', + 'lg': '1.25rem', + 'xl': '1.5rem', + } + }, + spacing: { + common: { + '0': '0', + '1': '0.25rem', + '2': '0.5rem', + }, + padding: { + '10': '2.5rem', + } + } + }) +}) diff --git a/dist/tailwind.css b/dist/tailwind.css index ba626c40f..9c3b0d75f 100644 --- a/dist/tailwind.css +++ b/dist/tailwind.css @@ -12369,4 +12369,4 @@ body { } } -/*# sourceMappingURL=tailwind.css.map */ +/*# sourceMappingURL=tailwind.css.map */ \ No newline at end of file diff --git a/docs/mix-manifest.json b/docs/mix-manifest.json index 367f5ef1e..9e26dfeeb 100644 --- a/docs/mix-manifest.json +++ b/docs/mix-manifest.json @@ -1,3 +1 @@ -{ - "/source/css/main.css": "/source/css/main.css" -} \ No newline at end of file +{} \ No newline at end of file diff --git a/docs/tailwind-config.js b/docs/tailwind-config.js deleted file mode 100644 index f28c25905..000000000 --- a/docs/tailwind-config.js +++ /dev/null @@ -1,334 +0,0 @@ -module.exports = { - breakpoints: { - sm: '576px', - md: '768px', - lg: '992px', - xl: '1200px', - }, - colors: { - 'black': '#000000', - 'grey-900': '#212b35', - 'grey-800': '#404e5c', - 'grey-700': '#647382', - 'grey-600': '#919eab', - 'grey-500': '#c5ced6', - 'grey-400': '#dfe3e8', - 'grey-300': '#f0f2f5', - 'grey-200': '#f7f9fa', - 'white': '#ffffff', - 'red-dark': '#d43633', - 'red': '#f25451', - 'red-light': '#fa8785', - 'red-lightest': '#fff1f0', - 'orange-dark': '#f29500', - 'orange': '#ffb82b', - 'orange-light': '#ffd685', - 'orange-lightest': '#fff8eb', - 'yellow-dark': '#ffc400', - 'yellow': '#ffe14a', - 'yellow-light': '#ffea83', - 'yellow-lightest': '#fffbe5', - 'green-dark': '#34ae4c', - 'green': '#57d06f', - 'green-light': '#b1f3be', - 'green-lightest': '#eefff1', - 'teal-dark': '#249e9a', - 'teal': '#4dc0b5', - 'teal-light': '#9eebe4', - 'teal-lightest': '#eefffd', - 'blue-dark': '#3687c8', - 'blue': '#4aa2ea', - 'blue-light': '#acdaff', - 'blue-lightest': '#f1f9ff', - 'indigo-dark': '#4957a5', - 'indigo': '#6574cd', - 'indigo-light': '#bcc5fb', - 'indigo-lightest': '#f4f5ff', - 'purple-dark': '#714cb4', - 'purple': '#976ae6', - 'purple-light': '#ceb3ff', - 'purple-lightest': '#f7f3ff', - 'pink-dark': '#d84f7d', - 'pink': '#f66d9b', - 'pink-light': '#ffa5c3', - 'pink-lightest': '#fdf2f5', - }, - text: { - fonts: { - 'sans': 'system-ui', - 'serif': 'Constantia, "Lucida Bright", Lucidabright, "Lucida Serif", Lucida, "DejaVu Serif", "Bitstream Vera Serif", "Liberation Serif", Georgia, serif', - 'mono': 'Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace', - }, - sizes: { - 'xs': '.75rem', // 12px - 'sm': '.875rem', // 14px - 'base': '1rem', // 16px - 'lg': '1.125rem', // 18px - 'xl': '1.25rem', // 20px - '2xl': '1.75rem', // 28px - '3xl': '2.375rem', // 38px - '4xl': '2.875rem', // 46px - }, - weights: { - 'hairline': 200, - 'thin': 300, - 'regular': 400, - 'medium': 600, - 'bold': 700, - }, - leading: { - 'none': 1, - 'tight': 1.25, - 'normal': 1.5, - 'loose': 2, - }, - tracking: { - 'tight': '-0.05em', - 'normal': '0', - 'wide': '0.1em', - }, - colors: [ - { - 'light': 'white', - 'light-soft': 'rgba(255, 255, 255, 60%)', - 'light-softer': 'rgba(255, 255, 255, 45%)', - 'light-softest': 'rgba(255, 255, 255, 35%)', - 'dark': 'grey-900', - 'dark-soft': 'grey-700', - 'dark-softer': 'grey-600', - 'dark-softest': 'grey-500', - }, - 'red-dark', - 'red', - 'red-light', - 'red-lightest', - 'orange-dark', - 'orange', - 'orange-light', - 'orange-lightest', - 'yellow-dark', - 'yellow', - 'yellow-light', - 'yellow-lightest', - 'green-dark', - 'green', - 'green-light', - 'green-lightest', - 'teal-dark', - 'teal', - 'teal-light', - 'teal-lightest', - 'blue-dark', - 'blue', - 'blue-light', - 'blue-lightest', - 'indigo-dark', - 'indigo', - 'indigo-light', - 'indigo-lightest', - 'purple-dark', - 'purple', - 'purple-light', - 'purple-lightest', - 'pink-dark', - 'pink', - 'pink-light', - 'pink-lightest', - ] - }, - backgrounds: { - colors: [ - { - 'light': 'white', - 'light-soft': 'grey-200', - 'light-softer': 'grey-300', - 'light-softest': 'grey-400', - 'dark': 'grey-900', - 'dark-soft': 'grey-800', - 'dark-softer': 'grey-700', - 'dark-softest': 'grey-600', - }, - 'red-dark', - 'red', - 'red-light', - 'red-lightest', - 'orange-dark', - 'orange', - 'orange-light', - 'orange-lightest', - 'yellow-dark', - 'yellow', - 'yellow-light', - 'yellow-lightest', - 'green-dark', - 'green', - 'green-light', - 'green-lightest', - 'teal-dark', - 'teal', - 'teal-light', - 'teal-lightest', - 'blue-dark', - 'blue', - 'blue-light', - 'blue-lightest', - 'indigo-dark', - 'indigo', - 'indigo-light', - 'indigo-lightest', - 'purple-dark', - 'purple', - 'purple-light', - 'purple-lightest', - 'pink-dark', - 'pink', - 'pink-light', - 'pink-lightest', - ], - }, - borders: { - defaults: { - width: '1px', - color: 'grey-500', - }, - widths: { - '0': '0', - '2': '2px', - '4': '4px', - '8': '8px', - }, - rounded: { - default: '.25rem', - modifiers: { - sm: '.125rem', - lg: '.5rem', - pill: '9999px', - } - }, - colors: [ - { - 'light': 'white', - 'light-soft': 'grey-200', - 'light-softer': 'grey-300', - 'dark': 'grey-600', - 'dark-soft': 'grey-500', - 'dark-softer': 'grey-400', - 'light-overlay': 'hsla(0, 0%, 0%, 20%)', - 'light-overlay-soft': 'hsla(0, 0%, 0%, 10%)', - 'light-overlay-softer': 'hsla(0, 0%, 0%, 5%)', - 'dark-overlay': 'hsla(0, 0%, 100%, 100%)', - 'dark-overlay-soft': 'hsla(0, 0%, 100%, 60%)', - 'dark-overlay-softer': 'hsla(0, 0%, 100%, 35%)', - }, - 'red-dark', - 'red', - 'red-light', - 'red-lightest', - 'orange-dark', - 'orange', - 'orange-light', - 'orange-lightest', - 'yellow-dark', - 'yellow', - 'yellow-light', - 'yellow-lightest', - 'green-dark', - 'green', - 'green-light', - 'green-lightest', - 'teal-dark', - 'teal', - 'teal-light', - 'teal-lightest', - 'blue-dark', - 'blue', - 'blue-light', - 'blue-lightest', - 'indigo-dark', - 'indigo', - 'indigo-light', - 'indigo-lightest', - 'purple-dark', - 'purple', - 'purple-light', - 'purple-lightest', - 'pink-dark', - 'pink', - 'pink-light', - 'pink-lightest', - ] - }, - sizing: { - common: { - '1': '0.25rem', - '2': '0.5rem', - '3': '0.75rem', - '4': '1rem', - '6': '1.5rem', - '8': '2rem', - '10': '2.5rem', - '12': '3rem', - '16': '4rem', - '24': '6rem', - '32': '8rem', - '40': '10rem', - '48': '12rem', - '64': '16rem', - '96': '24rem', - '128': '32rem', - 'full': '100%', - }, - width: { - '1/2': '50%', - '1/3': 'calc(100% / 3)', - '2/3': 'calc(100% / 3 * 2)', - '1/4': '25%', - '3/4': '75%', - '1/5': '20%', - '2/5': '40%', - '3/5': '60%', - '4/5': '80%', - '1/6': 'calc(100% / 6)', - '5/6': 'calc(100% / 6 * 5)', - 'screen': '100vw' - }, - height: { - 'screen': '100vh' - } - }, - spacing: { - common: { - 'px': '1px', - '0': '0', - '1': '0.25rem', - '2': '0.5rem', - '3': '0.75rem', - '4': '1rem', - '6': '1.5rem', - '8': '2rem', - '12': '3rem', - '16': '4rem', - }, - padding: {}, - margin: {}, - pull: {}, - }, - constrain: { - 'xs': '20rem', - 'sm': '30rem', - 'md': '40rem', - 'lg': '50rem', - 'xl': '60rem', - '2xl': '70rem', - '3xl': '80rem', - '4xl': '90rem', - '5xl': '100rem', - }, - shadows: { - '1': '0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.15)', - '2': '0 3px 6px rgba(0,0,0,0.12), 0 3px 6px rgba(0,0,0,0.13)', - '3': '0 10px 20px rgba(0,0,0,0.13), 0 6px 6px rgba(0,0,0,0.13)', - '4': '0 14px 28px rgba(0,0,0,0.16), 0 10px 10px rgba(0,0,0,0.11)', - '5': '0 19px 38px rgba(0,0,0,0.18), 0 15px 12px rgba(0,0,0,0.11)', - }, -} diff --git a/docs/tailwind.json b/docs/tailwind.json new file mode 100644 index 000000000..5a886666e --- /dev/null +++ b/docs/tailwind.json @@ -0,0 +1,10 @@ +{ + "extend": { + "spacing": { + "common": { + "12": "3rem", + "16": "4rem" + } + } + } +} diff --git a/docs/webpack.mix.js b/docs/webpack.mix.js index ed6d45737..ab5dc3642 100644 --- a/docs/webpack.mix.js +++ b/docs/webpack.mix.js @@ -1,5 +1,5 @@ const mix = require('laravel-mix'); -const tailwind = require('./../lib/tailwind.js').default; +const tailwind = require('./../lib/index.js'); /* |-------------------------------------------------------------------------- @@ -15,7 +15,7 @@ const tailwind = require('./../lib/tailwind.js').default; mix.less('source/_assets/less/main.less', 'source/css') .options({ postCss: [ - tailwind(require('./tailwind-config')), + tailwind(require('./tailwind.json')), ] }) diff --git a/src/index.js b/src/index.js index a8f3dbbf1..828230129 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import cssnext from 'postcss-cssnext' import stylefmt from 'stylefmt' import defaultConfig from './defaultConfig' +import mergeConfig from './util/mergeConfig' import addCustomMediaQueries from './lib/addCustomMediaQueries' import generateUtilities from './lib/generateUtilities' @@ -12,15 +13,15 @@ import substituteHoverableAtRules from './lib/substituteHoverableAtRules' import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules' import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules' -const plugin = postcss.plugin('tailwind', options => { - options = options || defaultConfig +const plugin = postcss.plugin('tailwind', (options = {}) => { + const config = mergeConfig(defaultConfig, options) return postcss([ - addCustomMediaQueries(options), - generateUtilities(options), - substituteHoverableAtRules(options), - substituteResponsiveAtRules(options), - substituteClassApplyAtRules(options), + addCustomMediaQueries(config), + generateUtilities(config), + substituteHoverableAtRules(config), + substituteResponsiveAtRules(config), + substituteClassApplyAtRules(config), cssnext(), stylefmt, ]) diff --git a/src/util/mergeConfig.js b/src/util/mergeConfig.js new file mode 100644 index 000000000..2d63aad9d --- /dev/null +++ b/src/util/mergeConfig.js @@ -0,0 +1,119 @@ +import _ from 'lodash' + +function normalizeColorList(colors) { + if (_.isArray(colors)) { + colors = _(colors).flatMap(color => { + if (_.isString(color)) { + return [[color, color]] + } + return _.toPairs(color) + }).fromPairs().value() + } + + return _.toPairs(colors) +} + +function normalizeConfig(config) { + return { + breakpoints: _.toPairs(_.get(config, 'breakpoints', {})), + colors: _.toPairs(_.get(config, 'colors', {})), + text: { + fonts: _.toPairs(_.get(config, 'text.fonts', {})), + sizes: _.toPairs(_.get(config, 'text.sizes', {})), + weights: _.toPairs(_.get(config, 'text.weights', {})), + leading: _.toPairs(_.get(config, 'text.leading', {})), + tracking: _.toPairs(_.get(config, 'text.tracking', {})), + colors: normalizeColorList(_.get(config, 'text.colors', {})), + }, + backgrounds: { + colors: normalizeColorList(_.get(config, 'backgrounds.colors', {})), + }, + borders: { + defauts: _.get(config, 'borders.defaults', {}), + widths: _.toPairs(_.get(config, 'borders.widths', {})), + rounded: { + default: _.get(config, 'borders.rounded.default'), + modifiers: _.toPairs(_.get(config, 'borders.rounded.modifiers', {})), + }, + colors: normalizeColorList(_.get(config, 'borders.colors', {})), + }, + sizing: { + common: _.toPairs(_.get(config, 'sizing.common', {})), + width: _.toPairs(_.get(config, 'sizing.width', {})), + height: _.toPairs(_.get(config, 'sizing.height', {})), + }, + spacing: { + common: _.toPairs(_.get(config, 'spacing.common', {})), + padding: _.toPairs(_.get(config, 'spacing.padding', {})), + margin: _.toPairs(_.get(config, 'spacing.margin', {})), + pull: _.toPairs(_.get(config, 'spacing.pull', {})), + }, + constrain: _.toPairs(_.get(config, 'constrain', {})), + shadows: _.toPairs(_.get(config, 'shadows', {})), + zIndex: _.toPairs(_.get(config, 'zIndex', {})), + extend: _.get(config, 'extend', {}) + } +} + +function fixPairs(config) { + return { + breakpoints: _.fromPairs(_.get(config, 'breakpoints', {})), + colors: _.fromPairs(_.get(config, 'colors', {})), + text: { + fonts: _.fromPairs(_.get(config, 'text.fonts', {})), + sizes: _.fromPairs(_.get(config, 'text.sizes', {})), + weights: _.fromPairs(_.get(config, 'text.weights', {})), + leading: _.fromPairs(_.get(config, 'text.leading', {})), + tracking: _.fromPairs(_.get(config, 'text.tracking', {})), + colors: normalizeColorList(_.get(config, 'text.colors', {})), + }, + backgrounds: { + colors: normalizeColorList(_.get(config, 'backgrounds.colors', {})), + }, + borders: { + defauts: _.get(config, 'borders.defaults', {}), + widths: _.fromPairs(_.get(config, 'borders.widths', {})), + rounded: { + default: _.get(config, 'borders.rounded.default'), + modifiers: _.fromPairs(_.get(config, 'borders.rounded.modifiers', {})), + }, + colors: normalizeColorList(_.get(config, 'borders.colors', {})), + }, + sizing: { + common: _.fromPairs(_.get(config, 'sizing.common', {})), + width: _.fromPairs(_.get(config, 'sizing.width', {})), + height: _.fromPairs(_.get(config, 'sizing.height', {})), + }, + spacing: { + common: _.fromPairs(_.get(config, 'spacing.common', {})), + padding: _.fromPairs(_.get(config, 'spacing.padding', {})), + margin: _.fromPairs(_.get(config, 'spacing.margin', {})), + pull: _.fromPairs(_.get(config, 'spacing.pull', {})), + }, + constrain: _.fromPairs(_.get(config, 'constrain', {})), + shadows: _.fromPairs(_.get(config, 'shadows', {})), + zIndex: _.fromPairs(_.get(config, 'zIndex', {})), + } +} + + +export default function mergeConfig(base, other) { + const replaced = _.defaultsDeep( + {}, + normalizeConfig(other), + normalizeConfig(base), + ) + + const extended = _.mergeWith( + {}, + replaced, + normalizeConfig(_.get(replaced, 'extend', {})), + (objValue, srcValue) => { + if (_.isArray(objValue)) { + return objValue.concat(srcValue); + } + } + ) + + return fixPairs(extended) +} From 5aca26ef24f684f7e4d44200bac3ebf57b66e50f Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Sun, 3 Sep 2017 08:06:25 -0400 Subject: [PATCH 2/3] Fix typo --- src/util/mergeConfig.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/mergeConfig.js b/src/util/mergeConfig.js index 2d63aad9d..d00e28803 100644 --- a/src/util/mergeConfig.js +++ b/src/util/mergeConfig.js @@ -29,7 +29,7 @@ function normalizeConfig(config) { colors: normalizeColorList(_.get(config, 'backgrounds.colors', {})), }, borders: { - defauts: _.get(config, 'borders.defaults', {}), + defaults: _.get(config, 'borders.defaults', {}), widths: _.toPairs(_.get(config, 'borders.widths', {})), rounded: { default: _.get(config, 'borders.rounded.default'), @@ -71,7 +71,7 @@ function fixPairs(config) { colors: normalizeColorList(_.get(config, 'backgrounds.colors', {})), }, borders: { - defauts: _.get(config, 'borders.defaults', {}), + defaults: _.get(config, 'borders.defaults', {}), widths: _.fromPairs(_.get(config, 'borders.widths', {})), rounded: { default: _.get(config, 'borders.rounded.default'), From 50ad9dba2b6efa695e0aaca392251c95df50021d Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Sun, 3 Sep 2017 09:28:16 -0400 Subject: [PATCH 3/3] Refactor config merging to be less absolute trash Needs better tests still. --- src/util/mergeConfig.js | 166 ++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 109 deletions(-) diff --git a/src/util/mergeConfig.js b/src/util/mergeConfig.js index d00e28803..34ea914ec 100644 --- a/src/util/mergeConfig.js +++ b/src/util/mergeConfig.js @@ -1,119 +1,67 @@ import _ from 'lodash' -function normalizeColorList(colors) { - if (_.isArray(colors)) { - colors = _(colors).flatMap(color => { - if (_.isString(color)) { - return [[color, color]] - } - return _.toPairs(color) - }).fromPairs().value() - } - - return _.toPairs(colors) +const configTemplate = { + breakpoints: null, + colors: null, + text: { + fonts: null, + sizes: null, + weights: null, + leading: null, + tracking: null, + colors: null + }, + backgrounds: { + colors: null, + }, + borders: { + defaults: null, + widths: null, + rounded: { + default: null, + modifiers: null + }, + colors: null + }, + sizing: { + common: null, + width: null, + height: null + }, + spacing: { + common: null, + padding: null, + margin: null, + pull: null + }, + constrain: null, + shadows: null, + zIndex: null } -function normalizeConfig(config) { - return { - breakpoints: _.toPairs(_.get(config, 'breakpoints', {})), - colors: _.toPairs(_.get(config, 'colors', {})), - text: { - fonts: _.toPairs(_.get(config, 'text.fonts', {})), - sizes: _.toPairs(_.get(config, 'text.sizes', {})), - weights: _.toPairs(_.get(config, 'text.weights', {})), - leading: _.toPairs(_.get(config, 'text.leading', {})), - tracking: _.toPairs(_.get(config, 'text.tracking', {})), - colors: normalizeColorList(_.get(config, 'text.colors', {})), - }, - backgrounds: { - colors: normalizeColorList(_.get(config, 'backgrounds.colors', {})), - }, - borders: { - defaults: _.get(config, 'borders.defaults', {}), - widths: _.toPairs(_.get(config, 'borders.widths', {})), - rounded: { - default: _.get(config, 'borders.rounded.default'), - modifiers: _.toPairs(_.get(config, 'borders.rounded.modifiers', {})), - }, - colors: normalizeColorList(_.get(config, 'borders.colors', {})), - }, - sizing: { - common: _.toPairs(_.get(config, 'sizing.common', {})), - width: _.toPairs(_.get(config, 'sizing.width', {})), - height: _.toPairs(_.get(config, 'sizing.height', {})), - }, - spacing: { - common: _.toPairs(_.get(config, 'spacing.common', {})), - padding: _.toPairs(_.get(config, 'spacing.padding', {})), - margin: _.toPairs(_.get(config, 'spacing.margin', {})), - pull: _.toPairs(_.get(config, 'spacing.pull', {})), - }, - constrain: _.toPairs(_.get(config, 'constrain', {})), - shadows: _.toPairs(_.get(config, 'shadows', {})), - zIndex: _.toPairs(_.get(config, 'zIndex', {})), - extend: _.get(config, 'extend', {}) - } +function replaceDefaults(template, defaults, replacements) { + return Object.keys(template).reduce((merged, key) => { + const value = template[key] + + if (_.isPlainObject(value)) { + merged[key] = replaceDefaults(value, _.get(defaults, key), _.get(replacements, key)) + } else { + merged[key] = _.get(replacements, key, _.get(defaults, key)) + } + + return merged + }, {}) } -function fixPairs(config) { - return { - breakpoints: _.fromPairs(_.get(config, 'breakpoints', {})), - colors: _.fromPairs(_.get(config, 'colors', {})), - text: { - fonts: _.fromPairs(_.get(config, 'text.fonts', {})), - sizes: _.fromPairs(_.get(config, 'text.sizes', {})), - weights: _.fromPairs(_.get(config, 'text.weights', {})), - leading: _.fromPairs(_.get(config, 'text.leading', {})), - tracking: _.fromPairs(_.get(config, 'text.tracking', {})), - colors: normalizeColorList(_.get(config, 'text.colors', {})), - }, - backgrounds: { - colors: normalizeColorList(_.get(config, 'backgrounds.colors', {})), - }, - borders: { - defaults: _.get(config, 'borders.defaults', {}), - widths: _.fromPairs(_.get(config, 'borders.widths', {})), - rounded: { - default: _.get(config, 'borders.rounded.default'), - modifiers: _.fromPairs(_.get(config, 'borders.rounded.modifiers', {})), - }, - colors: normalizeColorList(_.get(config, 'borders.colors', {})), - }, - sizing: { - common: _.fromPairs(_.get(config, 'sizing.common', {})), - width: _.fromPairs(_.get(config, 'sizing.width', {})), - height: _.fromPairs(_.get(config, 'sizing.height', {})), - }, - spacing: { - common: _.fromPairs(_.get(config, 'spacing.common', {})), - padding: _.fromPairs(_.get(config, 'spacing.padding', {})), - margin: _.fromPairs(_.get(config, 'spacing.margin', {})), - pull: _.fromPairs(_.get(config, 'spacing.pull', {})), - }, - constrain: _.fromPairs(_.get(config, 'constrain', {})), - shadows: _.fromPairs(_.get(config, 'shadows', {})), - zIndex: _.fromPairs(_.get(config, 'zIndex', {})), - } +function appendConfig(base, appends) { + return _.mergeWith({}, base, appends, (baseValue, appendsValue) => { + if (_.isArray(baseValue)) { + return baseValue.concat(appendsValue); + } + }) } - export default function mergeConfig(base, other) { - const replaced = _.defaultsDeep( - {}, - normalizeConfig(other), - normalizeConfig(base), - ) - - const extended = _.mergeWith( - {}, - replaced, - normalizeConfig(_.get(replaced, 'extend', {})), - (objValue, srcValue) => { - if (_.isArray(objValue)) { - return objValue.concat(srcValue); - } - } - ) - - return fixPairs(extended) + const replaced = replaceDefaults(configTemplate, base, other) + return appendConfig(replaced, _.get(other, 'extend', {})) }