Merge pull request #101 from adamwathan/smart-config-merging

Add support for merging and replacing config keys from a single config file
This commit is contained in:
Adam Wathan 2017-09-03 09:29:18 -04:00 committed by GitHub
commit afc99c45e2
8 changed files with 175 additions and 347 deletions

View File

@ -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',
}
}
})
})

2
dist/tailwind.css vendored
View File

@ -12369,4 +12369,4 @@ body {
}
}
/*# sourceMappingURL=tailwind.css.map */
/*# sourceMappingURL=tailwind.css.map */

View File

@ -1,3 +1 @@
{
"/source/css/main.css": "/source/css/main.css"
}
{}

View File

@ -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)',
},
}

10
docs/tailwind.json Normal file
View File

@ -0,0 +1,10 @@
{
"extend": {
"spacing": {
"common": {
"12": "3rem",
"16": "4rem"
}
}
}
}

View File

@ -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')),
]
})

View File

@ -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,
])

67
src/util/mergeConfig.js Normal file
View File

@ -0,0 +1,67 @@
import _ from 'lodash'
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 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 appendConfig(base, appends) {
return _.mergeWith({}, base, appends, (baseValue, appendsValue) => {
if (_.isArray(baseValue)) {
return baseValue.concat(appendsValue);
}
})
}
export default function mergeConfig(base, other) {
const replaced = replaceDefaults(configTemplate, base, other)
return appendConfig(replaced, _.get(other, 'extend', {}))
}